├── .gitignore ├── LICENSE.txt ├── README.txt ├── assembly_process_definitions.xml ├── chiplet_nre_study_def.xml ├── chiplet_nre_study_netlist.xml ├── design.py ├── generate_grid_test_files.py ├── generate_grid_test_files_3d.py ├── generate_plot.py ├── io_definitions.xml ├── layer_definitions.xml ├── load_and_test_design.py ├── load_and_test_design_test_breakdown.py ├── netlist.xml ├── readDesignFromFile.py ├── run_all_sweeps.sh ├── search_and_replace.py ├── sip.xml ├── sweep_assembly_process.sh ├── sweep_chiplet_size.sh ├── sweep_defect_density.sh ├── sweep_nre.sh ├── sweep_nre_1_custom.sh ├── sweep_reach.sh ├── sweep_substrates.sh ├── sweep_test_coverage.sh ├── sweep_test_coverage_immature.sh ├── test_definitions.xml └── wafer_process_definitions.xml /.gitignore: -------------------------------------------------------------------------------- 1 | __* 2 | *.png 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2025 UCLA NanoCAD Laboratory 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | ======================================================================= 2 | Copyright 2025 UCLA NanoCAD Laboratory 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | ======================================================================= 16 | Author: Alexander Graening (agraening@ucla.edu) 17 | 18 | ==================================== 19 | README for Chiplet Cost Model 20 | ==================================== 21 | 22 | General Usage: 23 | python load_and_test_design.py io_definitions.xml layer_definitions.xml wafer_process_definitions.xml assembly_process_definitions.xml test_definitions.xml netlist.xml sip.xml 24 | 25 | The above command will run the cost calculation on the demo configuration file sip.xml and demo netlist file netlist.xml 26 | 27 | To generate the plots in the paper "CATCH: a Cost Analysis Tool for Co-optimization of chiplet-based Heterogeneous systems" you can launch the script run_all_sweeps.sh 28 | sh run_all_sweeps.sh 29 | 30 | Requirements: 31 | Currently, I am running this using: 32 | Python 3.10.6 33 | Numpy 1.25.0 34 | xml.etree.ElementTree 1.3.0 35 | 36 | 37 | ==================================== 38 | Included Files: 39 | ==================================== 40 | 41 | design.py 42 | Contains class definitions for the chip class that is core to the model along with class definitions for layers, IOs, testing processes, wafer processes, and assembly methods. 43 | 44 | generate_grid_test_files.py 45 | This is used to generate the netlist and system definition files for the 800mm^2 testcase. The chiplets are placed next to each other on an interposer. 46 | 47 | generate_grid_test_files_3D.py 48 | This is used to generate the netlist and system definition files for the 800mm^2 testcase. The chiplets are stacked on top of each other in a single stack. 49 | 50 | load_and_test_design.py 51 | This is used to pass file names as an argument and build the system. This also prints out the computed system information. 52 | 53 | load_and_test_design_test_breakdown.py 54 | This is a variation of the above file to split the cost into scrap cost and non-scrap cost for plotting. 55 | 56 | readDesignFromFile.py 57 | Functions for reading xml files into the dictionary format and processing into the class structure are included here. 58 | 59 | search_and_replace.py 60 | This simply takes an input file and replaces one string with another. This is used to modify the configuration files to run sweeps. 61 | 62 | sip.xml 63 | Demo system definition file 64 | 65 | netlist.xml 66 | Demo netlist file 67 | 68 | io_definitions.xml 69 | IO definitions file 70 | 71 | layer_definitions.xml 72 | Layer definition file. This contains both "combined" layers that model a full stackup and individual layers such as metal and active layers to build a full stackup based on number of required metal layers. 73 | 74 | test_definitions.xml 75 | Test process definition file. This contains the constants necessary to compute testing cost and to compute a testing method aware yield. 76 | 77 | wafer_process_definitions.xml 78 | This contains the constants that are generally shared about parameters such as reticle size and wafer processing yield. 79 | 80 | assembly_process_definitions.xml 81 | This contains definitions of constants necessary for computing the assembly cost and yield impact. 82 | 83 | chiplet_nre_study_def.xml and chiplet_nre_study_netlist.xml 84 | Configuration files for study with a single low volume chip in a design with 3 high volume chips. 85 | 86 | run_all_sweeps.sh 87 | Runs all sweep scripts. 88 | 89 | sweep_assembly_process.sh 90 | Runs sweep on the assembly process across different 800mm2 homogeneous graph processor test cases. 91 | 92 | sweep_chiplet_size.sh 93 | Runs sweep of different 800mm2 homogeneous graph processor test cases for different process technology nodes. 94 | 95 | sweep_defect_density.sh 96 | Runs sweep defect density across different 800mm2 homogeneous graph processor test cases. 97 | 98 | sweep_nre.sh 99 | Runs sweep of different quantities across different 800mm2 homogeneous graph processor test cases without. 100 | 101 | sweep_nre_1_custom.sh 102 | Runs a sweep of quantity for a design with a single low-volume die and 3 high volume dies. 103 | 104 | sweep_reach.sh 105 | Runs a sweep of reach across a testcase. 106 | 107 | sweep_substrates.sh 108 | Compares organic, silicon, and glass for one example. 109 | 110 | sweep_test_coverage.sh 111 | Sweeps test coverage at the "typical" defect density used for the paper. 112 | 113 | sweep_test_coverage_immature.sh 114 | Sweeps test coverage at an elevated defect density. 115 | 116 | 117 | ==================================== 118 | General Summary 119 | ==================================== 120 | 121 | The general organization of the code: 122 | - Class definitions and model functions are included in design.py 123 | - Functions for reading the design are included in readDesignFromFile.py 124 | - load_and_test_design.py is a wrapper that makes this easier to use to test a single design. 125 | - Example sweeps are included in distinct .sh scripts and can all be run by launching run_all_sweeps.sh 126 | 127 | Modify or create new .xml files to evaluate new systems and processes. To add new considerations, edit the corresponding class in design.py. 128 | -------------------------------------------------------------------------------- /assembly_process_definitions.xml: -------------------------------------------------------------------------------- 1 | 76 | 77 | 90 | 91 | 113 | 114 | 136 | 137 | 159 | 160 | 173 | 195 | 196 | 218 | 219 | 241 | 242 | 264 | 265 | 278 | 300 | 301 | 304 | 326 | 327 | 328 | -------------------------------------------------------------------------------- /chiplet_nre_study_def.xml: -------------------------------------------------------------------------------- 1 | 18 | 40 | 62 | 63 | 85 | 86 | 108 | 109 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /chiplet_nre_study_netlist.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 25 | 26 | 32 | 33 | 39 | 40 | 46 | 47 | 53 | 54 | 60 | 61 | 67 | 68 | 74 | 75 | 81 | 82 | 88 | 89 | 95 | 96 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /generate_grid_test_files.py: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | import math 18 | import sys 19 | import os 20 | # Generate a system definition .xml file. 21 | 22 | 23 | # As input, take the number of chiplets, IO type, a bidirectional flag, external bandwidth, and the total power as inputs. 24 | if len(sys.argv) != 8: 25 | print("ERROR: Incorrect Number of Input Arguments\nUsage: python generate_test_files.py \nExiting...") 26 | sys.exit(1) 27 | 28 | 29 | number_of_chiplets = int(sys.argv[1]) 30 | interchiplet_IO_type = sys.argv[2] 31 | bidirectional = sys.argv[3] 32 | organic_flag_str = sys.argv[4] 33 | total_ext_bandwidth = float(sys.argv[5]) 34 | total_power = float(sys.argv[6]) 35 | logic_fraction = float(sys.argv[7]) 36 | 37 | total_chiplet_area = 800 38 | 39 | area_of_chiplets = total_chiplet_area / number_of_chiplets 40 | power_per_chiplet = total_power / number_of_chiplets 41 | 42 | identifier = "chiplet_" + str(number_of_chiplets) + "_" + str(math.floor(area_of_chiplets)) 43 | 44 | test_process = "KGD_free_test" 45 | interposer_test_process = "KGD_interposer_free_test" 46 | wafer_process = "process_1" 47 | # wafer_diameter = "300" 48 | # edge_exclusion = "3" 49 | # wafer_process_yield = " 0.94" 50 | # reticle_x = "26" 51 | # reticle_y = "33" 52 | 53 | # externalInputs = "0" 54 | # externalOutputs = "0" 55 | 56 | system_quantity = "10000000" 57 | quantity=str(int(system_quantity) * number_of_chiplets) 58 | 59 | if bidirectional == "True": 60 | bidirectional_flag = True 61 | elif bidirectional == "False": 62 | bidirectional_flag = False 63 | else: 64 | print("ERROR: Invalid bidirectional flag\nExiting...") 65 | sys.exit(1) 66 | 67 | if organic_flag_str == "True" or organic_flag_str == "true": 68 | organic_flag = True 69 | elif organic_flag_str == "False" or organic_flag_str == "false": 70 | organic_flag = False 71 | else: 72 | organic_flag = False 73 | 74 | if organic_flag: 75 | assembly_process = "organic_simultaneous_bonding" 76 | interposer_stackup = "1:combined_interposer_organic" 77 | else: 78 | assembly_process = "silicon_individual_bonding" 79 | interposer_stackup = "1:combined_interposer_silicon" 80 | 81 | chip_stackup = "1:combined_5nm" 82 | 83 | # Generate def xml file 84 | def_file = open(identifier + "_def" + ".xml", "w") 85 | 86 | def_file.write("\n") 108 | 109 | for i in range(number_of_chiplets): 110 | def_file.write("\t\n") 132 | def_file.write("\t\n") 133 | 134 | def_file.write("\n") 135 | def_file.close() 136 | 137 | # Generate netlist xml file 138 | # Open netlist file 139 | netlist_file = open(identifier + "_netlist" + ".xml", "w") 140 | netlist_file.write("\n") 141 | 142 | edge_bandwidth = total_ext_bandwidth / (math.sqrt(number_of_chiplets) * 4) 143 | 144 | for i in range(number_of_chiplets): 145 | if i == 0 or i == number_of_chiplets - 1 or i == math.sqrt(number_of_chiplets) - 1 or i == number_of_chiplets - math.sqrt(number_of_chiplets): 146 | # corner 147 | external_bandwidth = edge_bandwidth * 2 148 | elif i % math.sqrt(number_of_chiplets) == 0 or i % math.sqrt(number_of_chiplets) == math.sqrt(number_of_chiplets) - 1: 149 | # edge 150 | external_bandwidth = edge_bandwidth 151 | netlist_file.write("\t\n") 157 | netlist_file.write("\t\n") 158 | if bidirectional_flag != True: 159 | # Now the other direction 160 | netlist_file.write("\t\n") 166 | netlist_file.write("\t\n") 167 | 168 | # Now define internal connections assuming a grid of squares with the same edge bandwidth between each adjacent chiplets. 169 | for i in range(number_of_chiplets): 170 | if i % math.sqrt(number_of_chiplets) != math.sqrt(number_of_chiplets) - 1: # Connect to chiplet on the right 171 | netlist_file.write("\t\n") 177 | netlist_file.write("\t\n") 178 | if bidirectional_flag != True: 179 | if i % math.sqrt(number_of_chiplets) != 0: # Connect to chiplet on the left 180 | netlist_file.write("\t\n") 186 | netlist_file.write("\t\n") 187 | if i >= math.sqrt(number_of_chiplets): # Connect to chiplet above 188 | netlist_file.write("\t\n") 194 | netlist_file.write("\t\n") 195 | if bidirectional_flag != True: 196 | if i < number_of_chiplets - math.sqrt(number_of_chiplets): # Connect to chiplet below 197 | netlist_file.write("\t\n") 203 | netlist_file.write("\t\n") 204 | 205 | 206 | netlist_file.write("\n") 207 | netlist_file.close() 208 | print("Generated " + identifier + "_def.xml and " + identifier + "_netlist.xml") 209 | -------------------------------------------------------------------------------- /generate_grid_test_files_3d.py: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | import math 18 | import sys 19 | import os 20 | # Generate a system definition .xml file. 21 | 22 | 23 | # As input, take the number of chiplets, IO type, a bidirectional flag, external bandwidth, and the total power as inputs. 24 | if len(sys.argv) != 8: 25 | print("ERROR: Incorrect Number of Input Arguments\nUsage: python generate_test_files_3d.py \nExiting...") 26 | sys.exit(1) 27 | 28 | 29 | number_of_chiplets = int(sys.argv[1]) 30 | interchiplet_IO_type = sys.argv[2] 31 | bidirectional = sys.argv[3] 32 | organic_flag_str = sys.argv[4] 33 | total_ext_bandwidth = float(sys.argv[5]) 34 | total_power = float(sys.argv[6]) 35 | logic_fraction = float(sys.argv[7]) 36 | 37 | total_chiplet_area = 800 38 | 39 | area_of_chiplets = total_chiplet_area / number_of_chiplets 40 | power_per_chiplet = total_power / number_of_chiplets 41 | 42 | identifier = "chiplet_" + str(number_of_chiplets) + "_" + str(math.floor(area_of_chiplets)) 43 | 44 | test_process = "KGD_free_test" 45 | interposer_test_process = "KGD_interposer_free_test" 46 | wafer_process = "process_1" 47 | # wafer_diameter = "300" 48 | # edge_exclusion = "3" 49 | # wafer_process_yield = " 0.94" 50 | # reticle_x = "26" 51 | # reticle_y = "33" 52 | 53 | # externalInputs = "0" 54 | # externalOutputs = "0" 55 | 56 | system_quantity = "10000000" 57 | quantity=str(int(system_quantity) * number_of_chiplets) 58 | 59 | if bidirectional == "True": 60 | bidirectional_flag = True 61 | elif bidirectional == "False": 62 | bidirectional_flag = False 63 | else: 64 | print("ERROR: Invalid bidirectional flag\nExiting...") 65 | sys.exit(1) 66 | 67 | if organic_flag_str == "True" or organic_flag_str == "true": 68 | organic_flag = True 69 | elif organic_flag_str == "False" or organic_flag_str == "false": 70 | organic_flag = False 71 | else: 72 | organic_flag = False 73 | 74 | if organic_flag: 75 | assembly_process = "organic_simultaneous_bonding" 76 | interposer_stackup = "1:combined_interposer_organic" 77 | else: 78 | assembly_process = "silicon_individual_bonding" 79 | interposer_stackup = "1:combined_interposer_silicon" 80 | 81 | chip_stackup = "1:combined_5nm" 82 | 83 | # Generate def xml file 84 | def_file = open(identifier + "_def" + ".xml", "w") 85 | 86 | def_file.write("\n") 108 | 109 | for i in range(number_of_chiplets): 110 | def_file.write("\t\n") 132 | 133 | for i in range(number_of_chiplets): 134 | def_file.write("\t\n") 135 | 136 | def_file.write("\n") 137 | def_file.close() 138 | 139 | # Generate netlist xml file 140 | # Open netlist file 141 | netlist_file = open(identifier + "_netlist" + ".xml", "w") 142 | netlist_file.write("\n") 143 | 144 | edge_bandwidth = total_ext_bandwidth / (math.sqrt(number_of_chiplets) * 4) 145 | 146 | for i in range(number_of_chiplets): 147 | if i == 0 or i == number_of_chiplets - 1 or i == math.sqrt(number_of_chiplets) - 1 or i == number_of_chiplets - math.sqrt(number_of_chiplets): 148 | # corner 149 | external_bandwidth = edge_bandwidth * 2 150 | elif i % math.sqrt(number_of_chiplets) == 0 or i % math.sqrt(number_of_chiplets) == math.sqrt(number_of_chiplets) - 1: 151 | # edge 152 | external_bandwidth = edge_bandwidth 153 | netlist_file.write("\t\n") 159 | netlist_file.write("\t\n") 160 | # Now the other direction 161 | netlist_file.write("\t\n") 167 | netlist_file.write("\t\n") 168 | 169 | # Now define internal connections assuming a grid of squares with the same edge bandwidth between each adjacent chiplets. 170 | for i in range(number_of_chiplets): 171 | if i % math.sqrt(number_of_chiplets) != math.sqrt(number_of_chiplets) - 1: # Connect to chiplet on the right 172 | netlist_file.write("\t\n") 178 | netlist_file.write("\t\n") 179 | if bidirectional_flag != True: 180 | if i % math.sqrt(number_of_chiplets) != 0: # Connect to chiplet on the left 181 | netlist_file.write("\t\n") 187 | netlist_file.write("\t\n") 188 | if i >= math.sqrt(number_of_chiplets): # Connect to chiplet above 189 | netlist_file.write("\t\n") 195 | netlist_file.write("\t\n") 196 | if bidirectional_flag != True: 197 | if i < number_of_chiplets - math.sqrt(number_of_chiplets): # Connect to chiplet below 198 | netlist_file.write("\t\n") 204 | netlist_file.write("\t\n") 205 | 206 | 207 | netlist_file.write("\n") 208 | netlist_file.close() 209 | print("Generated " + identifier + "_def.xml and " + identifier + "_netlist.xml") 210 | -------------------------------------------------------------------------------- /generate_plot.py: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | import matplotlib.pyplot as plt 18 | import math 19 | import sys 20 | 21 | def read_data(filename): 22 | with open(filename, 'r') as file: 23 | lines = file.readlines() 24 | 25 | # Extract x-axis and y-axis 26 | x_axis_label = lines[0].strip().split(':')[1].strip() 27 | y_axis_label = lines[1].strip().split(':')[1].strip() 28 | 29 | # Extract x-labels from line 2 starting after the ":" 30 | x_labels = lines[2].strip().split(':')[1].strip().split() 31 | #x_labels = lines[2].strip().split()[1:] 32 | 33 | y_values = [] 34 | series_labels = [] 35 | 36 | stack = False 37 | 38 | # Extract the numbers from the subsequent lines 39 | if lines[3].strip().split()[0] == 'series:': 40 | lines_per_series = len(x_labels) + 1 41 | for series in range(0, (len(lines) - 3) // lines_per_series): 42 | series_labels.append(lines[3 + series * lines_per_series].strip().split(':')[1].strip()) 43 | sub_list = [] 44 | for line in lines[lines_per_series * series + 4:lines_per_series * (series + 1) + 4 - 1]: 45 | sub_str_list = line.strip().split() 46 | sub_list.append([float(value) for value in sub_str_list]) 47 | #sub_list.append([float(value) for value in line.strip().split()]) 48 | y_values.append(sub_list) 49 | elif lines[3].strip().split()[0] == 'stack:': 50 | # series_labels should be interpreted as the labels for the different segments of the stacked bar chart here. 51 | series_labels = lines[3].strip().split(':')[1].strip().split() 52 | intermediate_y_values = [] 53 | lines_per_series = len(x_labels) 54 | for line in lines[4:lines_per_series + 4]: 55 | sub_list = [] 56 | for value in line.strip().split(): 57 | sub_list.append(float(value)) 58 | intermediate_y_values.append(sub_list) 59 | for i in range(len(intermediate_y_values[0])): 60 | y_values.append([intermediate_y_values[j][i] for j in range(len(intermediate_y_values))]) 61 | stack = True 62 | else: 63 | series_labels.append("") 64 | series = [float(line.strip()) for line in lines[3:]] 65 | y_values.append(series) 66 | 67 | return x_axis_label, y_axis_label, x_labels, y_values, series_labels, stack 68 | 69 | def plot_data(x_axis_label, y_axis_label, x_labels, y_values, series_labels, stack, rotation, plot_type, output_filename, x_justification='right'): 70 | plt.figure(figsize=(10, 6)) 71 | 72 | bar_width = 0.5 73 | 74 | if stack: 75 | for i in range(len(y_values)): 76 | sum_y_values = [] 77 | for j in range(len(y_values[i])): 78 | sum_y_values.append(sum([y_values[k][j] for k in range(i)])) 79 | plt.bar(x_labels, y_values[i], label=series_labels[i], bottom=sum_y_values, width=bar_width) 80 | plt.legend() 81 | else: 82 | if plot_type == 'line': 83 | if len(series_labels) > 1: 84 | for i in range(len(y_values)): 85 | plt.plot(x_labels, y_values[i], marker='o', label=series_labels[i]) 86 | plt.legend() 87 | else: 88 | plt.plot(x_labels, y_values[0], marker='o') 89 | elif plot_type == 'bar': 90 | if len(series_labels) > 1: 91 | for i in range(len(y_values)): 92 | plt.bar(x_labels, y_values[i], label=series_labels[i], width=bar_width) 93 | plt.legend() 94 | else: 95 | plt.bar(x_labels, y_values[0], width=bar_width) 96 | else: 97 | print("Invalid plot type. Use 'line' or 'bar'.") 98 | return 99 | 100 | fontsize=22 101 | 102 | plt.xlabel(x_axis_label, fontsize=fontsize) 103 | plt.ylabel(y_axis_label, fontsize=fontsize) 104 | # plt.title(f'{x_axis_label} vs {y_axis_label}', fontsize=fontsize) 105 | if len(series_labels) > 1: 106 | # Count up the total number of characters in the series labels 107 | total_chars = sum([len(label) for label in series_labels]) 108 | n_cols = math.ceil(len(series_labels)/math.ceil(total_chars/20)) 109 | plt.legend(loc='upper center', bbox_to_anchor=(0.5, -0.2), fontsize=fontsize-10, ncol=n_cols) 110 | plt.grid(True) 111 | plt.xticks(rotation=rotation, ha=x_justification, fontsize=fontsize) 112 | plt.yticks(fontsize=fontsize) 113 | plt.tight_layout() 114 | # Output to file 115 | plt.savefig(output_filename) 116 | # Display the plot 117 | # plt.show() 118 | 119 | def main(): 120 | if len(sys.argv) != 6: 121 | print("Usage: python generate_plot.py ") 122 | sys.exit(1) 123 | 124 | filename = sys.argv[1] 125 | rotation = float(sys.argv[2]) 126 | x_justification = sys.argv[3] 127 | plot_type = sys.argv[4] 128 | output_filename = sys.argv[5] 129 | x_axis_label, y_axis_label, x_labels, y_values, series_labels, stack = read_data(filename) 130 | plot_data(x_axis_label, y_axis_label, x_labels, y_values, series_labels, stack, rotation, plot_type, output_filename, x_justification) 131 | 132 | if __name__ == "__main__": 133 | main() 134 | -------------------------------------------------------------------------------- /io_definitions.xml: -------------------------------------------------------------------------------- 1 | 78 | 79 | 80 | 84 | 86 | 88 | 89 | 91 | 92 | 101 | 102 | 103 | 112 | 113 | 122 | 123 | 132 | 133 | 142 | 143 | 152 | 153 | 155 | 157 | 158 | 160 | 161 | 170 | 171 | 173 | 174 | 178 | 187 | 188 | 197 | 198 | 207 | 208 | 217 | 218 | 227 | 228 | 237 | 238 | 247 | 248 | 257 | 258 | 267 | 268 | 270 | 271 | 272 | 281 | 282 | 291 | 292 | 301 | 302 | 305 | 314 | 315 | 324 | 325 | 334 | 335 | 344 | 345 | 354 | 355 | 356 | 365 | 366 | 367 | -------------------------------------------------------------------------------- /layer_definitions.xml: -------------------------------------------------------------------------------- 1 | 72 | 73 | 74 | 75 | 76 | 87 | 88 | 90 | 91 | 102 | 103 | 104 | 114 | 115 | 116 | 126 | 127 | 128 | 138 | 139 | 141 | 143 | 144 | 145 | 146 | 147 | 157 | 158 | 168 | 169 | 172 | 182 | 183 | 186 | 196 | 197 | 200 | 210 | 211 | 212 | 222 | 223 | 224 | 225 | 235 | 236 | 246 | 247 | 257 | 258 | 259 | 260 | 270 | 271 | 281 | 282 | 292 | 293 | 294 | 304 | 305 | 315 | 316 | 326 | 327 | 328 | -------------------------------------------------------------------------------- /load_and_test_design.py: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Filename: load_and_test_design.py 19 | # Author: Alexander Graening 20 | # Affiliation: University of California, Los Angeles 21 | # Email: agraening@ucla.edu 22 | # 23 | # Description: This is the main file used to launch loading a single design and viewing cost. 24 | # ==================================================================================== 25 | 26 | import design as d 27 | import readDesignFromFile as readDesign 28 | import sys 29 | import time 30 | 31 | 32 | # Main function 33 | def main(): 34 | # Get start time 35 | start_time = time.time() 36 | # Read the file names as command line arguments. 37 | if len(sys.argv) != 8: 38 | print("Usage: python load_and_test_design.py ") 39 | return 1 40 | 41 | # Read the File Names as Command Line Arguments 42 | io_file = sys.argv[1] 43 | layer_file = sys.argv[2] 44 | wafer_process_file = sys.argv[3] 45 | assembly_process_file = sys.argv[4] 46 | test_file = sys.argv[5] 47 | netlist_file = sys.argv[6] 48 | chip_file = sys.argv[7] 49 | 50 | # Read the Design Library Files 51 | io_list = readDesign.io_definition_list_from_file(io_file) 52 | layer_list = readDesign.layer_definition_list_from_file(layer_file) 53 | wafer_process_list = readDesign.wafer_process_definition_list_from_file(wafer_process_file) 54 | assembly_process_list = readDesign.assembly_process_definition_list_from_file(assembly_process_file) 55 | test_process_list = readDesign.test_process_definition_list_from_file(test_file) 56 | 57 | # Read the Design Netlist File 58 | adjacency_matrix, utilization, names = readDesign.global_adjacency_matrix_from_file(netlist_file,io_list) 59 | 60 | # Read the System Definition 61 | sip = d.Chip(filename = chip_file, etree = None, parent_chip = None, wafer_process_list = wafer_process_list, assembly_process_list = assembly_process_list, test_process_list = test_process_list, layers = layer_list, ios = io_list, adjacency_matrix_definitions = adjacency_matrix, average_bandwidth_utilization=utilization, block_names = names, static = False) 62 | 63 | # Print the Design Description 64 | # sip.print_description() 65 | 66 | #print("Cost of design = " + str(sip.get_cost())) 67 | print(sip.compute_total_cost()) 68 | 69 | # for chip in sip.get_chips(): 70 | # print(chip.name + " " + str(chip.get_cost())) 71 | 72 | end_time = time.time() 73 | 74 | #print("Total time: " + str(end_time - start_time) + " seconds") 75 | 76 | return 0 77 | 78 | 79 | # Setup auto-run of main function. 80 | if __name__ == "__main__": 81 | main() 82 | -------------------------------------------------------------------------------- /load_and_test_design_test_breakdown.py: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Filename: load_and_test_design.py 19 | # Author: Alexander Graening 20 | # Affiliation: University of California, Los Angeles 21 | # Email: agraening@ucla.edu 22 | # 23 | # Description: This is the main file used to launch loading a single design and viewing cost. 24 | # ==================================================================================== 25 | 26 | import design as d 27 | import readDesignFromFile as readDesign 28 | import sys 29 | import time 30 | 31 | 32 | # Main function 33 | def main(): 34 | # Get start time 35 | start_time = time.time() 36 | # Read the file names as command line arguments. 37 | if len(sys.argv) != 8: 38 | print("Usage: python load_and_test_design.py ") 39 | return 1 40 | 41 | # Read the File Names as Command Line Arguments 42 | io_file = sys.argv[1] 43 | layer_file = sys.argv[2] 44 | wafer_process_file = sys.argv[3] 45 | assembly_process_file = sys.argv[4] 46 | test_file = sys.argv[5] 47 | netlist_file = sys.argv[6] 48 | chip_file = sys.argv[7] 49 | 50 | # Read the Design Library Files 51 | io_list = readDesign.io_definition_list_from_file(io_file) 52 | layer_list = readDesign.layer_definition_list_from_file(layer_file) 53 | wafer_process_list = readDesign.wafer_process_definition_list_from_file(wafer_process_file) 54 | assembly_process_list = readDesign.assembly_process_definition_list_from_file(assembly_process_file) 55 | test_process_list = readDesign.test_process_definition_list_from_file(test_file) 56 | 57 | # Read the Design Netlist File 58 | adjacency_matrix, utilization, names = readDesign.global_adjacency_matrix_from_file(netlist_file,io_list) 59 | 60 | # Read the System Definition 61 | sip = d.Chip(filename = chip_file, etree = None, parent_chip = None, wafer_process_list = wafer_process_list, assembly_process_list = assembly_process_list, test_process_list = test_process_list, layers = layer_list, ios = io_list, adjacency_matrix_definitions = adjacency_matrix, average_bandwidth_utilization=utilization, block_names = names, static = False) 62 | 63 | # Print the Design Description 64 | # sip.print_description() 65 | 66 | #print("Cost of design = " + str(sip.get_cost())) 67 | print(str(sip.compute_total_non_scrap_cost()) + " " + str(sip.compute_scrap_cost())) 68 | 69 | # for chip in sip.get_chips(): 70 | # print(chip.name + " " + str(chip.get_cost())) 71 | 72 | end_time = time.time() 73 | 74 | #print("Total time: " + str(end_time - start_time) + " seconds") 75 | 76 | return 0 77 | 78 | 79 | # Setup auto-run of main function. 80 | if __name__ == "__main__": 81 | main() 82 | -------------------------------------------------------------------------------- /netlist.xml: -------------------------------------------------------------------------------- 1 | 75 | 76 | 77 | 78 | 84 | 85 | 86 | 92 | 93 | 94 | 100 | 101 | 102 | 108 | 109 | 110 | 116 | 117 | 118 | 124 | 125 | 126 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /readDesignFromFile.py: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Filename: readDesignFromFile.py 19 | # Author: Alexander Graening 20 | # Affiliation: University of California, Los Angeles 21 | # Email: agraening@ucla.edu 22 | # 23 | # Description: This file contains the functions to read the given library .xml files. 24 | # ==================================================================================== 25 | 26 | import design as d 27 | import numpy as np 28 | import xml.etree.ElementTree as ET 29 | import math 30 | import sys 31 | 32 | # Note that in if you add new parameters to the XML file, you will need to add them to the class constructors in design.py 33 | # This means that you will also need to add the initial values to the class declaration in the following functions 34 | # otherwise there will be a rather confusing error since the static attribute will be set True by default. 35 | 36 | # Function to read the wafer process definitions. 37 | def wafer_process_definition_list_from_file(filename): 38 | # print("Reading wafer process definitions from file: " + filename) 39 | # Read the XML file. 40 | tree = ET.parse(filename) 41 | # Get root of the XML file. 42 | root = tree.getroot() 43 | # List of wafer process . 44 | wp_list = [] 45 | # Iterate over the IO definitions. 46 | for wp_def in root: 47 | # Create an Wafer Process object. 48 | wp = d.WaferProcess(name = "", wafer_diameter = 0.0, edge_exclusion = 0.0, wafer_process_yield = 0.0, 49 | dicing_distance = 0.0, reticle_x = 0.0, reticle_y = 0.0, wafer_fill_grid = "False", 50 | nre_front_end_cost_per_mm2_memory = 0.0, nre_back_end_cost_per_mm2_memory = 0.0, 51 | nre_front_end_cost_per_mm2_logic = 0.0, nre_back_end_cost_per_mm2_logic = 0.0, 52 | nre_front_end_cost_per_mm2_analog = 0.0, nre_back_end_cost_per_mm2_analog = 0.0, 53 | static = False) 54 | attributes = wp_def.attrib 55 | # Iterate over the IO definition attributes. 56 | # Set the IO object attributes. 57 | wp.name = attributes["name"] 58 | wp.wafer_diameter =float(attributes["wafer_diameter"]) 59 | wp.edge_exclusion = float(attributes["edge_exclusion"]) 60 | wp.wafer_process_yield = float(attributes["wafer_process_yield"]) 61 | wp.dicing_distance = float(attributes["dicing_distance"]) 62 | wp.reticle_x = float(attributes["reticle_x"]) 63 | wp.reticle_y = float(attributes["reticle_y"]) 64 | wp.wafer_fill_grid = attributes["wafer_fill_grid"] 65 | wp.nre_front_end_cost_per_mm2_memory = float(attributes["nre_front_end_cost_per_mm2_memory"]) 66 | wp.nre_back_end_cost_per_mm2_memory = float(attributes["nre_back_end_cost_per_mm2_memory"]) 67 | wp.nre_front_end_cost_per_mm2_logic = float(attributes["nre_front_end_cost_per_mm2_logic"]) 68 | wp.nre_back_end_cost_per_mm2_logic = float(attributes["nre_back_end_cost_per_mm2_logic"]) 69 | wp.nre_front_end_cost_per_mm2_analog = float(attributes["nre_front_end_cost_per_mm2_analog"]) 70 | wp.nre_back_end_cost_per_mm2_analog = float(attributes["nre_back_end_cost_per_mm2_analog"]) 71 | wp.set_static() 72 | # Append the wafer_process object to the list. 73 | wp_list.append(wp) 74 | # Return the list of wafer process definition objects. 75 | return wp_list 76 | 77 | # Define a function to read the IO definitions from a file. 78 | def io_definition_list_from_file(filename): 79 | # print("Reading IO definitions from file: " + filename) 80 | # Read the XML file. 81 | tree = ET.parse(filename) 82 | root = tree.getroot() 83 | # Create a list of IO objects. 84 | io_list = [] 85 | # Iterate over the IO definitions. 86 | for io_def in root: 87 | # Create an IO object. 88 | io = d.IO(type = "", rx_area = 0.0, tx_area = 0.0, shoreline = 0.0, bandwidth = 0.0, wire_count = 0, 89 | bidirectional = "False", energy_per_bit = 0.0, reach = 0.0, static = False) 90 | attributes = io_def.attrib 91 | # Iterate over the IO definition attributes. 92 | # Set the IO object attributes. 93 | io.type = attributes["type"] 94 | io.rx_area = float(attributes["rx_area"]) 95 | io.tx_area = float(attributes["tx_area"]) 96 | io.shoreline = float(attributes["shoreline"]) 97 | io.bandwidth = float(attributes["bandwidth"]) 98 | io.wire_count = int(attributes["wire_count"]) 99 | io.bidirectional = attributes["bidirectional"] 100 | io.energy_per_bit = float(attributes["energy_per_bit"]) 101 | io.reach = float(attributes["reach"]) 102 | io.set_static() 103 | # Append the IO object to the list. 104 | io_list.append(io) 105 | # Return the list of IO objects. 106 | return io_list 107 | 108 | # Define a function to read the layer definitions from a file. 109 | def layer_definition_list_from_file(filename): 110 | # print("Reading layer definitions from file: " + filename) 111 | # Read the XML file. 112 | tree = ET.parse(filename) 113 | root = tree.getroot() 114 | # Create a list of layer objects. 115 | layer_list = [] 116 | # Iterate over the layer definitions. 117 | for layer_def in root: 118 | # Create a layer object. 119 | layer = d.Layer(name = "", active = "False", cost_per_mm2 = 0, transistor_density = 0, defect_density = 0, critical_area_ratio = 0, 120 | clustering_factor = 0, litho_percent = 0, mask_cost = 0, stitching_yield = 0, static = False) 121 | attributes = layer_def.attrib 122 | # Set the layer object attributes. 123 | layer.name = attributes["name"] 124 | layer.active = attributes["active"] 125 | layer.cost_per_mm2 = float(attributes["cost_per_mm2"]) 126 | layer.transistor_density = float(attributes["transistor_density"]) 127 | layer.defect_density = float(attributes["defect_density"]) 128 | layer.critical_area_ratio = float(attributes["critical_area_ratio"]) 129 | layer.clustering_factor = float(attributes["clustering_factor"]) 130 | layer.litho_percent = float(attributes["litho_percent"]) 131 | layer.mask_cost = float(attributes["nre_mask_cost"]) 132 | layer.stitching_yield = float(attributes["stitching_yield"]) 133 | 134 | layer.set_static() 135 | # Append the layer object to the list. 136 | layer_list.append(layer) 137 | # Return the list of layer objects. 138 | # print("At end of layer_list_from_file") 139 | return layer_list 140 | 141 | # Define a function to read the assembly process definitions from a file. 142 | def assembly_process_definition_list_from_file(filename): 143 | # print("Reading assembly process definitions from file: " + filename) 144 | # Read the XML file. 145 | tree = ET.parse(filename) 146 | root = tree.getroot() 147 | # Create a list of assembly process objects. 148 | assembly_process_list = [] 149 | # Iterate over the assembly process definitions. 150 | for assembly_process_def in root: 151 | # Create an assembly process object. 152 | assembly_process = d.Assembly(name = "", materials_cost_per_mm2 = 0.0, bb_cost_per_second = None, picknplace_machine_cost = 0.0, 153 | picknplace_machine_lifetime = 1.0, picknplace_machine_uptime = 0.0, picknplace_technician_yearly_cost = 0.0, 154 | picknplace_time = 0.0, picknplace_group = 0, bonding_machine_cost = 0.0, bonding_machine_lifetime = 1.0, 155 | bonding_machine_uptime = 0.0, bonding_technician_yearly_cost = 0.0, bonding_time = 0.0, 156 | bonding_group = 0, die_separation = 0.0, edge_exclusion = 0.0, bonding_pitch = 0.0, max_pad_current_density = 0.0, 157 | alignment_yield = 0.0, bonding_yield = 0.0, dielectric_bond_defect_density = 0.0, static = False) 158 | 159 | attributes = assembly_process_def.attrib 160 | 161 | assembly_process.name = attributes["name"] 162 | if attributes["bb_cost_per_second"] == "": 163 | assembly_process.bb_cost_per_second = None 164 | else: 165 | assembly_process.bb_cost_per_second = float(attributes["bb_cost_per_second"]) 166 | # # The following would set machine and technician parameters as a list of an undefined length. 167 | # # This has been switched to defining these parameters in terms of two values, one for bonding and one for pick and place. 168 | # # Leaving this for now, in case a reason comes up to rever to the old version. 169 | # assembly_process.set_machine_cost_list([float(x) for x in attributes["machine_cost_list"].split(',')]) 170 | # assembly_process.set_machine_lifetime_list([float(x) for x in attributes["machine_lifetime_list"].split(',')]) 171 | # assembly_process.set_machine_uptime_list([float(x) for x in attributes["machine_uptime_list"].split(',')]) 172 | # assembly_process.set_technician_yearly_cost_list([float(x) for x in attributes["technician_yearly_cost_list"].split(',')]) 173 | assembly_process.materials_cost_per_mm2 = float(attributes["materials_cost_per_mm2"]) 174 | assembly_process.picknplace_machine_cost = float(attributes["picknplace_machine_cost"]) 175 | assembly_process.picknplace_machine_lifetime = float(attributes["picknplace_machine_lifetime"]) 176 | assembly_process.picknplace_machine_uptime = float(attributes["picknplace_machine_uptime"]) 177 | assembly_process.picknplace_technician_yearly_cost = float(attributes["picknplace_technician_yearly_cost"]) 178 | assembly_process.picknplace_time = float(attributes["picknplace_time"]) 179 | assembly_process.picknplace_group = int(attributes["picknplace_group"]) 180 | assembly_process.bonding_machine_cost = float(attributes["bonding_machine_cost"]) 181 | assembly_process.bonding_machine_lifetime = float(attributes["bonding_machine_lifetime"]) 182 | assembly_process.bonding_machine_uptime = float(attributes["bonding_machine_uptime"]) 183 | assembly_process.bonding_technician_yearly_cost = float(attributes["bonding_technician_yearly_cost"]) 184 | assembly_process.bonding_time = float(attributes["bonding_time"]) 185 | assembly_process.bonding_group = int(attributes["bonding_group"]) 186 | assembly_process.compute_picknplace_cost_per_second() 187 | assembly_process.compute_bonding_cost_per_second() 188 | assembly_process.die_separation = float(attributes["die_separation"]) 189 | assembly_process.edge_exclusion = float(attributes["edge_exclusion"]) 190 | assembly_process.bonding_pitch = float(attributes["bonding_pitch"]) 191 | assembly_process.max_pad_current_density = float(attributes["max_pad_current_density"]) 192 | assembly_process.alignment_yield = float(attributes["alignment_yield"]) 193 | assembly_process.bonding_yield = float(attributes["bonding_yield"]) 194 | assembly_process.dielectric_bond_defect_density = float(attributes["dielectric_bond_defect_density"]) 195 | 196 | assembly_process.set_static() 197 | 198 | # Append the assembly process object to the list. 199 | assembly_process_list.append(assembly_process) 200 | # Return the list of assembly process objects. 201 | return assembly_process_list 202 | 203 | # Define a function to read the test process definitions from a file. 204 | def test_process_definition_list_from_file(filename): 205 | # print("Reading test process definitions from file: " + filename) 206 | # Read the XML file. 207 | tree = ET.parse(filename) 208 | root = tree.getroot() 209 | # Create a list of test process objects. 210 | test_process_list = [] 211 | # Iterate over the test process definitions. 212 | for test_process_def in root: 213 | # Create a test process object. 214 | test_process = d.Test(name = "", 215 | time_per_test_cycle = 0.0, cost_per_second = 0.0, samples_per_input = 1, 216 | test_self = "False", bb_self_pattern_count = "", bb_self_scan_chain_length = "", 217 | self_defect_coverage = 0.0, self_test_reuse = 1, 218 | self_num_scan_chains = 0, self_num_io_per_scan_chain = 0, self_num_test_io_offset = 0, 219 | self_test_failure_dist = "normal", 220 | test_assembly = "False", bb_assembly_pattern_count = "", bb_assembly_scan_chain_length = "", 221 | assembly_defect_coverage = 0.0, assembly_test_reuse = 1, 222 | assembly_num_scan_chains = 0, assembly_num_io_per_scan_chain = 0, assembly_num_test_io_offset = 0, 223 | assembly_test_failure_dist = "normal", 224 | static = False) 225 | 226 | attributes = test_process_def.attrib 227 | test_process.name = attributes["name"] 228 | test_process.time_per_test_cycle = float(attributes["time_per_test_cycle"]) 229 | test_process.samples_per_input = int(attributes["samples_per_input"]) 230 | 231 | test_process.cost_per_second = float(attributes["cost_per_second"]) 232 | 233 | test_process.test_self = attributes["test_self"] 234 | if attributes["bb_self_pattern_count"] == "": 235 | test_process.bb_self_pattern_count = None 236 | else: 237 | test_process.bb_self_pattern_count = int(attributes["bb_self_pattern_count"]) 238 | if attributes["bb_self_scan_chain_length"] == "": 239 | test_process.bb_self_scan_chain_length = None 240 | else: 241 | test_process.bb_self_scan_chain_length = int(attributes["bb_self_scan_chain_length"]) 242 | test_process.self_defect_coverage = float(attributes["self_defect_coverage"]) 243 | 244 | test_process.self_test_reuse = int(attributes["self_test_reuse"]) 245 | test_process.self_num_scan_chains = int(attributes["self_num_scan_chains"]) 246 | test_process.self_num_io_per_scan_chain = int(attributes["self_num_io_per_scan_chain"]) 247 | test_process.self_num_test_io_offset = int(attributes["self_num_test_io_offset"]) 248 | 249 | test_process.self_test_failure_dist = attributes["self_test_failure_dist"] 250 | 251 | test_process.test_assembly = attributes["test_assembly"] 252 | if attributes["bb_assembly_pattern_count"] == "": 253 | test_process.bb_assembly_pattern_count = None 254 | else: 255 | test_process.bb_assembly_pattern_count = int(attributes["bb_assembly_pattern_count"]) 256 | if attributes["bb_assembly_scan_chain_length"] == "": 257 | test_process.bb_assembly_scan_chain_length = None 258 | else: 259 | test_process.bb_assembly_scan_chain_length = int(attributes["bb_assembly_scan_chain_length"]) 260 | test_process.assembly_defect_coverage = float(attributes["assembly_defect_coverage"]) 261 | 262 | test_process.assembly_test_reuse = int(attributes["assembly_test_reuse"]) 263 | test_process.assembly_num_scan_chains = int(attributes["assembly_num_scan_chains"]) 264 | test_process.assembly_num_io_per_scan_chain = int(attributes["assembly_num_io_per_scan_chain"]) 265 | test_process.assembly_num_test_io_offset = int(attributes["assembly_num_test_io_offset"]) 266 | 267 | test_process.assembly_test_failure_dist = attributes["assembly_test_failure_dist"] 268 | 269 | test_process.set_static() 270 | 271 | #test_process.set_name(attributes["name"]) 272 | #test_process.set_test_self(True if attributes["test_self"] == "True" or attributes["test_self"] == "TRUE" or attributes["test_self"] == "true" else False) 273 | #test_process.set_test_assembly(True if attributes["test_assembly"] == "True" or attributes["test_assembly"] == "TRUE" or attributes["test_assembly"] == "true" else False) 274 | #test_process.set_self_defect_coverage(float(attributes["self_defect_coverage"])) 275 | #test_process.set_assembly_defect_coverage(float(attributes["assembly_defect_coverage"])) 276 | #test_process.set_self_test_cost_per_mm2(float(attributes["self_test_cost_per_mm2"])) 277 | #test_process.set_assembly_test_cost_per_mm2(float(attributes["assembly_test_cost_per_mm2"])) 278 | #test_process.set_self_pattern_count(int(attributes["self_pattern_count"])) 279 | #test_process.set_assembly_pattern_count(int(attributes["assembly_pattern_count"])) 280 | #test_process.set_self_test_failure_dist(int(attributes["self_test_failure_dist"])) 281 | #test_process.set_assembly_test_failure_dist(int(attributes["assembly_test_failure_dist"])) 282 | #test_process.set_static() 283 | 284 | test_process_list.append(test_process) 285 | 286 | return test_process_list 287 | 288 | # Define a function to construct the global adjacency matrix from the netlist file. 289 | def global_adjacency_matrix_from_file(filename, io_list): 290 | # TOSO: Add comments on building adjacency matrix. 291 | # print("Reading netlist from file: " + filename) 292 | # Read the XML file. 293 | tree = ET.parse(filename) 294 | root = tree.getroot() 295 | 296 | # Split the root.attrib["block_names"] string at commas and store in list. 297 | block_names = [] 298 | 299 | # The output format is a dictionary of items with format {type: numpy array adjacencey matrix} 300 | global_adjacency_matrix = {} 301 | # The following contains entries mirroring the global adjacency matrix 302 | # For each entry in the global adjacency matrix, this indicates the average bandwidth utilization 303 | # that should be used for the power calculation. 304 | average_bandwidth_utilization = {} 305 | 306 | # Iterate over the net definitions. 307 | for net_def in root: 308 | link_average_bandwidth_utilization = float(net_def.attrib["average_bandwidth_utilization"]) 309 | link_type = net_def.attrib["type"] 310 | # Check if the type of net is already a key in the dictionary. 311 | if link_type not in global_adjacency_matrix: 312 | # print("Adding new net type to adjacency matrix: " + link_type) 313 | # If so, append the new net to the existing adjacency matrix. 314 | global_adjacency_matrix[link_type] = np.zeros((len(block_names), len(block_names))) 315 | average_bandwidth_utilization[link_type] = np.zeros((len(block_names), len(block_names))) 316 | 317 | # If block 0 or block 1 is not in the list of block names, add it. 318 | if net_def.attrib["block0"] not in block_names: 319 | # print("Adding new block to adjacency matrix: " + net_def.attrib["block0"]) 320 | block_names.append(net_def.attrib["block0"]) 321 | # Add a row and column to each numpy adjacency matrix. 322 | for key in global_adjacency_matrix: 323 | global_adjacency_matrix[key] = np.pad(global_adjacency_matrix[key], ((0,1),(0,1)), 'constant', constant_values=0) 324 | average_bandwidth_utilization[key] = np.pad(average_bandwidth_utilization[key], ((0,1),(0,1)), 'constant', constant_values=0) 325 | if net_def.attrib["block1"] not in block_names: 326 | # print("Adding new block to adjacency matrix: " + net_def.attrib["block1"]) 327 | block_names.append(net_def.attrib["block1"]) 328 | # Add a row and column to each numpy adjacency matrix. 329 | for key in global_adjacency_matrix: 330 | global_adjacency_matrix[key] = np.pad(global_adjacency_matrix[key], ((0,1),(0,1)), 'constant', constant_values=0) 331 | average_bandwidth_utilization[key] = np.pad(average_bandwidth_utilization[key], ((0,1),(0,1)), 'constant', constant_values=0) 332 | 333 | io_bandwidth = None 334 | bidirectional = None 335 | 336 | # print("Searching for and IO type that matches " + link_type) 337 | for io in io_list: 338 | #print(io.type()) 339 | if link_type == io.type: 340 | io_bandwidth = io.bandwidth 341 | bidirectional = io.bidirectional 342 | 343 | if io_bandwidth is None or bidirectional is None: 344 | print("ERROR: Net type " + link_type + " not found in io_list.") 345 | sys.exit(1) 346 | 347 | # Find the indices of the two blocks connected by the net. 348 | block1_index = block_names.index(net_def.attrib["block0"]) 349 | block2_index = block_names.index(net_def.attrib["block1"]) 350 | 351 | if net_def.attrib["bb_count"] == "": 352 | ios_to_add = int(math.ceil(float(net_def.attrib["bandwidth"])/io_bandwidth)) 353 | else: 354 | ios_to_add = int(net_def.attrib["bb_count"]) 355 | if ios_to_add == 0: 356 | peak_utilization_factor = 1 357 | else: 358 | peak_utilization_factor = float(net_def.attrib["bandwidth"])/(ios_to_add*io_bandwidth) 359 | link_average_bandwidth_utilization *= peak_utilization_factor 360 | if not bidirectional: 361 | if average_bandwidth_utilization[link_type][block1_index,block2_index] == 0: 362 | average_bandwidth_utilization[link_type][block1_index,block2_index] = link_average_bandwidth_utilization 363 | else: 364 | average_bandwidth_utilization[link_type][block1_index,block2_index] = (average_bandwidth_utilization[link_type][block1_index,block2_index]*global_adjacency_matrix[link_type][block1_index,block2_index] + link_average_bandwidth_utilization*ios_to_add)/(global_adjacency_matrix[link_type][block1_index,block2_index] + ios_to_add) 365 | global_adjacency_matrix[link_type][block1_index,block2_index] += ios_to_add 366 | else: 367 | if average_bandwidth_utilization[link_type][block1_index,block2_index] == 0: 368 | average_bandwidth_utilization[link_type][block1_index,block2_index] = link_average_bandwidth_utilization 369 | else: 370 | average_bandwidth_utilization[link_type][block1_index,block2_index] = (average_bandwidth_utilization[link_type][block1_index,block2_index]*global_adjacency_matrix[link_type][block1_index,block2_index] + link_average_bandwidth_utilization*ios_to_add)/(global_adjacency_matrix[link_type][block1_index,block2_index] + ios_to_add) 371 | global_adjacency_matrix[link_type][block1_index,block2_index] += ios_to_add 372 | if average_bandwidth_utilization[link_type][block2_index,block1_index] == 0: 373 | average_bandwidth_utilization[link_type][block2_index,block1_index] = link_average_bandwidth_utilization 374 | else: 375 | average_bandwidth_utilization[link_type][block2_index,block1_index] = (average_bandwidth_utilization[link_type][block2_index,block1_index]*global_adjacency_matrix[link_type][block2_index,block1_index] + link_average_bandwidth_utilization*ios_to_add)/(global_adjacency_matrix[link_type][block2_index,block1_index] + ios_to_add) 376 | global_adjacency_matrix[link_type][block2_index,block1_index] += ios_to_add 377 | 378 | return global_adjacency_matrix, average_bandwidth_utilization, block_names 379 | 380 | # Define a function to construct the root chip and all subchips from a definition file. 381 | def chip_from_dict(etree, io_list, layer_list, wafer_process_list, assembly_process_list, test_process_list, global_adjacency_matrix, average_bandwidth_utilization, block_names): 382 | chip = d.Chip(filename = None, etree = etree, parent_chip = None, wafer_process_list = wafer_process_list, assembly_process_list = assembly_process_list, test_process_list = test_process_list, layers = layer_list, ios = io_list, adjacency_matrix_definitions = global_adjacency_matrix, average_bandwidth_utilization=average_bandwidth_utilization, block_names = block_names, static = False) 383 | return chip 384 | -------------------------------------------------------------------------------- /run_all_sweeps.sh: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Filename: run_all_sweeps.sh 19 | # Author: Alexander Graening 20 | # Affiliation: University of California, Los Angeles 21 | # Email: agraening@ucla.edu 22 | # ==================================================================================== 23 | 24 | 25 | # Sweep script for CATCH: a Cost Analysis Tool for Co-optimization of chiplet-based Heterogeneous systems" 26 | # Simply run with sh run_all_sweeps.sh to generate all plots in the paper. 27 | 28 | # For sweeps, use python search_and_replace.py 29 | # Also, clean up temp files to avoid workspace bloat. 30 | 31 | echo 32 | echo "Running all sweeps" 33 | 34 | echo 35 | python generate_grid_test_files.py 2 UCIe_advanced True False 32 100 0.0 36 | python generate_grid_test_files.py 4 UCIe_advanced True False 32 100 0.0 37 | python generate_grid_test_files.py 9 UCIe_advanced True False 32 100 0.0 38 | python generate_grid_test_files.py 16 UCIe_advanced True False 32 100 0.0 39 | python generate_grid_test_files.py 25 UCIe_advanced True False 32 100 0.0 40 | python generate_grid_test_files.py 36 UCIe_advanced True False 32 100 0.0 41 | python generate_grid_test_files.py 49 UCIe_advanced True False 32 100 0.0 42 | python generate_grid_test_files.py 64 UCIe_advanced True False 32 100 0.0 43 | 44 | echo 45 | echo "Sweeping size" 46 | sh sweep_chiplet_size.sh > sweep_chiplet_size_results.txt 47 | cat sweep_chiplet_size_results.txt 48 | python generate_plot.py sweep_chiplet_size_results.txt 0 center line sweep_chiplet_size_results.png 49 | rm sweep_chiplet_size_results.txt 50 | 51 | echo 52 | echo "Sweeping defect density" 53 | sh sweep_defect_density.sh > sweep_defect_density_results.txt 54 | cat sweep_defect_density_results.txt 55 | python generate_plot.py sweep_defect_density_results.txt 0 center line sweep_defect_density_results.png 56 | rm sweep_defect_density_results.txt 57 | 58 | echo 59 | echo "Sweeping assembly process" 60 | sh sweep_assembly_process.sh > sweep_assembly_process_results.txt 61 | cat sweep_assembly_process_results.txt 62 | python generate_plot.py sweep_assembly_process_results.txt 0 center line sweep_assembly_process_results.png 63 | rm sweep_assembly_process_results.txt 64 | 65 | echo 66 | echo "Sweeping NRE" 67 | sh sweep_nre.sh > sweep_nre_results.txt 68 | cat sweep_nre_results.txt 69 | python generate_plot.py sweep_nre_results.txt 0 center line sweep_nre_results.png 70 | rm sweep_nre_results.txt 71 | 72 | echo "Cleaning up" 73 | rm chiplet_2_400_def.xml 74 | rm chiplet_2_400_netlist.xml 75 | rm chiplet_4_200_def.xml 76 | rm chiplet_4_200_netlist.xml 77 | rm chiplet_9_88_def.xml 78 | rm chiplet_9_88_netlist.xml 79 | rm chiplet_16_50_def.xml 80 | rm chiplet_16_50_netlist.xml 81 | rm chiplet_25_32_def.xml 82 | rm chiplet_25_32_netlist.xml 83 | rm chiplet_36_22_def.xml 84 | rm chiplet_36_22_netlist.xml 85 | rm chiplet_49_16_def.xml 86 | rm chiplet_49_16_netlist.xml 87 | rm chiplet_64_12_def.xml 88 | rm chiplet_64_12_netlist.xml 89 | 90 | # To see the impact of sweeping design quantity to see the impact on NRE for 91 | # a case where a single design unit is repeated homogeneously across the design 92 | # we adjust the design costs as below. 93 | # 94 | # Note that the design cost here increases for smaller dies to account for the 95 | # increasing quantities since different dies are not marked as the same. 96 | # Instead, quantities are inflated. 97 | echo 98 | python generate_grid_test_files.py 2 UCIe_advanced True False 32 100 0.02 99 | python generate_grid_test_files.py 4 UCIe_advanced True False 32 100 0.04 100 | python generate_grid_test_files.py 9 UCIe_advanced True False 32 100 0.09 101 | python generate_grid_test_files.py 16 UCIe_advanced True False 32 100 0.16 102 | python generate_grid_test_files.py 25 UCIe_advanced True False 32 100 0.25 103 | python generate_grid_test_files.py 36 UCIe_advanced True False 32 100 0.36 104 | python generate_grid_test_files.py 49 UCIe_advanced True False 32 100 0.49 105 | python generate_grid_test_files.py 64 UCIe_advanced True False 32 100 0.64 106 | 107 | echo 108 | echo "Sweeping NRE" 109 | sh sweep_nre.sh > sweep_nre_design_results.txt 110 | cat sweep_nre_design_results.txt 111 | python generate_plot.py sweep_nre_design_results.txt 0 center line sweep_nre_design_results.png 112 | rm sweep_nre_design_results.txt 113 | 114 | echo "Cleaning up" 115 | rm chiplet_2_400_def.xml 116 | rm chiplet_2_400_netlist.xml 117 | rm chiplet_4_200_def.xml 118 | rm chiplet_4_200_netlist.xml 119 | rm chiplet_9_88_def.xml 120 | rm chiplet_9_88_netlist.xml 121 | rm chiplet_16_50_def.xml 122 | rm chiplet_16_50_netlist.xml 123 | rm chiplet_25_32_def.xml 124 | rm chiplet_25_32_netlist.xml 125 | rm chiplet_36_22_def.xml 126 | rm chiplet_36_22_netlist.xml 127 | rm chiplet_49_16_def.xml 128 | rm chiplet_49_16_netlist.xml 129 | rm chiplet_64_12_def.xml 130 | rm chiplet_64_12_netlist.xml 131 | 132 | # NRE_1_custom uses a custom test case 133 | 134 | echo 135 | echo "Sweeping NRE with a single custom die in a group of 4" 136 | sh sweep_nre_1_custom.sh > sweep_nre_1_custom_results.txt 137 | cat sweep_nre_1_custom_results.txt 138 | python generate_plot.py sweep_nre_1_custom_results.txt 0 center bar sweep_nre_1_custom_results.png 139 | rm sweep_nre_1_custom_results.txt 140 | 141 | echo 142 | python generate_grid_test_files.py 16 UCIe_standard True True 10000 100 0.0 143 | 144 | echo 145 | echo "Sweep IO reach" 146 | sh sweep_reach.sh > sweep_reach_results.txt 147 | cat sweep_reach_results.txt 148 | python generate_plot.py sweep_reach_results.txt 0 center bar sweep_reach_results.png 149 | rm sweep_reach_results.txt 150 | 151 | echo "Cleaning up" 152 | rm chiplet_16_50_def.xml 153 | rm chiplet_16_50_netlist.xml 154 | 155 | echo 156 | python generate_grid_test_files.py 16 UCIe_standard True True 32 100 0.0 157 | 158 | echo 159 | echo "Sweeping different substrates" 160 | sh sweep_substrates.sh > sweep_substrates_results.txt 161 | cat sweep_substrates_results.txt 162 | python generate_plot.py sweep_substrates_results.txt 0 center bar sweep_substrates_results.png 163 | rm sweep_substrates_results.txt 164 | 165 | echo 166 | echo "Sweep test coverage" 167 | sh sweep_test_coverage.sh > sweep_test_coverage_results.txt 168 | cat sweep_test_coverage_results.txt 169 | python generate_plot.py sweep_test_coverage_results.txt 0 center bar sweep_test_coverage_results.png 170 | rm sweep_test_coverage_results.txt 171 | 172 | echo 173 | echo "Sweep test coverage immature process" 174 | sh sweep_test_coverage_immature.sh > sweep_test_coverage_immature_results.txt 175 | cat sweep_test_coverage_immature_results.txt 176 | python generate_plot.py sweep_test_coverage_immature_results.txt 0 center bar sweep_test_coverage_immature_results.png 177 | rm sweep_test_coverage_immature_results.txt 178 | 179 | echo "Cleaning up" 180 | rm chiplet_16_50_def.xml 181 | rm chiplet_16_50_netlist.xml 182 | 183 | # The following sweeps use the same basic testcase. 184 | echo 185 | python generate_grid_test_files_3d.py 16 UCIe_advanced True False 32 100 0.0 186 | 187 | echo 188 | echo "Sweep test coverage 3D" 189 | sh sweep_test_coverage.sh > sweep_test_coverage_results.txt 190 | cat sweep_test_coverage_results.txt 191 | python generate_plot.py sweep_test_coverage_results.txt 0 center bar sweep_test_coverage_3d_results.png 192 | rm sweep_test_coverage_results.txt 193 | 194 | echo 195 | echo "Sweep test coverage 3D immature process" 196 | sh sweep_test_coverage_immature.sh > sweep_test_coverage_immature_results.txt 197 | cat sweep_test_coverage_immature_results.txt 198 | python generate_plot.py sweep_test_coverage_immature_results.txt 0 center bar sweep_test_coverage_immature_3d_results.png 199 | rm sweep_test_coverage_immature_results.txt 200 | 201 | echo "Cleaning up" 202 | rm chiplet_16_50_def.xml 203 | rm chiplet_16_50_netlist.xml 204 | -------------------------------------------------------------------------------- /search_and_replace.py: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # Read command line arguments 18 | import sys 19 | 20 | if len(sys.argv) != 5: 21 | print("Usage: python script.py input_file string_to_replace replacement_string output_file") 22 | sys.exit(1) 23 | 24 | input_file, string_to_replace, replacement_string, output_file = sys.argv[1:] 25 | 26 | # Read input file 27 | try: 28 | with open(input_file, 'r') as fin: 29 | content = fin.read() 30 | except FileNotFoundError: 31 | print(f"Input file '{input_file}' not found.") 32 | sys.exit(1) 33 | 34 | # Replace occurrences 35 | new_content = content.replace(string_to_replace, replacement_string) 36 | 37 | # Write to output file 38 | with open(output_file, 'w') as fout: 39 | fout.write(new_content) 40 | 41 | # print(f"Replaced '{string_to_replace}' with '{replacement_string}' in '{input_file}'. Result saved in '{output_file}'.") 42 | 43 | -------------------------------------------------------------------------------- /sip.xml: -------------------------------------------------------------------------------- 1 | 128 | 129 | 155 | 181 | 207 | 208 | 209 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /sweep_assembly_process.sh: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Author: Alexander Graening 19 | # Affiliation: University of California, Los Angeles 20 | # Email: agraening@ucla.edu 21 | # ==================================================================================== 22 | 23 | INPUT_FILE_PRE="chiplet_" 24 | INPUT_FILE_POST="_def.xml" 25 | INPUT_NETLIST_PRE="chiplet_" 26 | INPUT_NETLIST_POST="_netlist.xml" 27 | 28 | #SERIES="organic_25_simultaneous_bonding organic_55_simultaneous_bonding organic_simultaneous_bonding silicon_individual_bonding silicon_45_individual_bonding" 29 | SERIES="silicon_individual_bonding silicon_simultaneous_bonding organic_simultaneous_bonding" 30 | SWEEP="2_400 4_200 9_88 16_50 25_32 36_22 49_16 64_12" 31 | 32 | # echo "Creating a temporary file temp_${INPUT_FILE}" 33 | echo "x-axis label: Count_Size(mm2)" 34 | echo "y-axis label: Cost ($)" 35 | echo "Sweep: ${SWEEP}" 36 | for series in $SERIES 37 | do 38 | echo "series: ${series}" 39 | for size in $SWEEP 40 | do 41 | INPUT_FILE="${INPUT_FILE_PRE}${size}${INPUT_FILE_POST}" 42 | INPUT_NETLIST="${INPUT_NETLIST_PRE}${size}${INPUT_NETLIST_POST}" 43 | # echo "Replacing ${ap} in ${INPUT_FILE}" 44 | python search_and_replace.py ${INPUT_FILE} silicon_individual_bonding ${series} temp_${INPUT_FILE} 45 | 46 | # echo "$ap" 47 | # If ap includes the word "silicon", then also replace "combined_interposer_organic" with "combined_interposer_silicon" 48 | if echo "$series" | grep -q "silicon"; then 49 | # echo "Replacing combined_interposer_organic with combined_interposer_silicon" 50 | python search_and_replace.py temp_${INPUT_FILE} combined_interposer_organic combined_interposer_silicon temp_${INPUT_FILE} 51 | python search_and_replace.py ${INPUT_NETLIST} UCIe_standard UCIe_advanced temp_${INPUT_NETLIST} 52 | elif echo "$series" | grep -q "organic"; then 53 | # echo "Replacing combined_interposer_silicon with combined_interposer_organic" 54 | python search_and_replace.py temp_${INPUT_FILE} combined_interposer_silicon combined_interposer_organic temp_${INPUT_FILE} 55 | python search_and_replace.py ${INPUT_NETLIST} UCIe_advanced UCIe_standard temp_${INPUT_NETLIST} 56 | cp ${INPUT_NETLIST} temp_${INPUT_NETLIST} 57 | else 58 | echo "Error: assembly process does not contain silicon or organic" 59 | cp ${INPUT_NETLIST} temp_${INPUT_NETLIST} 60 | fi 61 | 62 | python load_and_test_design.py io_definitions.xml layer_definitions.xml wafer_process_definitions.xml assembly_process_definitions.xml test_definitions.xml temp_${INPUT_NETLIST} temp_${INPUT_FILE} 63 | # Note that it is possible to replace multiple lines by running search and replace on the output file instead of regenerating from scratch. 64 | # python search_and_replace.py temp_${INPUT_FILE} temp_${INPUT_FILE} 65 | rm temp_${INPUT_FILE} 66 | rm temp_${INPUT_NETLIST} 67 | done 68 | done 69 | -------------------------------------------------------------------------------- /sweep_chiplet_size.sh: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Author: Alexander Graening 19 | # Affiliation: University of California, Los Angeles 20 | # Email: agraening@ucla.edu 21 | # ==================================================================================== 22 | 23 | INPUT_FILE_PRE="chiplet_" 24 | INPUT_FILE_POST="_def.xml" 25 | INPUT_NETLIST_PRE="chiplet_" 26 | INPUT_NETLIST_POST="_netlist.xml" 27 | 28 | SWEEP="2_400 4_200 9_88 16_50 25_32 36_22 49_16 64_12" 29 | TECHNOLOGIES="3nm 5nm 7nm 10nm 12nm 40nm" 30 | 31 | echo "x-axis label: Count_Size(mm2)" 32 | echo "y-axis label: Cost ($)" 33 | echo "Sweep: ${SWEEP}" 34 | for tech in $TECHNOLOGIES 35 | do 36 | echo "series: ${tech}" 37 | 38 | for size in $SWEEP 39 | do 40 | INPUT_FILE="${INPUT_FILE_PRE}${size}${INPUT_FILE_POST}" 41 | INPUT_NETLIST="${INPUT_NETLIST_PRE}${size}${INPUT_NETLIST_POST}" 42 | python search_and_replace.py ${INPUT_FILE} combined_5nm combined_${tech} temp_${INPUT_FILE} 43 | python load_and_test_design.py io_definitions.xml layer_definitions.xml wafer_process_definitions.xml assembly_process_definitions.xml test_definitions.xml ${INPUT_NETLIST} temp_${INPUT_FILE} 44 | rm temp_${INPUT_FILE} 45 | done 46 | done 47 | -------------------------------------------------------------------------------- /sweep_defect_density.sh: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Author: Alexander Graening 19 | # Affiliation: University of California, Los Angeles 20 | # Email: agraening@ucla.edu 21 | # ==================================================================================== 22 | 23 | INPUT_FILE_PRE="chiplet_" 24 | INPUT_FILE_POST="_def.xml" 25 | INPUT_NETLIST_PRE="chiplet_" 26 | INPUT_NETLIST_POST="_netlist.xml" 27 | 28 | SWEEP="2_400 4_200 9_88 16_50 25_32 36_22 49_16 64_12" 29 | DEFECT_DENSITY="0.001 0.005 0.01" 30 | 31 | echo "x-axis label: Count_Size(mm2)" 32 | echo "y-axis label: Cost ($)" 33 | echo "Sweep: ${SWEEP}" 34 | tech="3nm" 35 | for dd in $DEFECT_DENSITY 36 | do 37 | echo "series: ${dd}" 38 | 39 | for size in $SWEEP 40 | do 41 | INPUT_FILE="${INPUT_FILE_PRE}${size}${INPUT_FILE_POST}" 42 | INPUT_NETLIST="${INPUT_NETLIST_PRE}${size}${INPUT_NETLIST_POST}" 43 | python search_and_replace.py ${INPUT_FILE} combined_5nm combined_3nm_${dd} temp_${INPUT_FILE} 44 | python load_and_test_design.py io_definitions.xml layer_definitions.xml wafer_process_definitions.xml assembly_process_definitions.xml test_definitions.xml ${INPUT_NETLIST} temp_${INPUT_FILE} 45 | rm temp_${INPUT_FILE} 46 | done 47 | done 48 | -------------------------------------------------------------------------------- /sweep_nre.sh: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Author: Alexander Graening 19 | # Affiliation: University of California, Los Angeles 20 | # Email: agraening@ucla.edu 21 | # ==================================================================================== 22 | 23 | INPUT_FILE_PRE="chiplet_" 24 | INPUT_FILE_POST="_def.xml" 25 | INPUT_NETLIST_PRE="chiplet_" 26 | INPUT_NETLIST_POST="_netlist.xml" 27 | 28 | SWEEP="2_400 4_200 9_88 16_50 25_32 36_22 49_16 64_12" 29 | 30 | QUANTITIES="10000 100000 1000000 10000000" 31 | 32 | 33 | echo "x-axis label: Count_Size(mm2)" 34 | echo "y-axis label: Cost ($)" 35 | echo "Sweep: ${SWEEP}" 36 | for q in $QUANTITIES 37 | do 38 | echo "series: ${q}" 39 | 40 | for size in $SWEEP 41 | do 42 | INPUT_FILE="${INPUT_FILE_PRE}${size}${INPUT_FILE_POST}" 43 | INPUT_NETLIST="${INPUT_NETLIST_PRE}${size}${INPUT_NETLIST_POST}" 44 | python search_and_replace.py ${INPUT_FILE} 10000000 $q temp_${INPUT_FILE} 45 | # Extract the part of size before a '_' and set it to a variable 46 | NUM_CHIPS=$(echo $size | cut -d'_' -f1) 47 | # Multiply NUM_CHIPS by 10000000 and set it to a variable 48 | QUANTITY_TO_REPLACE=$(($NUM_CHIPS * 10000000)) 49 | NEW_QUANTITY=$(($NUM_CHIPS * $q)) 50 | python search_and_replace.py temp_${INPUT_FILE} $QUANTITY_TO_REPLACE $NEW_QUANTITY temp_${INPUT_FILE} 51 | python load_and_test_design.py io_definitions.xml layer_definitions.xml wafer_process_definitions.xml assembly_process_definitions.xml test_definitions.xml ${INPUT_NETLIST} temp_${INPUT_FILE} 52 | rm temp_${INPUT_FILE} 53 | done 54 | done 55 | -------------------------------------------------------------------------------- /sweep_nre_1_custom.sh: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Author: Alexander Graening 19 | # Affiliation: University of California, Los Angeles 20 | # Email: agraening@ucla.edu 21 | # ==================================================================================== 22 | 23 | INPUT_FILE="chiplet_nre_study_def.xml" 24 | INPUT_NETLIST="chiplet_nre_study_netlist.xml" 25 | 26 | QUANTITIES="10000 100000 1000000 10000000" 27 | 28 | echo "x-axis label: New Die Quantity" 29 | echo "y-axis label: Cost ($)" 30 | echo "Sweep: $QUANTITIES" 31 | for q in $QUANTITIES 32 | do 33 | python search_and_replace.py ${INPUT_FILE} INSERTSWEEPQUANTITY $q temp_${INPUT_FILE} 34 | python load_and_test_design.py io_definitions.xml layer_definitions.xml wafer_process_definitions.xml assembly_process_definitions.xml test_definitions.xml ${INPUT_NETLIST} temp_${INPUT_FILE} 35 | rm temp_${INPUT_FILE} 36 | done 37 | -------------------------------------------------------------------------------- /sweep_reach.sh: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Author: Alexander Graening 19 | # Affiliation: University of California, Los Angeles 20 | # Email: agraening@ucla.edu 21 | # ==================================================================================== 22 | 23 | INPUT_FILE="chiplet_16_50_def.xml" 24 | INPUT_NETLIST_FILE="chiplet_16_50_netlist.xml" 25 | INPUT_IO_FILE="io_definitions.xml" 26 | INPUT_LAYER_FILE="layer_definitions.xml" 27 | INPUT_WAFER_FILE="wafer_process_definitions.xml" 28 | INPUT_ASSEMBLY_FILE="assembly_process_definitions.xml" 29 | INPUT_TEST_FILE="test_definitions.xml" 30 | 31 | IO_NAME="UCIe_standard" 32 | NEW_IO_NAME="2Gbs_100vCDM_" 33 | SWEEP="2mm 5mm 10mm 20mm" 34 | 35 | # echo "Creating a temporary file temp_${INPUT_FILE}" 36 | echo "x-axis label: Reach (mm)" 37 | echo "y-axis label: Cost ($)" 38 | echo "Sweep Reach for ${IO_NAME}: ${SWEEP}" 39 | for io in $SWEEP 40 | #organic_25_simultaneous_bonding organic_55_simultaneous_bonding organic_simultaneous_bonding silicon_individual_bonding silicon_45_individual_bonding 41 | do 42 | # echo "Replacing ${ap} in ${INPUT_FILE}" 43 | python search_and_replace.py ${INPUT_NETLIST_FILE} ${IO_NAME} ${NEW_IO_NAME}${io} temp_${INPUT_NETLIST_FILE} 44 | 45 | python load_and_test_design.py ${INPUT_IO_FILE} ${INPUT_LAYER_FILE} ${INPUT_WAFER_FILE} ${INPUT_ASSEMBLY_FILE} ${INPUT_TEST_FILE} temp_${INPUT_NETLIST_FILE} ${INPUT_FILE} 46 | # Note that it is possible to replace multiple lines by running search and replace on the output file instead of regenerating from scratch. 47 | # python search_and_replace.py temp_${INPUT_FILE} temp_${INPUT_FILE} 48 | done 49 | rm temp_${INPUT_NETLIST_FILE} 50 | # echo "Temp file removed." 51 | -------------------------------------------------------------------------------- /sweep_substrates.sh: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Author: Alexander Graening 19 | # Affiliation: University of California, Los Angeles 20 | # Email: agraening@ucla.edu 21 | # ==================================================================================== 22 | 23 | INPUT_FILE="chiplet_16_50_def.xml" 24 | INPUT_NETLIST="chiplet_16_50_netlist.xml" 25 | 26 | SWEEP="organic silicon glass" 27 | # SWEEP="organic_simultaneous_bonding silicon_individual_bonding" 28 | 29 | # echo "Creating a temporary file temp_${INPUT_FILE}" 30 | echo "x-axis label: Substrate" 31 | echo "y-axis label: Cost ($)" 32 | echo "Sweep: ${SWEEP}" 33 | for ap in $SWEEP 34 | #organic_25_simultaneous_bonding organic_55_simultaneous_bonding organic_simultaneous_bonding silicon_individual_bonding silicon_45_individual_bonding 35 | do 36 | # echo "Replacing ${ap} in ${INPUT_FILE}" 37 | if echo "$ap" | grep -q "organic"; then 38 | # echo "Replacing silicon_individual_bonding with organic_simultaneous_bonding" 39 | python search_and_replace.py ${INPUT_FILE} silicon_individual_bonding organic_simultaneous_bonding temp_${INPUT_FILE} 40 | cp ${INPUT_NETLIST} temp_${INPUT_NETLIST} 41 | elif echo "$ap" | grep -q "silicon"; then 42 | # echo "Replacing silicon_individual_bonding with silicon_individual_bonding" 43 | python search_and_replace.py ${INPUT_FILE} silicon_individual_bonding silicon_individual_bonding temp_${INPUT_FILE} 44 | python search_and_replace.py temp_${INPUT_NETLIST} UCIe_standard UCIe_advanced temp_${INPUT_NETLIST} 45 | elif echo "$ap" | grep -q "glass"; then 46 | # echo "Replacing silicon_individual_bonding with silicon_individual_bonding" 47 | python search_and_replace.py ${INPUT_FILE} silicon_individual_bonding glass_individual_bonding temp_${INPUT_FILE} 48 | python search_and_replace.py temp_${INPUT_NETLIST} UCIe_standard UCIe_advanced temp_${INPUT_NETLIST} 49 | else 50 | echo "Error: ap does not contain silicon, organic, or glass" 51 | cp ${INPUT_NETLIST} temp_${INPUT_NETLIST} 52 | fi 53 | 54 | # echo "$ap" 55 | # If ap includes the word "silicon", then also replace "combined_interposer_silicon" with "combined_interposer_silicon" 56 | if echo "$ap" | grep -q "silicon"; then 57 | # echo "Replacing combined_interposer_silicon with combined_interposer_silicon" 58 | python search_and_replace.py temp_${INPUT_FILE} combined_interposer_silicon combined_interposer_silicon temp_${INPUT_FILE} 59 | python search_and_replace.py ${INPUT_NETLIST} UCIe_standard UCIe_advanced temp_${INPUT_NETLIST} 60 | elif echo "$ap" | grep -q "organic"; then 61 | # echo "Replacing combined_interposer_silicon with combined_interposer_organic" 62 | python search_and_replace.py temp_${INPUT_FILE} combined_interposer_silicon combined_interposer_organic temp_${INPUT_FILE} 63 | cp ${INPUT_NETLIST} temp_${INPUT_NETLIST} 64 | elif echo "$ap" | grep -q "glass"; then 65 | # echo "Replacing combined_interposer_silicon with combined_interposer_organic" 66 | python search_and_replace.py temp_${INPUT_FILE} combined_interposer_silicon combined_interposer_glass temp_${INPUT_FILE} 67 | python search_and_replace.py ${INPUT_NETLIST} UCIe_standard UCIe_advanced temp_${INPUT_NETLIST} 68 | else 69 | echo "Error: ap does not contain silicon, organic, or glass" 70 | cp ${INPUT_NETLIST} temp_${INPUT_NETLIST} 71 | fi 72 | 73 | python load_and_test_design.py io_definitions.xml layer_definitions.xml wafer_process_definitions.xml assembly_process_definitions.xml test_definitions.xml temp_${INPUT_NETLIST} temp_${INPUT_FILE} 74 | # Note that it is possible to replace multiple lines by running search and replace on the output file instead of regenerating from scratch. 75 | # python search_and_replace.py temp_${INPUT_FILE} temp_${INPUT_FILE} 76 | done 77 | rm temp_${INPUT_FILE} 78 | rm temp_${INPUT_NETLIST} 79 | # echo "Temp file removed." 80 | -------------------------------------------------------------------------------- /sweep_test_coverage.sh: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Author: Alexander Graening 19 | # Affiliation: University of California, Los Angeles 20 | # Email: agraening@ucla.edu 21 | # ==================================================================================== 22 | 23 | INPUT_FILE="chiplet_16_50_def.xml" 24 | INPUT_NETLIST_FILE="chiplet_16_50_netlist.xml" 25 | INPUT_IO_FILE="io_definitions.xml" 26 | INPUT_LAYER_FILE="layer_definitions.xml" 27 | INPUT_WAFER_FILE="wafer_process_definitions.xml" 28 | INPUT_ASSEMBLY_FILE="assembly_process_definitions.xml" 29 | INPUT_TEST_FILE="test_definitions.xml" 30 | 31 | SWEEP="0.5 0.9 0.95 1.0" 32 | 33 | # echo "Creating a temporary file temp_${INPUT_FILE}" 34 | echo "x-axis label: Fault Coverage" 35 | echo "y-axis label: Cost ($)" 36 | echo "Sweep Test Coverage For: ${SWEEP}" 37 | echo "stack: non-scrap scrap" 38 | for coverage in $SWEEP 39 | #organic_25_simultaneous_bonding organic_55_simultaneous_bonding organic_simultaneous_bonding silicon_individual_bonding silicon_45_individual_bonding 40 | do 41 | # echo "Replacing ${ap} in ${INPUT_FILE}" 42 | # python search_and_replace.py ${INPUT_FILE} organic_simultaneous_bonding silicon_individual_bonding temp_${INPUT_FILE} 43 | # python search_and_replace.py temp_${INPUT_FILE} combined_interposer_organic combined_interposer_silicon temp_${INPUT_FILE} 44 | python search_and_replace.py ${INPUT_FILE} combined_5nm combined_3nm_0.005 temp_${INPUT_FILE} 45 | python search_and_replace.py temp_${INPUT_FILE} KGD_free_test free_test_${coverage} temp_${INPUT_FILE} 46 | 47 | python load_and_test_design_test_breakdown.py ${INPUT_IO_FILE} ${INPUT_LAYER_FILE} ${INPUT_WAFER_FILE} ${INPUT_ASSEMBLY_FILE} ${INPUT_TEST_FILE} ${INPUT_NETLIST_FILE} temp_${INPUT_FILE} 48 | # Note that it is possible to replace multiple lines by running search and replace on the output file instead of regenerating from scratch. 49 | # python search_and_replace.py temp_${INPUT_FILE} temp_${INPUT_FILE} 50 | done 51 | rm temp_${INPUT_FILE} 52 | # echo "Temp file removed." 53 | -------------------------------------------------------------------------------- /sweep_test_coverage_immature.sh: -------------------------------------------------------------------------------- 1 | # ======================================================================= 2 | # Copyright 2025 UCLA NanoCAD Laboratory 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ======================================================================= 16 | 17 | # ==================================================================================== 18 | # Author: Alexander Graening 19 | # Affiliation: University of California, Los Angeles 20 | # Email: agraening@ucla.edu 21 | # ==================================================================================== 22 | 23 | INPUT_FILE="chiplet_16_50_def.xml" 24 | INPUT_NETLIST_FILE="chiplet_16_50_netlist.xml" 25 | INPUT_IO_FILE="io_definitions.xml" 26 | INPUT_LAYER_FILE="layer_definitions.xml" 27 | INPUT_WAFER_FILE="wafer_process_definitions.xml" 28 | INPUT_ASSEMBLY_FILE="assembly_process_definitions.xml" 29 | INPUT_TEST_FILE="test_definitions.xml" 30 | 31 | SWEEP="0.5 0.9 0.95 1.0" 32 | 33 | # echo "Creating a temporary file temp_${INPUT_FILE}" 34 | echo "x-axis label: Fault Coverage" 35 | echo "y-axis label: Cost ($)" 36 | echo "Sweep Test Coverage For: ${SWEEP}" 37 | echo "stack: non-scrap scrap" 38 | for coverage in $SWEEP 39 | #organic_25_simultaneous_bonding organic_55_simultaneous_bonding organic_simultaneous_bonding silicon_individual_bonding silicon_45_individual_bonding 40 | do 41 | # echo "Replacing ${ap} in ${INPUT_FILE}" 42 | # python search_and_replace.py ${INPUT_FILE} organic_simultaneous_bonding silicon_individual_bonding temp_${INPUT_FILE} 43 | # python search_and_replace.py temp_${INPUT_FILE} combined_interposer_organic combined_interposer_silicon temp_${INPUT_FILE} 44 | python search_and_replace.py ${INPUT_FILE} combined_5nm combined_3nm_0.01 temp_${INPUT_FILE} 45 | python search_and_replace.py temp_${INPUT_FILE} KGD_free_test free_test_${coverage} temp_${INPUT_FILE} 46 | 47 | python load_and_test_design_test_breakdown.py ${INPUT_IO_FILE} ${INPUT_LAYER_FILE} ${INPUT_WAFER_FILE} ${INPUT_ASSEMBLY_FILE} ${INPUT_TEST_FILE} ${INPUT_NETLIST_FILE} temp_${INPUT_FILE} 48 | # Note that it is possible to replace multiple lines by running search and replace on the output file instead of regenerating from scratch. 49 | # python search_and_replace.py temp_${INPUT_FILE} temp_${INPUT_FILE} 50 | done 51 | rm temp_${INPUT_FILE} 52 | # echo "Temp file removed." 53 | -------------------------------------------------------------------------------- /test_definitions.xml: -------------------------------------------------------------------------------- 1 | 100 | 101 | 102 | 103 | 104 | 133 | 134 | 163 | 164 | 165 | 166 | 195 | 196 | 225 | 226 | 255 | 256 | 285 | 286 | 315 | 316 | 345 | 346 | 375 | 376 | 405 | 406 | 435 | 436 | 465 | 466 | 467 | -------------------------------------------------------------------------------- /wafer_process_definitions.xml: -------------------------------------------------------------------------------- 1 | 73 | 74 | 81 | 82 | 86 | 87 | 88 | 103 | 104 | 119 | 120 | 121 | --------------------------------------------------------------------------------