Repository: cuhk-eda/cu-gr Branch: dac2020 Commit: 9b1aa8a7db4e Files: 391 Total size: 12.9 MB Directory structure: gitextract_gkk6unka/ ├── .gitignore ├── LICENSE ├── README.md ├── drcu ├── ispd18eval/ │ ├── README │ ├── ispd18eval.sh │ ├── ispd18eval.tcl │ ├── ispd18eval.w │ └── ispd18eval_bin ├── ispd19eval/ │ ├── README │ ├── ispd19eval.sh │ ├── ispd19eval.tcl │ ├── ispd19eval.w │ └── ispd19eval_bin ├── rsyn/ │ ├── .gitrepo │ ├── LICENSE │ ├── README.md │ ├── include/ │ │ ├── def5.8/ │ │ │ ├── defiAlias.hpp │ │ │ ├── defiAssertion.hpp │ │ │ ├── defiBlockage.hpp │ │ │ ├── defiComponent.hpp │ │ │ ├── defiDebug.hpp │ │ │ ├── defiDefs.hpp │ │ │ ├── defiFPC.hpp │ │ │ ├── defiFill.hpp │ │ │ ├── defiGroup.hpp │ │ │ ├── defiIOTiming.hpp │ │ │ ├── defiKRDefs.hpp │ │ │ ├── defiMisc.hpp │ │ │ ├── defiNet.hpp │ │ │ ├── defiNonDefault.hpp │ │ │ ├── defiPartition.hpp │ │ │ ├── defiPath.hpp │ │ │ ├── defiPinCap.hpp │ │ │ ├── defiPinProp.hpp │ │ │ ├── defiProp.hpp │ │ │ ├── defiPropType.hpp │ │ │ ├── defiRegion.hpp │ │ │ ├── defiRowTrack.hpp │ │ │ ├── defiScanchain.hpp │ │ │ ├── defiSite.hpp │ │ │ ├── defiSlot.hpp │ │ │ ├── defiTimingDisable.hpp │ │ │ ├── defiUser.hpp │ │ │ ├── defiUtil.hpp │ │ │ ├── defiVia.hpp │ │ │ ├── defrCallBacks.hpp │ │ │ ├── defrData.hpp │ │ │ ├── defrReader.hpp │ │ │ ├── defrSettings.hpp │ │ │ ├── defwWriter.hpp │ │ │ ├── defwWriterCalls.hpp │ │ │ └── defzlib.hpp │ │ └── lef5.8/ │ │ ├── lefiArray.hpp │ │ ├── lefiCrossTalk.hpp │ │ ├── lefiDebug.hpp │ │ ├── lefiDefs.hpp │ │ ├── lefiEncryptInt.hpp │ │ ├── lefiKRDefs.hpp │ │ ├── lefiLayer.hpp │ │ ├── lefiMacro.hpp │ │ ├── lefiMisc.hpp │ │ ├── lefiNonDefault.hpp │ │ ├── lefiProp.hpp │ │ ├── lefiPropType.hpp │ │ ├── lefiUnits.hpp │ │ ├── lefiUser.hpp │ │ ├── lefiUtil.hpp │ │ ├── lefiVia.hpp │ │ ├── lefiViaRule.hpp │ │ ├── lefrCallBacks.hpp │ │ ├── lefrData.hpp │ │ ├── lefrReader.hpp │ │ ├── lefrSettings.hpp │ │ ├── lefwWriter.hpp │ │ ├── lefwWriterCalls.hpp │ │ └── lefzlib.hpp │ ├── lib/ │ │ └── linux/ │ │ ├── libdef.a │ │ └── liblef.a │ └── src/ │ └── rsyn/ │ ├── 3rdparty/ │ │ └── json/ │ │ └── json.hpp │ ├── core/ │ │ ├── Rsyn.h │ │ ├── RsynTypes.h │ │ ├── dscp/ │ │ │ ├── LibraryCell.h │ │ │ └── LibraryModule.h │ │ ├── infra/ │ │ │ ├── Attribute.h │ │ │ ├── Exception.h │ │ │ ├── List.h │ │ │ ├── Observer.h │ │ │ ├── RangeBasedLoop.h │ │ │ └── RawPointer.h │ │ └── obj/ │ │ ├── data/ │ │ │ ├── Arc.h │ │ │ ├── Cell.h │ │ │ ├── Design.h │ │ │ ├── Instance.h │ │ │ ├── Library.h │ │ │ ├── LibraryArc.h │ │ │ ├── LibraryCell.h │ │ │ ├── LibraryModule.h │ │ │ ├── LibraryPin.h │ │ │ ├── Module.h │ │ │ ├── Net.h │ │ │ ├── Object.h │ │ │ ├── Pin.h │ │ │ └── Port.h │ │ ├── decl/ │ │ │ ├── Arc.h │ │ │ ├── Cell.h │ │ │ ├── Design.h │ │ │ ├── Instance.h │ │ │ ├── Library.h │ │ │ ├── LibraryArc.h │ │ │ ├── LibraryCell.h │ │ │ ├── LibraryModule.h │ │ │ ├── LibraryPin.h │ │ │ ├── Module.h │ │ │ ├── Net.h │ │ │ ├── Object.h │ │ │ ├── Pin.h │ │ │ └── Port.h │ │ └── impl/ │ │ ├── Arc.h │ │ ├── Cell.h │ │ ├── Design.h │ │ ├── Instance.h │ │ ├── Library.h │ │ ├── LibraryArc.h │ │ ├── LibraryCell.h │ │ ├── LibraryModule.h │ │ ├── LibraryPin.h │ │ ├── Module.h │ │ ├── Net.h │ │ ├── Object.h │ │ ├── Pin.h │ │ └── Port.h │ ├── db/ │ │ ├── Database.cpp │ │ ├── Database.h │ │ ├── Serializable.h │ │ └── SerializationStream.h │ ├── export/ │ │ └── Rsyn/ │ │ ├── DesignObserver │ │ ├── PhysicalDesign │ │ ├── PhysicalDesignObserver │ │ ├── Point │ │ ├── Polygon │ │ ├── Rect │ │ ├── RoutingGuide │ │ ├── Scenario │ │ ├── Session │ │ └── Timer │ ├── io/ │ │ ├── legacy/ │ │ │ ├── Legacy.h │ │ │ └── PlacerInternals.h │ │ ├── parser/ │ │ │ ├── guide-ispd18/ │ │ │ │ ├── GuideDescriptor.h │ │ │ │ ├── GuideParser.cpp │ │ │ │ └── GuideParser.h │ │ │ ├── lef_def/ │ │ │ │ ├── DEFControlParser.cpp │ │ │ │ ├── DEFControlParser.h │ │ │ │ ├── LEFControlParser.cpp │ │ │ │ └── LEFControlParser.h │ │ │ ├── parser_helper.cpp │ │ │ └── parser_helper.h │ │ └── reader/ │ │ ├── ISPD2018Reader.cpp │ │ ├── ISPD2018Reader.h │ │ ├── PopulateRsyn.cpp │ │ └── PopulateRsyn.h │ ├── ispd18/ │ │ ├── Guide.h │ │ ├── RoutingGuide.cpp │ │ └── RoutingGuide.h │ ├── phy/ │ │ ├── PhysicalDesign.h │ │ ├── PhysicalRouting.cpp │ │ ├── PhysicalRouting.h │ │ ├── PhysicalService.cpp │ │ ├── PhysicalService.h │ │ ├── infra/ │ │ │ ├── PhysicalAttribute.h │ │ │ └── PhysicalObserver.h │ │ ├── obj/ │ │ │ ├── data/ │ │ │ │ ├── LayerViaManagerData.h │ │ │ │ ├── PhysicalDesign.h │ │ │ │ ├── PhysicalDieData.h │ │ │ │ ├── PhysicalGCellData.h │ │ │ │ ├── PhysicalGroupData.h │ │ │ │ ├── PhysicalInstanceData.h │ │ │ │ ├── PhysicalLayerData.h │ │ │ │ ├── PhysicalLibraryCellData.h │ │ │ │ ├── PhysicalLibraryPinData.h │ │ │ │ ├── PhysicalNetData.h │ │ │ │ ├── PhysicalObject.h │ │ │ │ ├── PhysicalObstacleData.h │ │ │ │ ├── PhysicalPinData.h │ │ │ │ ├── PhysicalPinGeometryData.h │ │ │ │ ├── PhysicalPinLayerData.h │ │ │ │ ├── PhysicalRegionData.h │ │ │ │ ├── PhysicalRoutingGridData.h │ │ │ │ ├── PhysicalRoutingPointData.h │ │ │ │ ├── PhysicalRowData.h │ │ │ │ ├── PhysicalSiteData.h │ │ │ │ ├── PhysicalSpacingData.h │ │ │ │ ├── PhysicalSpacingRuleData.h │ │ │ │ ├── PhysicalSpacingTableData.h │ │ │ │ ├── PhysicalSpecialNetData.h │ │ │ │ ├── PhysicalSpecialWireData.h │ │ │ │ ├── PhysicalTracksData.h │ │ │ │ ├── PhysicalViaData.h │ │ │ │ ├── ViaGeometryData.h │ │ │ │ └── ViaRuleData.h │ │ │ ├── decl/ │ │ │ │ ├── LayerViaManager.h │ │ │ │ ├── PhysicalCell.h │ │ │ │ ├── PhysicalDesign.h │ │ │ │ ├── PhysicalDie.h │ │ │ │ ├── PhysicalGCell.h │ │ │ │ ├── PhysicalGroup.h │ │ │ │ ├── PhysicalInstance.h │ │ │ │ ├── PhysicalLayer.h │ │ │ │ ├── PhysicalLibraryCell.h │ │ │ │ ├── PhysicalLibraryPin.h │ │ │ │ ├── PhysicalModule.h │ │ │ │ ├── PhysicalNet.h │ │ │ │ ├── PhysicalObstacle.h │ │ │ │ ├── PhysicalPin.h │ │ │ │ ├── PhysicalPinGeometry.h │ │ │ │ ├── PhysicalPinLayer.h │ │ │ │ ├── PhysicalPort.h │ │ │ │ ├── PhysicalRegion.h │ │ │ │ ├── PhysicalRoutingGrid.h │ │ │ │ ├── PhysicalRoutingPoint.h │ │ │ │ ├── PhysicalRow.h │ │ │ │ ├── PhysicalSite.h │ │ │ │ ├── PhysicalSpacing.h │ │ │ │ ├── PhysicalSpecialNet.h │ │ │ │ ├── PhysicalSpecialWire.h │ │ │ │ ├── PhysicalTracks.h │ │ │ │ ├── PhysicalVia.h │ │ │ │ ├── PhysicalViaGeometry.h │ │ │ │ ├── PhysicalViaRule.h │ │ │ │ ├── PhysicalViaRuleBase.h │ │ │ │ └── PhysicalViaRuleGenerate.h │ │ │ └── impl/ │ │ │ ├── LayerViaManager.h │ │ │ ├── PhysicalCell.h │ │ │ ├── PhysicalDesign.cpp │ │ │ ├── PhysicalDesign.h │ │ │ ├── PhysicalDie.h │ │ │ ├── PhysicalGCell.h │ │ │ ├── PhysicalGroup.h │ │ │ ├── PhysicalInstance.h │ │ │ ├── PhysicalLayer.h │ │ │ ├── PhysicalLibraryCell.h │ │ │ ├── PhysicalLibraryPin.h │ │ │ ├── PhysicalModule.h │ │ │ ├── PhysicalNet.h │ │ │ ├── PhysicalObstacle.h │ │ │ ├── PhysicalPin.h │ │ │ ├── PhysicalPinGeometry.h │ │ │ ├── PhysicalPinLayer.h │ │ │ ├── PhysicalPort.h │ │ │ ├── PhysicalRegion.h │ │ │ ├── PhysicalRoutingGrid.h │ │ │ ├── PhysicalRoutingPoint.h │ │ │ ├── PhysicalRow.h │ │ │ ├── PhysicalSite.h │ │ │ ├── PhysicalSpacing.h │ │ │ ├── PhysicalSpecialNet.h │ │ │ ├── PhysicalSpecialWire.h │ │ │ ├── PhysicalTracks.h │ │ │ ├── PhysicalVia.h │ │ │ ├── PhysicalViaGeometry.h │ │ │ ├── PhysicalViaRule.h │ │ │ ├── PhysicalViaRuleBase.h │ │ │ └── PhysicalViaRuleGenerate.h │ │ └── util/ │ │ ├── DefDescriptors.h │ │ ├── LefDescriptors.h │ │ ├── PhysicalLayerUtil.cpp │ │ ├── PhysicalTransform.cpp │ │ ├── PhysicalTransform.h │ │ ├── PhysicalTypes.h │ │ └── PhysicalUtil.h │ ├── session/ │ │ ├── Reader.h │ │ ├── Service.h │ │ ├── Session.cpp │ │ └── Session.h │ ├── setup/ │ │ ├── reader.cpp │ │ └── service.cpp │ └── util/ │ ├── Array.h │ ├── AsciiProgressBar.h │ ├── Bounds.h │ ├── Color.h │ ├── Colorize.h │ ├── Debug.h │ ├── DoubleRectangle.h │ ├── Environment.h │ ├── Exception.h │ ├── FloatRectangle.h │ ├── FloatingPoint.h │ ├── Json.h │ ├── MD5.h │ ├── MemoryUsage.h │ ├── Proxy.h │ ├── RangeBasedLoop.h │ ├── Stipple.h │ ├── Stopwatch.h │ ├── String.h │ ├── ThreadPool.h │ ├── TristateFlag.h │ ├── Units.h │ ├── dbu.h │ ├── dim.h │ ├── double2.h │ ├── float2.h │ └── geometry/ │ ├── Point.h │ ├── Polygon.cpp │ ├── Polygon.h │ ├── Rect.cpp │ └── Rect.h ├── scripts/ │ ├── build.py │ ├── gprof2dot.py │ ├── run.py │ └── run_base.py ├── src/ │ ├── .clang-format │ ├── CMakeLists.txt │ ├── db/ │ │ ├── CutLayer.cpp │ │ ├── CutLayer.h │ │ ├── Database.cpp │ │ ├── Database.h │ │ ├── GeoPrimitive.cpp │ │ ├── GeoPrimitive.h │ │ ├── LayerList.cpp │ │ ├── LayerList.h │ │ ├── MetalLayer.cpp │ │ ├── MetalLayer.h │ │ ├── Net.cpp │ │ ├── Net.h │ │ ├── RouteGrid.cpp │ │ ├── RouteGrid.h │ │ ├── RsynService.h │ │ ├── Setting.cpp │ │ ├── Setting.h │ │ ├── Stat.cpp │ │ └── Stat.h │ ├── flute/ │ │ ├── ChangeLog.txt │ │ ├── Readme │ │ ├── dist.c │ │ ├── dist.h │ │ ├── dl.c │ │ ├── dl.h │ │ ├── err.c │ │ ├── err.h │ │ ├── flute.c │ │ ├── flute.h │ │ ├── flute_mst.c │ │ ├── global.h │ │ ├── heap.c │ │ ├── heap.h │ │ ├── license.txt │ │ ├── memAlloc.c │ │ ├── memAlloc.h │ │ ├── mst2.c │ │ ├── mst2.h │ │ ├── neighbors.c │ │ └── neighbors.h │ ├── global.h │ ├── gr_db/ │ │ ├── GCell.cpp │ │ ├── GCell.h │ │ ├── GrDatabase.cpp │ │ ├── GrDatabase.h │ │ ├── GrGeoPrimitive.cpp │ │ ├── GrGeoPrimitive.h │ │ ├── GrNet.cpp │ │ ├── GrNet.h │ │ ├── GrRouteGrid.cpp │ │ ├── GrRouteGrid.h │ │ ├── GridTopo.cpp │ │ └── GridTopo.h │ ├── main.cpp │ ├── multi_net/ │ │ ├── CongestionMap.cpp │ │ ├── CongestionMap.h │ │ ├── Router.cpp │ │ ├── Router.h │ │ ├── Scheduler.cpp │ │ └── Scheduler.h │ ├── single_net/ │ │ ├── GenGuide.cpp │ │ ├── GenGuide.h │ │ ├── GridGraph.cpp │ │ ├── GridGraph.h │ │ ├── InitRoute.cpp │ │ ├── InitRoute.h │ │ ├── MazeRoute.cpp │ │ ├── MazeRoute.h │ │ ├── SingleNetRouter.cpp │ │ └── SingleNetRouter.h │ └── utils/ │ ├── enum.h │ ├── geo.h │ ├── log.cpp │ ├── log.h │ ├── prettyprint.h │ └── utils.h └── toys/ └── iccad2019c/ └── ispd18_sample/ ├── ispd18_sample.input.def └── ispd18_sample.input.lef ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .vscode build debug run*/ scripts/__pycache__ tags ================================================ FILE: LICENSE ================================================ READ THIS LICENSE AGREEMENT CAREFULLY BEFORE USING THIS PRODUCT. BY USING THIS PRODUCT YOU INDICATE YOUR ACCEPTANCE OF THE TERMS OF THE FOLLOWING AGREEMENT. THESE TERMS APPLY TO YOU AND ANY SUBSEQUENT LICENSEE OF THIS PRODUCT. License Agreement for CUGR Copyright (c) 2020 by The Chinese University of Hong Kong All rights reserved CU-SD LICENSE (adapted from the original BSD license) Redistribution of the any code, with or without modification, are permitted provided that the conditions below are met. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name nor trademark of the copyright holder or the author may be used to endorse or promote products derived from this software without specific prior written permission. Users are entirely responsible, to the exclusion of the author, for compliance with (a) regulations set by owners or administrators of employed equipment, (b) licensing terms of any other software, and (c) local, national, and international regulations regarding use, including those regarding import, export, and use of encryption software. THIS FREE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, EFFECTS OF UNAUTHORIZED OR MALICIOUS NETWORK ACCESS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: README.md ================================================ CUGR ====================================== CUGR is a VLSI global routing tool developed by the research team supervised by Prof. Evangeline F. Y. Young at The Chinese University of Hong Kong (CUHK). Different from previous global routers whose quality is usually measured by wirelength and resource overflow, CUGR is a detailed routability-driven global router and its solution quality is solely determined by the final detailed routing results. In particular, our global router adopts several efficient and effective methods to generate a set of connected rectangles to guide the detailed router: * A sophisticated probability-based cost scheme * An optimal 3D pattern routing technique that combines 2D pattern routing and layer assignment * A multi-level maze routing utilizes two levels of routing * A patching technique that adds useful route guides to further improve the detailed routability. * ... More details are in the following paper: * Jinwei Liu, Chak-Wa Pui, Fangzhou Wang, Evangeline F. Y. Young, ["CUGR: Detailed-Routability-Driven 3D Global Routing with Probabilistic Resource Model"](https://ieeexplore.ieee.org/document/9218646), ACM/IEEE Design Automation Conference (DAC), San Francisco, CA, USA, July 19-23, 2020. (CUGR supports ICCAD'19 benchmarks ([v2](http://iccad-contest.org/2019/Problem_C/iccad19_benchmarks_v2.tar.gz), [hidden](http://iccad-contest.org/2019/Problem_C/iccad19_hidden_benchmarks.tar.gz)). This version of code is consistent with the DAC paper.) ## 1. How to Build **Step 1:** Download the source code. For example, ```bash $ git clone https://github.com/cuhk-eda/cu-gr ``` **Step 2:** Go to the project root and build by ```bash $ cd cu-gr $ scripts/build.py -o release ``` Note that this will generate two folders under the root, `build` and `run` (`build` contains intermediate files for build/compilation, while `run` contains binaries and auxiliary files). More details are in [`scripts/build.py`](scripts/build.py). ### 1.1. Dependencies * [GCC](https://gcc.gnu.org/) (version >= 5.5.0) or other working c++ compliers * [CMake](https://cmake.org/) (version >= 2.8) * [Boost](https://www.boost.org/) (version >= 1.58) * [Python](https://www.python.org/) (version 3, optional, for utility scripts) * [Innovus®](https://www.cadence.com/content/cadence-www/global/en_US/home/tools/digital-design-and-signoff/soc-implementation-and-floorplanning/innovus-implementation-system.html) (version 18.1, optional, for design rule checking and evaluation) * [Rsyn](https://github.com/RsynTeam/rsyn-x) (a trimmed version is used, already added under folder `rsyn`) * [Dr. CU](https://github.com/cuhk-eda/dr-cu) (v4.1.1, optional, official detailed router for ICCAD'19 Contest, [binary](http://iccad-contest.org/2019/Problem_C/drcu_june19.zip) is already included under the root) ## 2. How to Run ### 2.1. Toy Test #### Run Binary Directly Go to the `run` directory and run the binary `iccad19gr` with a toy case `ispd18_sample`: ```bash $ cd run $ ./iccad19gr -lef ../toys/iccad2019c/ispd18_sample/ispd18_sample.input.lef -def ../toys/iccad2019c/ispd18_sample/ispd18_sample.input.def -output ispd18_sample.solution.guide -threads 8 ``` #### Run with a Wrapping Script Instead of running the binary directly, you may also use a wrapping script `run.py` to save typing and do more: ```bash $ cd run $ ./run.py 8s -p ../toys/ ``` If Innovus® has been properly installed in your OS, an evaluation can be launched by ```bash $ ./run.py 8s -s eval -p ../toys/ ``` In the end, a result table will be printed in the terminal. Furthermore, the solution can be visualized by ```bash $ ./run.py 8s -s view -p ../toys/ ``` which gives: ![ispd18_sample.solution.png](/toys/iccad2019c/ispd18_sample/ispd18_sample.solution.png) The three steps, `route`, `eval` and `view` of `run.py` can also be invoked in a single line: ```bash $ ./run.py 8s -s route eval view -p ../toys/ ``` More usage about `run.py` can be known by the option `-h`. ### 2.2. Batch Test The benchmarks can be downloaded from [the hompage of ISPD'18 Contest ](http://www.ispd.cc/contests/18/#benchmarks). You may let `run.py` know the benchmark path by setting OS environmental variable `BENCHMARK_PATH` or specifying it under option `-p`. Then, ```bash $ cd run $ ./run.py -s route eval [option...] ``` ## 3. Modules * `ispd18eval`: scripts and other files for evaluation, provided by [ICCAD'19 Contest](http://iccad-contest.org/2019/Problem_C/eval.zip) * `ispd19eval`: scripts and other files for evaluation, provided by [ICCAD'19 Contest](http://iccad-contest.org/2019/Problem_C/eval.zip) * `rsyn`: code from [Rsyn](https://github.com/RsynTeam/rsyn-x) for file IO * `scripts`: utility python scripts * `src`: C++ source code * `db`: database, including the global grid graph and the net information * `single_net`: routing a single net, including querying the global grid graph, building the local grid graph, running maze routing, and some post processing * `multi_net`: routing all nets with "rip-up and rereoute" and multithreading * `utils`: some utility code * `toys`: toy test cases * `drcu`: default detailed router for evaluation ## 4. Results Experiments are performed on a 64-bit Linux workstation with Intel Xeon Silver 4114 CPU (2.20GHz, 40 cores) and 256GB memory. Consistent with the contest, eight threads are used. | Design | Wire Length & Via | Non-Preferred Usage | Short | Min-Area & Spacing | DR Score | GR Runtime (sec) | |:---------:|:------------------:|:--------------------:|:--------:|:-------------------:|:--------:|:---------------:| | `ispd2018_test5` | 15613663 | 166994 | 330425 | 288500 | 16089196 | 68 | | `ispd2018_test5_metal5` | 15807997 | 135293 | 261150 | 224000 | 16210303 | 85 | | `ispd2018_test8` | 37441058 | 269993 | 209470 | 144000 | 37908815 | 236 | | `ispd2018_test8_metal5` | 36746610 | 336768 | 194510 | 129500 | 37293962 | 300 | | `ispd2018_test10` | 39061258 | 882371 | 669965 | 471000 | 40600501 | 334 | | `ispd2018_test10_metal5` | 40246090 | 1413120 | 4021620 | 685500 | 46300610 | 373 | | `ispd2019_test7` | 77286072 | 1428396 | 9680620 | 6883000 | 88577731 | 506 | | `ispd2019_test7_metal5` | 70848996 | 1535876 | 9943260 | 6686000 | 82169293 | 377 | | `ispd2019_test8` | 119199593 | 1338449 | 7780220 | 6103000 | 128412302 | 365 | | `ispd2019_test8_metal5` | 116062781 | 1493314 | 8561400 | 6089000 | 126429212 | 588 | | `ispd2019_test9` | 184246497 | 2181774 | 14765850 | 10847000 | 201270655 | 528 | | `ispd2019_test9_metal5` | 179242111 | 2323850 | 16020280 | 10948000 | 197937335 | 658 | ## 5. License READ THIS LICENSE AGREEMENT CAREFULLY BEFORE USING THIS PRODUCT. BY USING THIS PRODUCT YOU INDICATE YOUR ACCEPTANCE OF THE TERMS OF THE FOLLOWING AGREEMENT. THESE TERMS APPLY TO YOU AND ANY SUBSEQUENT LICENSEE OF THIS PRODUCT. License Agreement for CUGR Copyright (c) 2020 by The Chinese University of Hong Kong All rights reserved CU-SD LICENSE (adapted from the original BSD license) Redistribution of the any code, with or without modification, are permitted provided that the conditions below are met. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name nor trademark of the copyright holder or the author may be used to endorse or promote products derived from this software without specific prior written permission. Users are entirely responsible, to the exclusion of the author, for compliance with (a) regulations set by owners or administrators of employed equipment, (b) licensing terms of any other software, and (c) local, national, and international regulations regarding use, including those regarding import, export, and use of encryption software. THIS FREE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, EFFECTS OF UNAUTHORIZED OR MALICIOUS NETWORK ACCESS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: ispd18eval/README ================================================ Prerequisite ------------ Please make sure you have Innovus installed and the path to Innovus is added to your $PATH environment variable. To add a path to $PATH variable, add the following statement to your shell config file: Assuming the path to Innovus is /path/to/innovus/bin For bash/ksh, add the following line to .bashrc/.kshrc export PATH=/path/to/innovus/bin:$PATH For csh/tcsh, add the following line to .cshrc setenv PATH /path/to/innovus/bin:$PATH Usage ----- ./ispd18eval.sh -lef -guide -def Example ------- ./ispd18eval.sh -lef sample/ispd18_sample.input.lef -guide sample/ispd18_sample.input.guide -def sample/ispd18_sample.output.def Required files -------------- in benchmark directory (use benchmark "sample" as example): ispd18_sample.input.lef - input LEF file ispd18_sample.input.guide - input route guide file ispd18_sample.output.def - output DEF file with routing solution in evaluation directory: ispd18eval.sh - evaluation script ispd18eval - evaluation binary for score calculation ispd18eval.w - weights for score calculation ispd18eval.tcl - script for Innovus Output files ------------ in the current directory (use benchmark "sample" as example): score.rpt Notes ----- Please make sure: 1. You have write permission to the current directory. 2. You are able to start Innovus by just using "innovus" command on your terminal. Otherwise, you have to add the Innovus bin directory to your PATH variable. Contacts -------- ispd2018contest@gmail.com ================================================ FILE: ispd18eval/ispd18eval.sh ================================================ #!/bin/sh if [ $# -eq 0 ] ; then echo "$0 -lef -guide -def " echo "example:" echo "$0 -lef sample/ispd18_sample.input.lef -guide sample/ispd18_sample.input.guide -def sample/ispd18_sample.output.def" exit fi INVS="innovus" EVAL="./ispd18eval_bin" command -v $INVS || { echo "$INVS is not available." exit 1 } keepLogs=0 #read arguments while [ $# -gt 0 ] ; do case $1 in -lef) shift ; inputLef=$1 ;; -guide) shift ; inputRg=$1 ;; -def) shift ; outputDef=$1 ;; -keep) shift ; keepLogs=1 ;; *) echo "unknown : $1" ;; esac shift done evalGeoRpt='eval.geo.rpt' evalConRpt='eval.con.rpt' evalScoreRpt='eval.score.rpt' evalTcl='eval.tcl' if [ ! -f $inputLef ] ; then echo "ERROR: $inputLef not found" exit elif [ ! -f $inputRg ] ; then echo "ERROR: $inputRg not found" exit elif [ ! -f $outputDef ] ; then echo "ERROR: $outputDef not found" exit fi if [ -f $evalTcl ] ; then echo "WARNING: tcl file exists, overwriting..." fi echo "#evaluation script for ISPD 2018 contest" > $evalTcl echo 'source ispd18eval.tcl' >> $evalTcl echo "evaluate $inputLef $outputDef $evalGeoRpt $evalConRpt" >> $evalTcl echo 'exit' >>$evalTcl if [ "$keepLogs" = 0 ] ; then rm -f $evalGeoRpt rm -f $evalConRpt fi cmd="$INVS -init $evalTcl -log eval.log -overwrite -nowin" echo $cmd $cmd if [ "$keepLogs" = 0 ] ; then rm $evalTcl rm 'eval.log' rm 'eval.logv' rm 'eval.cmd' rm `basename "$outputDef.v"` fi cmd="$EVAL -lef $inputLef -def $outputDef -guide $inputRg -georpt $evalGeoRpt -conrpt $evalConRpt" echo $cmd $cmd | tee $evalScoreRpt ================================================ FILE: ispd18eval/ispd18eval.tcl ================================================ proc evaluate { inputLef outputDef evalGeoRpt evalConRpt } { setMultiCpuUsage -localCpu 8 loadDesign $inputLef $outputDef setVerifyGeometryMode -area { 0 0 0 0 } setVerifyGeometryMode -minWidth false setVerifyGeometryMode -minSpacing true setVerifyGeometryMode -minArea true setVerifyGeometryMode -sameNet true setVerifyGeometryMode -short true setVerifyGeometryMode -overlap false setVerifyGeometryMode -offRGrid false setVerifyGeometryMode -offMGrid false setVerifyGeometryMode -mergedMGridCheck false setVerifyGeometryMode -minHole false setVerifyGeometryMode -implantCheck false setVerifyGeometryMode -minimumCut false setVerifyGeometryMode -minStep false setVerifyGeometryMode -viaEnclosure false setVerifyGeometryMode -antenna false setVerifyGeometryMode -insuffMetalOverlap false setVerifyGeometryMode -pinInBlkg false setVerifyGeometryMode -diffCellViol false setVerifyGeometryMode -sameCellViol false setVerifyGeometryMode -padFillerCellsOverlap false setVerifyGeometryMode -routingBlkgPinOverlap false setVerifyGeometryMode -routingCellBlkgOverlap false setVerifyGeometryMode -regRoutingOnly false setVerifyGeometryMode -stackedViasOnRegNet false setVerifyGeometryMode -wireExt false setVerifyGeometryMode -useNonDefaultSpacing false setVerifyGeometryMode -maxWidth false setVerifyGeometryMode -maxNonPrefLength -1 setVerifyGeometryMode -error 10000000 catch { verifyGeometry -report $evalGeoRpt } catch { verifyConnectivity -noFloatingMetal -error 10000000 -report $evalConRpt } #catch { verifyConnectivity -type all -noAntenna -noUnConnPin -geomConnect -noSoftPGConnect -noFloatingMetal -error 10000000 -report $evalConRpt } exit } proc loadDesign { lef def } { catch { loadLefFile $lef } catch { loadDefFile $def } } ================================================ FILE: ispd18eval/ispd18eval.w ================================================ Wire 0.5 Via 2.0 OutOfGuideWire 1.0 OutOfGuideVia 1.0 OffTrackWire 0.5 OffTrackVia 1.0 WrongWayWire 1.0 Short 500.0 Area 500.0 Spacing 500.0 Open 0.0 ================================================ FILE: ispd19eval/README ================================================ Prerequisite ------------ Please make sure you have Innovus installed and the path to Innovus is added to your $PATH environment variable. To add a path to $PATH variable, add the following statement to your shell config file: Assuming the path to Innovus is /path/to/innovus/bin For bash/ksh, add the following line to .bashrc/.kshrc export PATH=/path/to/innovus/bin:$PATH For csh/tcsh, add the following line to .cshrc setenv PATH /path/to/innovus/bin:$PATH Usage ----- ./ispd19eval.sh -lef -guide -idef -odef Example ------- ./ispd19eval.sh -lef sample/ispd19_sample.input.lef -guide sample/ispd19_sample.input.guide -idef sample/ispd19_sample.input.def -odef sample/ispd19_sample.output.def Required files -------------- in benchmark directory (use benchmark "sample" as example): ispd19_sample.input.lef - input LEF file ispd19_sample.input.def - input DEF file ispd19_sample.input.guide - input route guide file ispd19_sample.output.def - output DEF file with routing solution in evaluation directory: ispd19eval.sh - evaluation script ispd19eval - evaluation binary for score calculation ispd19eval.w - weights for score calculation ispd19eval.tcl - script for Innovus Output files ------------ in the current directory (use benchmark "sample" as example): score.rpt Notes ----- Please make sure: 1. You have write permission to the current directory. 2. You are able to start Innovus by just using "innovus" command on your terminal. Otherwise, you have to add the Innovus bin directory to your PATH variable. Contacts -------- ispd2019contest@gmail.com ================================================ FILE: ispd19eval/ispd19eval.sh ================================================ #!/bin/sh if [ $# -eq 0 ] ; then echo "$0 -lef -guide -idef -odef " echo "example:" echo "$0 -lef sample/ispd19_sample.input.lef -guide sample/ispd19_sample.input.guide -idef sample/ispd19_sample.input.def -odef sample/ispd19_sample.output.def" exit fi INVS="innovus" EVAL="./ispd19eval_bin" command -v $INVS || { echo "$INVS is not available." exit 1 } method='a' keepLogs=0 prefix= trimmedDef='eval.def' combinedDef='comb.def' #read arguments while [ $# -gt 0 ] ; do case $1 in -lef) shift ; inputLef=$1 ;; -guide) shift ; inputRg=$1 ;; -idef) shift ; inputDef=$1 ;; -odef) shift ; outputDef=$1 ;; -tdef) shift ; trimmedDef=$1 ;; -cdef) shift ; combinedDef=$1 ;; -prefix) shift ; prefix=$1 ;; -method) shift ; method=$1 ;; -keep) keepLogs=1 ;; *) echo "unknown : $1" ;; esac shift done evalGeoRpt="${prefix}eval.geo.rpt" evalConRpt="${prefix}eval.con.rpt" evalScoreRpt="${prefix}eval.score.rpt" evalTcl="${prefix}eval.tcl" invsLog="${prefix}eval" if [ ! -f $inputLef ] ; then echo "ERROR: $inputLef not found" exit elif [ ! -f $inputRg ] ; then echo "ERROR: $inputRg not found" exit elif [ ! -f $inputDef ] ; then echo "ERROR: $inputDef not found" exit elif [ ! -f $outputDef ] ; then echo "ERROR: $outputDef not found" exit fi if [ -f $evalTcl ] ; then echo "WARNING: tcl file exists, overwriting..." fi if [ "$method" = 'a' ] ; then dbuMicron=`grep "UNITS DISTANCE MICRONS" $inputDef | cut -d' ' -f 4` echo 'VERSION 5.8 ;' > $trimmedDef echo 'DIVIDERCHAR "/" ;' >> $trimmedDef echo 'BUSBITCHARS "[]" ;' >> $trimmedDef echo "UNITS DISTANCE MICRONS $dbuMicron ;" >> $trimmedDef sed -n '/^[[:blank:]]*NETS[[:blank:]]*[1-9][0-9]*[[:blank:]]*;[[:blank:]]*$/,/^[[:blank:]]*END NETS[[:blank:]]*$/p' $outputDef >> $trimmedDef elif [ "$method" = 'b' ] ; then sed -n '/^[[:blank:]]*VERSION[[:blank:]]*[0-9]\.[0-9][[:blank:]]*;[[:blank:]]*$/,/^END SPECIALNETS[[:blank:]]*$/p' $inputDef > $combinedDef sed -n '/^[[:blank:]]*NETS[[:blank:]]*[1-9][0-9]*[[:blank:]]*;[[:blank:]]*$/,/^[[:blank:]]*END NETS[[:blank:]]*$/p' $outputDef >> $combinedDef echo "END DESIGN" >> $combinedDef else echo "ERROR: unknown evaluation method $method" exit fi echo "#evaluation script for ISPD 2019 contest" > $evalTcl echo 'source ispd19eval.tcl' >> $evalTcl if [ "$method" = 'a' ] ; then echo "evaluate $inputLef $inputDef $trimmedDef $evalGeoRpt $evalConRpt" >> $evalTcl else echo "evaluate $inputLef $combinedDef {} $evalGeoRpt $evalConRpt" >> $evalTcl fi echo 'exit' >>$evalTcl if [ "$keepLogs" = 0 ] ; then rm -f $evalGeoRpt rm -f $evalConRpt fi cmd="$INVS -init $evalTcl -log $invsLog.log -overwrite -nowin" echo $cmd $cmd if [ "$keepLogs" = 0 ] ; then rm -f $evalTcl rm -f "$invsLog.log" rm -f "$invsLog.logv" rm -f "$invsLog.cmd" rm -f `basename "$outputDef.v"` fi cmd="$EVAL -lef $inputLef -def $outputDef -guide $inputRg -georpt $evalGeoRpt -conrpt $evalConRpt" echo $cmd $cmd | tee $evalScoreRpt ================================================ FILE: ispd19eval/ispd19eval.tcl ================================================ setMultiCpuUsage -localCpu 8 proc evaluate { inputLef inputDef outputDef evalGeoRpt evalConRpt } { loadDesign $inputLef $inputDef $outputDef set_verify_drc_mode -disable_rules {} set_verify_drc_mode -check_implant true set_verify_drc_mode -check_implant_across_rows false set_verify_drc_mode -check_ndr_spacing false set_verify_drc_mode -check_only default set_verify_drc_mode -check_same_via_cell false set_verify_drc_mode -exclude_pg_net false set_verify_drc_mode -ignore_trial_route false set_verify_drc_mode -report $evalGeoRpt set_verify_drc_mode -limit 10000000 catch { verify_drc } # catch { verifyConnectivity -noFloatingMetal -error 10000000 -report $evalConRpt } catch { verifyConnectivity -type all -noAntenna -noUnConnPin -geomConnect -noSoftPGConnect -noFloatingMetal -error 10000000 -report $evalConRpt } exit } proc loadDesign { lef idef odef } { catch { loadLefFile $lef } catch { loadDefFile $idef } if { $odef != "" } { catch { defIn $odef } } } ================================================ FILE: ispd19eval/ispd19eval.w ================================================ Wire 0.5 SingleCutVia 4.0 MultiCutVia 2.0 OutOfGuideWire 1.0 OutOfGuideVia 1.0 OffTrackWire 0.5 OffTrackVia 1.0 WrongWayWire 1.0 Short 500.0 ShortArea 500.0 ParallelRun 500.0 EndOfLine 500.0 CutSpacing 500.0 AdjCutSpacing 500.0 CornerSpacing 500.0 MinArea 500.0 Open 0.0 ================================================ FILE: ispd19eval/ispd19eval_bin ================================================ [File too large to display: 10.4 MB] ================================================ FILE: rsyn/.gitrepo ================================================ ; DO NOT EDIT (unless you know what you are doing) ; ; This subdirectory is a git "subrepo", and this file is maintained by the ; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme ; [subrepo] remote = https://github.com/rsyn/rsyn.git branch = master commit = 99dc1241ef523c416be2617c7c7bdd3eec15413f parent = 09d1bb30dc611121087a3ce33968e806944d33bb cmdver = 0.3.1 ================================================ FILE: rsyn/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS ================================================ FILE: rsyn/README.md ================================================ #### This is a subrepository. Please go to the [rsyn-x](https://github.com/rsyn/rsyn-x) for the main repository. ================================================ FILE: rsyn/include/def5.8/defiAlias.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013 - 2014, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiALIAS_h #define defiALIAS_h #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defAliasIterator; class defrData; class defiAlias_itr { public: defiAlias_itr(defrData *defData = 0); void Init(); void Destroy(); ~defiAlias_itr(); int Next(); const char* Key(); const char* Data(); int Marked(); protected: defAliasIterator *iterator; int first; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiAssertion.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiAssertion_h #define defiAssertion_h #include "defiKRDefs.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE // Struct holds the data for one assertion/constraint. // An assertion or constraint is either a net/path rule or a // wired logic rule. // // A net/path rule is an item or list of items plus specifications. // The specifications are: rise/fall min/max. // The items are a list of (one or more) net names or paths or a // combination of both. // // A wired logic rule is a netname and a distance. // // We will NOT allow the mixing of wired logic rules and net/path delays // in the same assertion/constraint. // // We will allow the rule to be a sum of sums (which will be interpreted // as just one list). // class defrData; class defiAssertion { public: defiAssertion(defrData *data); void Init(); void Destroy(); ~defiAssertion(); void setConstraintMode(); void setAssertionMode(); void setSum(); void setDiff(); void setNetName(const char* name); void setRiseMin(double num); void setRiseMax(double num); void setFallMin(double num); void setFallMax(double num); void setDelay(); void setWiredlogicMode(); void setWiredlogic(const char* net, double dist); void addNet(const char* name); void addPath(const char* fromInst, const char* fromPin, const char* toInst, const char* toPin); void bumpItems(); void unsetSum(); int isAssertion() const; // Either isAssertion or isConstraint is true int isConstraint() const; int isWiredlogic() const; // Either isWiredlogic or isDelay is true int isDelay() const; int isSum() const; int isDiff() const; int hasRiseMin() const; int hasRiseMax() const; int hasFallMin() const; int hasFallMax() const; double riseMin() const; double riseMax() const; double fallMin() const; double fallMax() const; const char* netName() const; // Wired logic net name double distance() const; // Wired logic distance int numItems() const; // number of paths or nets int isPath(int index) const; // is item #index a path? int isNet(int index) const; // is item #index a net? void path(int index, char** fromInst, char** fromPin, char** toInst, char** toPin) const; // Get path data for item #index void net(int index, char** netName) const; // Get net data for item #index void clear(); void print(FILE* f) const; protected: char isAssertion_; char isSum_; char isDiff_; char hasRiseMin_; char hasRiseMax_; char hasFallMin_; char hasFallMax_; char isWiredlogic_; char isDelay_; char* netName_; // wired logic net name int netNameLength_; double riseMin_; double riseMax_; double fallMin_; double fallMax_; // also used to store the wired logic dist int numItems_; int numItemsAllocated_; char* itemTypes_; int** items_; // not really integers. defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiBlockage.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiBLOCKAGES_h #define defiBLOCKAGES_h #include #include "defiKRDefs.hpp" #include "defiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; class defiBlockage { public: defiBlockage(defrData *data); void Init(); void Destroy(); ~defiBlockage(); void clear(); void clearPoly(); void setLayer(const char* name); void setPlacement(); void setComponent(const char* name); void setSlots(); void setFills(); void setPushdown(); void setExceptpgnet(); // 5.7 void setSoft(); // 5.7 void setPartial(double maxDensity); // 5.7 void setSpacing(int minSpacing); void setDesignRuleWidth(int width); void setMask(int maskColor); // 5.8 void addRect(int xl, int yl, int xh, int yh); void addPolygon(defiGeometries* geom); int hasLayer() const; int hasPlacement() const; int hasComponent() const; int hasSlots() const; int hasFills() const; int hasPushdown() const; int hasExceptpgnet() const; // 5.7 int hasSoft() const; // 5.7 int hasPartial() const; // 5.7 int hasSpacing() const; // 5.6 int hasDesignRuleWidth() const; // 5.6 int hasMask() const; // 5.8 int mask() const; // 5.8 int minSpacing() const; // 5.6 int designRuleWidth() const; // 5.6 double placementMaxDensity() const; // 5.7 const char* layerName() const; const char* layerComponentName() const; const char* placementComponentName() const; int numRectangles() const; int xl(int index) const; int yl(int index) const; int xh(int index) const; int yh(int index) const; int numPolygons() const; // 5.6 struct defiPoints getPolygon(int index) const; // 5.6 void print(FILE* f) const; protected: int hasLayer_; char* layerName_; int layerNameLength_; int hasPlacement_; int hasComponent_; char* componentName_; int componentNameLength_; int hasSlots_; int hasFills_; int hasPushdown_; // 5.7 int hasExceptpgnet_ ; // 5.7 int hasSoft_; // 5.7 double maxDensity_; // 5.7 int minSpacing_; int width_; int numRectangles_; int rectsAllocated_; int mask_; // 5.8 int* xl_; int* yl_; int* xh_; int* yh_; int numPolys_; // 5.6 int polysAllocated_; // 5.6 struct defiPoints** polygons_; // 5.6 defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiComponent.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiComponent_h #define defiComponent_h #include #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; // Placement status for the component. // Default is 0 #define DEFI_COMPONENT_UNPLACED 1 #define DEFI_COMPONENT_PLACED 2 #define DEFI_COMPONENT_FIXED 3 #define DEFI_COMPONENT_COVER 4 // Struct holds the data for componentMaskShiftLayers. class defiComponentMaskShiftLayer { public: defiComponentMaskShiftLayer(defrData *data); ~defiComponentMaskShiftLayer(); void Init(); void Destroy(); void addMaskShiftLayer(const char* layer); int numMaskShiftLayers() const; void bumpLayers(int size); void clear(); const char* maskShiftLayer(int index) const; protected: int layersAllocated_; // allocated size of layers_ int numLayers_; // number of places used in layers_ char** layers_; defrData *defData; }; // Struct holds the data for one component. class defiComponent { public: defiComponent(defrData *defData); void Init(); void Destroy(); ~defiComponent(); void IdAndName(const char* id, const char* name); void setGenerate(const char* genName, const char* macroName); void setPlacementStatus(int n); void setPlacementLocation(int x, int y, int orient); void setRegionName(const char* name); void setRegionBounds(int xl, int yl, int xh, int yh); void setEEQ(const char* name); void addNet(const char* netName); void addProperty(const char* name, const char* value, const char type); void addNumProperty(const char* name, const double d, const char* value, const char type); void reverseNetOrder(); void setWeight(int w); void setMaskShift(const char* color); void setSource(const char* name); void setForeignName(const char* name); void setFori(const char* name); void setForeignLocation(int x, int y, int orient); void setHalo(int left, int bottom, int right, int top); // 5.6 void setHaloSoft(); // 5.7 void setRouteHalo(int haloDist, const char* minLayer, const char* maxLayer); // 5.7 void clear(); // For OA to modify the Id & Name void changeIdAndName(const char* id, const char* name); const char* id() const; const char* name() const; int placementStatus() const; int isUnplaced() const; int isPlaced() const; int isFixed() const; int isCover() const; int placementX() const; int placementY() const; int placementOrient() const; const char* placementOrientStr() const; int hasRegionName() const; int hasRegionBounds() const; int hasEEQ() const; int hasGenerate() const; int hasSource() const; int hasWeight() const; int weight() const; int maskShiftSize() const; int maskShift(int index) const; int hasNets() const; int numNets() const; const char* net(int index) const; const char* regionName() const; const char* source() const; const char* EEQ() const; const char* generateName() const; const char* macroName() const; int hasHalo() const; // 5.6 int hasHaloSoft() const; // 5.7 void haloEdges(int* left, int* bottom, int* right, int* top); // 5.6 int hasRouteHalo() const; // 5.7 int haloDist() const; // 5.7 const char* minLayer() const; // 5.7 const char* maxLayer() const; // 5.7 // Returns arrays for the ll and ur of the rectangles in the region. // The number of items in the arrays is given in size. void regionBounds(int*size, int** xl, int** yl, int** xh, int** yh) const; int hasForeignName() const; const char* foreignName() const; int foreignX() const; int foreignY() const; const char* foreignOri() const; // return the string value of the orient int foreignOrient() const; // return the enum value of the orient int hasFori() const; int numProps() const; char* propName(int index) const; char* propValue(int index) const; double propNumber(int index) const; char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; // Debug printing void print(FILE* fout) const; void bumpId(int size); void bumpName(int size); void bumpRegionName(int size); void bumpEEQ(int size); void bumpNets(int size); void bumpForeignName(int size); void bumpMinLayer(int size); void bumpMaxLayer(int size); void bumpFori(int size); protected: char* id_; // instance id char* name_; // name. int nameSize_; // allocated size of name. int idSize_; // allocated size of id. int ForiSize_; // allocate size of foreign ori int status_; // placement status char hasRegionName_; // the file supplied a region name for this comp char hasEEQ_; // the file supplied an eeq char hasGenerate_; // the file supplied an generate name and macro name char hasWeight_; // the file supplied a weight char hasFori_; // the file supplied a foreign orig name int orient_; // orientation int x_, y_; // placement loc int numRects_; int rectsAllocated_; int* rectXl_; // region points int* rectYl_; int* rectXh_; int* rectYh_; char* regionName_; // name. int regionNameSize_; // allocated size of region name char* EEQ_; int EEQSize_; // allocated size of eeq int numNets_; // number of net connections int netsAllocated_; // allocated size of nets array char** nets_; // net connections int weight_; int* maskShift_; int maskShiftSize_; char* source_; char hasForeignName_; // the file supplied a foreign name char* foreignName_; // name int foreignNameSize_; // allocate size of foreign name int Fx_, Fy_; // foreign loc int Fori_; // foreign ori int generateNameSize_; char* generateName_; int macroNameSize_; char* macroName_; int hasHalo_; int hasHaloSoft_; // 5.7 int leftHalo_; int bottomHalo_; int rightHalo_; int topHalo_; int haloDist_; // 5.7 int minLayerSize_; // 5.7 char* minLayer_; // 5.7 int maxLayerSize_; // 5.7 char* maxLayer_; // 5.7 int numProps_; int propsAllocated_; char** names_; char** values_; double* dvalues_; char* types_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiDebug.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiDebug_h #define defiDebug_h #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; /* Set flag */ extern void defiSetDebug (int num, int value) ; /* Read flag */ extern int defiDebug (int num) ; /* Error loggin function */ extern void defiError(int check, int msgNum, const char* message, defrData *defData = NULL); /* for auto upshifting names in case insensitive files */ extern const char* upperCase(const char* c, defrData *defData = NULL); extern const char* DEFCASE(const char* ch, defrData *defData = NULL); END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiDefs.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** /* Definitions header file for the DEF Interface */ #ifndef DEFI_DEFS_H #define DEFI_DEFS_H #include #include #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE /*=================== General Types and Definitions =================*/ #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #ifndef NULL #define NULL (0) #endif typedef struct defpoint defPOINT; struct defpoint { int x; int y; }; typedef struct defrect defRECT; struct defrect { defPOINT ll,ur; }; typedef struct deftoken defTOKEN; struct deftoken { defTOKEN *next; int what; int data; defPOINT pt; }; #define START_LIST 10001 #define POINT_SPEC 10002 #define VIA_SPEC 10003 #define WIDTH_SPEC 10004 #define LAYER_SPEC 10005 #define SHAPE_SPEC 10006 #ifndef MIN #define MIN(x,y) ((x) < (y)? (x) : (y)) #endif #ifndef MIN #define MAX(x,y) ((x) > (y)? (x) : (y)) #endif #define ROUND(x) ((x) >= 0 ? (int)((x)+0.5) : (int)((x)-0.5)) //defTOKEN *TokenFromRect(); /*=================== Enumerated Types ============================*/ typedef int defiBoolean; /* Every type of object has a unique identifier, and each object * which is created knows its type, by storing the defiObjectType_e * as the first member in the structure. * */ typedef enum { /* decrease likelihood of accidentally correct values by starting at an unusual number */ defiInvalidObject = 41713, defiUnknownObject /* void * */ } defiObjectType_e; /* The memory policy controls how an object which refers to or is composed of * other objects manages those sub-objects, particularly when the parent * object is copied or deleted. The policy is specified as an argument to the * constructor or initializer, and it is stored with the parent object. * * The memory policy is a generalization of the common distinction between * deep and shallow copies. When a shallow copy of a parent object is made, * the copy maintains pointers to the original sub-objects, and the original * parent remains responsible for deleting those sub-objects. When a deep * copy of a parent object is made, the copy maintains pointers to new copies * of each of the sub-objects, and the copy is responsible for deleting the * new sub-objects. * * The defiPrivateSubObjects policy corresponds to a deep copy, while the the * defiReferencedSubObjects policy corresponds to a shallow copy. Usually an * initial parent object will be created using defiPrivateSubObjects. When a * copy is made of that parent object, the copy may either maintain its own * private versions of each sub-object, or it may refer to the original * sub-objects. * * In certain cases, it is useful to create a deep copy of a parent object, * even though the new parent object shouldn't be responsible for the new * sub-objects. In this case, the defiOrphanSubObjects and * defiAdoptedSubObjects policies may be used. defiOrphanSubObjects is * specified while creating the deep copy, and then defiAdoptedSubObjects is * specified while creating another parent which will take on the * responsibility for the orphans. * * An object's memory policy affects only the sub-objects which it directly * controls. Those sub-objects themselves may have the same memory policy as * their parents, or they may have a different memory policy. When a copy is * made of a child sub-object, the memory policy of the child controls * whether deep or shallow copies are made of the grandchildren. */ typedef enum { /* decrease likelihood of accidentally correct values by starting at an unusual number */ defiInvalidMemoryPolicy = 23950, defiPrivateSubObjects, // deep copy + delete defiReferencedSubObjects, // shallow copy, no delete defiOrphanSubObjects, // deep copy, no delete defiAdoptedSubObjects // shallow copy + delete } defiMemoryPolicy_e; /* An opaque pointer for passing user data through from one API * function to another. * A handle which a user can set to point to their own data * on a per-callback basis. (See the comment in defwWriter.h) */ #define defiUserData void * #define defiUserDataHandle void ** /* On SunOs 4.1.3 with acc, this is in libansi.a, but isn't properly * declared anywhere in the header files supplied with the compiler. */ #ifdef __SunOS_4_1_3 extern int strcasecmp(const char*, const char*); #endif #ifdef WIN32 #define strdup _strdup #endif END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiFPC.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiFPC_h #define defiFPC_h #include #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; class defiFPC { public: defiFPC(defrData *data); void Init(); void Destroy(); ~defiFPC(); void clear(); void setName(const char* name, const char* direction); void setAlign(); void setMax(double num); void setMin(double num); void setEqual(double num); void setDoingBottomLeft(); void setDoingTopRight(); void addRow(const char* name); void addComps(const char* name); void addItem(char typ, const char* name); const char* name() const; int isVertical() const; int isHorizontal() const; int hasAlign() const; int hasMax() const; int hasMin() const; int hasEqual() const; double alignMax() const; double alignMin() const; double equal() const; int numParts() const; // Return the constraint number "index" where index is // from 0 to numParts() // The returned corner is 'B' for bottom left 'T' for topright // The returned typ is 'R' for rows 'C' for comps // The returned char* points to name of the item. void getPart(int index, int* corner, int* typ, char** name) const; // debug print void print(FILE* f) const; protected: char* name_; int nameLength_; char direction_; // H or V char hasAlign_; char hasMin_; char hasMax_; char hasEqual_; char corner_; // Bottomleft or Topright double minMaxEqual_; int namesAllocated_; // allocated size of names_ and rowOrComp_ int namesUsed_; // number of entries used in the arrays char* rowOrComp_; char** names_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiFill.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiFILL_h #define defiFILL_h #include #include "defiKRDefs.hpp" #include "defiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; class defiFill { public: defiFill(defrData *data); void Init(); void Destroy(); ~defiFill(); void clear(); void clearPoly(); void clearPts(); void setLayer(const char* name); void setLayerOpc(); // 5.7 void addRect(int xl, int yl, int xh, int yh); void addPolygon(defiGeometries* geom); void setVia(const char* name); // 5.7 void setViaOpc(); // 5.7 void addPts(defiGeometries* geom); // 5.7 int hasLayer() const; const char* layerName() const; int hasLayerOpc() const; // 5.7 void setMask(int colorMask); // 5.8 int layerMask() const; // 5.8 int viaTopMask() const; // 5.8 int viaCutMask() const; // 5.8 int viaBottomMask() const; // 5.8 int numRectangles() const; int xl(int index) const; int yl(int index) const; int xh(int index) const; int yh(int index) const; int numPolygons() const; // 5.6 struct defiPoints getPolygon(int index) const; // 5.6 int hasVia() const; // 5.7 const char* viaName() const; // 5.7 int hasViaOpc() const; // 5.7 int numViaPts() const; // 5.7 struct defiPoints getViaPts(int index) const; // 5.7 void print(FILE* f) const; protected: int hasLayer_; char* layerName_; int layerNameLength_; int layerOpc_; // 5.7 int numRectangles_; int rectsAllocated_; int* xl_; int* yl_; int* xh_; int* yh_; int numPolys_; // 5.6 int polysAllocated_; // 5.6 struct defiPoints** polygons_; // 5.6 int hasVia_; // 5.7 char* viaName_; // 5.7 int viaNameLength_; // 5.7 int viaOpc_; // 5.7 int numPts_; // 5.7 int ptsAllocated_; // 5.7 int mask_; // 5.8 struct defiPoints** viaPts_; // 5.7 defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiGroup.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiGroup_h #define defiGroup_h #include #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; // Struct holds the data for one property. class defiGroup { public: defiGroup(defrData *data); void Init(); void Destroy(); ~defiGroup(); void clear(); void setup(const char* name); void addProperty(const char* name, const char* value, const char type); void addNumProperty(const char* name, const double d, const char* value, const char type); void addRegionRect(int xl, int yl, int xh, int yh); void setRegionName(const char* name); void setMaxX(int x); void setMaxY(int y); void setPerim(int p); const char* name() const; const char* regionName() const; int hasRegionBox() const; int hasRegionName() const; int hasMaxX() const; int hasMaxY() const; int hasPerim() const; void regionRects(int* size, int** xl, int**yl, int** xh, int** yh) const; int maxX() const; int maxY() const; int perim() const; int numProps() const; const char* propName(int index) const; const char* propValue(int index) const; double propNumber(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; // debug print void print(FILE* f) const; protected: char* name_; int nameLength_; char* region_; int regionLength_; int rectsAllocated_; int numRects_; int* xl_; int* yl_; int* xh_; int* yh_; int maxX_; int maxY_; int perim_; char hasRegionBox_; char hasRegionName_; char hasPerim_; char hasMaxX_; char hasMaxY_; int numProps_; int propsAllocated_; char** propNames_; char** propValues_; double* propDValues_; char* propTypes_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiIOTiming.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiIOTiming_h #define defiIOTiming_h #include #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; class defiIOTiming { public: defiIOTiming(defrData *data); void Init(); void Destroy(); ~defiIOTiming(); void clear(); void setName(const char* inst, const char* pin); void setVariable(const char* riseFall, double min, double max); void setSlewRate(const char* riseFall, double min, double max); void setCapacitance(double num); void setDriveCell(const char* name); void setFrom(const char* name); void setTo(const char* name); void setParallel(double num); int hasVariableRise() const; int hasVariableFall() const; int hasSlewRise() const; int hasSlewFall() const; int hasCapacitance() const; int hasDriveCell() const; int hasFrom() const; int hasTo() const; int hasParallel() const; const char* inst() const; const char* pin() const; double variableFallMin() const; double variableRiseMin() const; double variableFallMax() const; double variableRiseMax() const; double slewFallMin() const; double slewRiseMin() const; double slewFallMax() const; double slewRiseMax() const; double capacitance() const; const char* driveCell() const; const char* from() const; const char* to() const; double parallel() const; // debug print void print(FILE* f) const; protected: char* inst_; int instLength_; char* pin_; int pinLength_; char* from_; int fromLength_; char* to_; int toLength_; char* driveCell_; char driveCellLength_; char hasVariableRise_; char hasVariableFall_; char hasSlewRise_; char hasSlewFall_; char hasCapacitance_; char hasDriveCell_; char hasFrom_; char hasTo_; char hasParallel_; double variableFallMin_; double variableRiseMin_; double variableFallMax_; double variableRiseMax_; double slewFallMin_; double slewRiseMin_; double slewFallMax_; double slewRiseMax_; double capacitance_; double parallel_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiKRDefs.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiKRDEFS_h #define defiKRDEFS_h #define BEGIN_LEFDEF_PARSER_NAMESPACE namespace LefDefParser { #define END_LEFDEF_PARSER_NAMESPACE } #define USE_LEFDEF_PARSER_NAMESPACE using namespace LefDefParser; #endif /* defiKRDEFS_h */ ================================================ FILE: rsyn/include/def5.8/defiMisc.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiMisc_h #define defiMisc_h #include #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; struct defiPoints { int numPoints; int* x; int* y; }; class defiGeometries { public: defiGeometries(defrData *data); void Init(); void Reset(); void Destroy(); ~defiGeometries(); void startList(int x, int y); void addToList(int x, int y); int numPoints() const; void points(int index, int* x, int* y) const; protected: int numPoints_; int pointsAllocated_; int* x_; int* y_; defrData *defData; }; class defiStyles { public: defiStyles(); void Init(); void Destroy(); ~defiStyles(); void clear(); void setStyle(int styleNum); void setPolygon(defiGeometries* geom); int style() const; struct defiPoints getPolygon() const; protected: int styleNum_; struct defiPoints* polygon_; int numPointAlloc_; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiNet.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013 - 2017, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: icftcm $ // $Revision: #2 $ // $Date: 2017/06/19 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiNet_h #define defiNet_h #include #include "defiKRDefs.hpp" #include "defiPath.hpp" #include "defiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; /* Return codes for defiNet::viaOrient DEF_ORIENT_N 0 DEF_ORIENT_W 1 DEF_ORIENT_S 2 DEF_ORIENT_E 3 DEF_ORIENT_FN 4 DEF_ORIENT_FW 5 DEF_ORIENT_FS 6 DEF_ORIENT_FE 7 */ class defiWire { public: defiWire(defrData *data); ~defiWire(); void Init(const char* type, const char* wireShieldName); void Destroy(); void clear(); void addPath(defiPath *p, int reset, int netOsnet, int *needCbk); const char* wireType() const; const char* wireShieldNetName() const; int numPaths() const; defiPath* path(int index); const defiPath* path(int index) const; void bumpPaths(long long size); protected: char* type_; char* wireShieldName_; // It only set from specialnet SHIELD, 5.4 int numPaths_; long long pathsAllocated_; defiPath** paths_; defrData *defData; }; class defiSubnet { public: defiSubnet(defrData *data); void Init(); void Destroy(); ~defiSubnet(); void setName(const char* name); void setNonDefault(const char* name); void addPin(const char* instance, const char* pin, int syn); void addMustPin(const char* instance, const char* pin, int syn); // WMD -- the following will be removed by the next release void setType(const char* typ); // Either FIXED COVER ROUTED void addPath(defiPath* p, int reset, int netOsnet, int *needCbk); // NEW: a net can have more than 1 wire void addWire(const char *typ); void addWirePath(defiPath *p, int reset, int netOsnet, int *needCbk); // Debug printing void print(FILE* f) const; const char* name() const; int numConnections() const; const char* instance(int index) const; const char* pin(int index) const; int pinIsSynthesized(int index) const; int pinIsMustJoin(int index) const; // WMD -- the following will be removed by the next release int isFixed() const; int isRouted() const; int isCover() const; int hasNonDefaultRule() const; // WMD -- the following will be removed by the next release int numPaths() const; defiPath* path(int index); const defiPath* path(int index) const; const char* nonDefaultRule() const; int numWires() const; defiWire* wire(int index); const defiWire* wire(int index) const; void bumpName(long long size); void bumpPins(long long size); void bumpPaths(long long size); void clear(); protected: char* name_; // name. int nameSize_; // allocated size of name. int numPins_; // number of pins used in array. long long pinsAllocated_; // number of pins allocated in array. char** instances_; // instance names for connections char** pins_; // pin names for connections char* synthesized_; // synthesized flags for pins char* musts_; // must-join flags // WMD -- the following will be removed by the next release char isFixed_; // net type char isRouted_; char isCover_; defiPath** paths_; // paths for this subnet int numPaths_; // number of paths used long long pathsAllocated_; // allocated size of paths array int numWires_; // number of wires defined in the subnet long long wiresAllocated_; // number of wires allocated in the subnet defiWire** wires_; // this replace the paths char* nonDefaultRule_; defrData *defData; }; class defiVpin { public: defiVpin(defrData *data); ~defiVpin(); void Init(const char* name); void Destroy(); void setLayer(const char* name); void setBounds(int xl, int yl, int xh, int yh); void setOrient(int orient); void setLoc(int x, int y); void setStatus(char st); int xl() const ; int yl() const ; int xh() const ; int yh() const ; char status() const; /* P-placed, F-fixed, C-cover, ' ' - not set */ int orient() const ; const char* orientStr() const ; int xLoc() const; int yLoc() const; const char* name() const; const char* layer() const; protected: int xl_; int yl_; int xh_; int yh_; int orient_; /* 0-7 -1 is no orient */ char status_; /* P-placed F-fixed C-cover ' '- none */ int xLoc_; int yLoc_; char* name_; char* layer_; defrData *defData; }; // Pre 5.4 class defiShield { public: defiShield(defrData *data); ~defiShield(); void Init(const char* name); void Destroy(); void clear(); void addPath(defiPath *p, int reset, int netOsnet, int *needCbk); const char* shieldName() const; int numPaths() const; defiPath* path(int index); const defiPath* path(int index) const; void bumpPaths(long long size); protected: char* name_; int numPaths_; long long pathsAllocated_; defiPath** paths_; defrData *defData; }; // Struct holds the data for one component. class defiNet { public: defiNet(defrData *data); void Init(); void Destroy(); ~defiNet(); // Routines used by YACC to set the fields in the net. void setName(const char* name); void addPin(const char* instance, const char* pin, int syn); void addMustPin(const char* instance, const char* pin, int syn); void setWeight(int w); // WMD -- the following will be removed by the next release void setType(const char* typ); // Either FIXED COVER ROUTED void addProp(const char* name, const char* value, const char type); void addNumProp(const char* name, const double d, const char* value, const char type); void addSubnet(defiSubnet* subnet); // NEW: a net can have more than 1 wire void addWire(const char *typ, const char* wireShieldName); void addWirePath(defiPath* p, int reset, int netOsnet, int *needCbk); void addShape(const char *shapeType); // 5.8 void setSource(const char* typ); void setFixedbump(); // 5.4.1 void setFrequency(double frequency); // 5.4.1 void setOriginal(const char* typ); void setPattern(const char* typ); void setCap(double w); void setUse(const char* typ); void setNonDefaultRule(const char* typ); void setStyle(int style); void addShield(const char* shieldNetName); // pre 5.4 void addNoShield(const char* shieldNetName); // pre 5.4 void addShieldNet(const char* shieldNetName); void addShieldPath(defiPath* p, int reset, int netOsnet, int *needCbk); void clear(); void setWidth(const char* layer, double dist); void setSpacing(const char* layer, double dist); void setVoltage(double num); void setRange(double left, double right); void setXTalk(int num); void addVpin(const char* name); void addVpinLayer(const char* name); void addVpinLoc(const char* status, int x, int y, int orient); void addVpinBounds(int xl, int yl, int xh, int yh); // 5.6 void addPolygon(const char* layerName, defiGeometries* geom, int *needCbk, int mask, const char* routeStatus, const char* shapeType, const char* shieldNetName); void addRect(const char* layerName, int xl, int yl, int xh, int yh, int *needCbk, int mask, const char* routeStatus, const char* shapeType, const char* shieldNetName); // 5.6 void addPts(const char* viaName, int o, defiGeometries* geom, int *needCbk, int mask, const char* routeStatus, const char* shapeType, const char* shieldNetName); //VIA 5.8 // For OA to modify the netName, id & pinName void changeNetName(const char* name); void changeInstance(const char* name, int index); void changePin(const char* name, int index); // Routines to return the value of net data. const char* name() const; int weight() const; int numProps() const; const char* propName(int index) const; const char* propValue(int index) const; double propNumber(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; int numConnections() const; const char* instance(int index) const; const char* pin(int index) const; int pinIsMustJoin(int index) const; int pinIsSynthesized(int index) const; int numSubnets() const; defiSubnet* subnet(int index); const defiSubnet* subnet(int index) const; // WMD -- the following will be removed by the next release int isFixed() const; int isRouted() const; int isCover() const; /* The following routines are for wiring */ int numWires() const; defiWire* wire(int index); const defiWire* wire(int index) const; /* Routines to get the information about Virtual Pins. */ int numVpins() const; defiVpin* vpin(int index); const defiVpin* vpin(int index) const; int hasProps() const; int hasWeight() const; int hasSubnets() const; int hasSource() const; int hasFixedbump() const; // 5.4.1 int hasFrequency() const; // 5.4.1 int hasPattern() const; int hasOriginal() const; int hasCap() const; int hasUse() const; int hasStyle() const; int hasNonDefaultRule() const; int hasVoltage() const; int hasSpacingRules() const; int hasWidthRules() const; int hasXTalk() const; int numSpacingRules() const; void spacingRule(int index, char** layer, double* dist, double* left, double* right) const; int numWidthRules() const; void widthRule(int index, char** layer, double* dist) const; double voltage() const; int XTalk() const; const char* source() const; double frequency() const; const char* original() const; const char* pattern() const; double cap() const; const char* use() const; int style() const; const char* nonDefaultRule() const; // WMD -- the following will be removed by the next release int numPaths() const; defiPath* path(int index); const defiPath* path(int index) const; int numShields() const; // pre 5.4 defiShield* shield(int index); // pre 5.4 const defiShield* shield(int index) const ; // pre 5.4 int numShieldNets() const; const char* shieldNet(int index) const; int numNoShields() const; // pre 5.4 defiShield* noShield(int index); // pre 5.4 const defiShield* noShield(int index) const; // pre 5.4 // 5.6 int numPolygons() const; // 5.6 const char* polygonName(int index) const; // 5.6 struct defiPoints getPolygon(int index) const; // 5.6 int polyMask(int index) const; const char* polyRouteStatus(int index) const; const char* polyRouteStatusShieldName(int index) const; const char* polyShapeType(int index) const; int numRectangles() const; // 5.6 const char* rectName(int index) const; // 5.6 int xl(int index)const; // 5.6 int yl(int index)const; // 5.6 int xh(int index)const; // 5.6 int yh(int index)const; // 5.6 int rectMask(int index)const; const char* rectRouteStatus(int index) const; const char* rectRouteStatusShieldName(int index) const; const char* rectShapeType(int index) const; // 5.8 int numViaSpecs() const; struct defiPoints getViaPts(int index) const; const char* viaName(int index) const; const int viaOrient(int index) const; const char* viaOrientStr(int index) const; const int topMaskNum(int index) const; const int cutMaskNum(int index) const; const int bottomMaskNum(int index) const; const char* viaRouteStatus(int index) const; const char* viaRouteStatusShieldName(int index) const; const char* viaShapeType(int index) const; // Debug printing void print(FILE* f) const; void bumpName(long long size); void bumpPins(long long size); void bumpProps(long long size); void bumpSubnets(long long size); void bumpPaths(long long size); void bumpShieldNets(long long size); // The method freeWire() is added is user select to have a callback // per wire within a net This is an internal method and is not public void freeWire(); void freeShield(); // Clear the rectangles & polygons data if partial path callback is set void clearRectPolyNPath(); void clearRectPoly(); void clearVia(); protected: char* name_; // name. int nameSize_; // allocated size of name. int numPins_; // number of pins used in array. long long pinsAllocated_; // number of pins allocated in array. char** instances_; // instance names for connections char** pins_; // pin names for connections char* musts_; // must-join flags for pins char* synthesized_; // synthesized flags for pins int weight_; // net weight char hasWeight_; // flag for optional weight // WMD -- the following will be removed by the nex release char isFixed_; // net type char isRouted_; char isCover_; char hasCap_; // file supplied a capacitance value char hasFrequency_; // file supplied a frequency value char hasVoltage_; int numProps_; // num of props in array char** propNames_; // Prop names char** propValues_; // Prop values All in strings! double* propDValues_; // Prop values in numbers! char* propTypes_; // Prop types, 'I' - Integer, 'R' - Real, 'S' - String long long propsAllocated_; // allocated size of props array int numSubnets_; // num of subnets in array defiSubnet** subnets_; // Prop names long long subnetsAllocated_; // allocated size of props array double cap_; // cap value char* source_; int fixedbump_; // 5.4.1 double frequency_; // 5.4.1 char* pattern_; char* original_; char* use_; char* nonDefaultRule_; int style_; // WMD -- the following will be removed by the nex release defiPath** paths_; // paths for this subnet int numPaths_; // number of paths used long long pathsAllocated_; // allocated size of paths array double voltage_; int numWires_; // number of wires defined in the net long long wiresAllocated_; // allocated size of wire paths array defiWire** wires_; // this replace the paths long long widthsAllocated_; int numWidths_; char** wlayers_; double* wdist_; long long spacingAllocated_; int numSpacing_; char** slayers_; double* sdist_; double* sleft_; double* sright_; int xTalk_; int numVpins_; long long vpinsAllocated_; defiVpin** vpins_; int numShields_; // number of SHIELD paths used long long shieldsAllocated_; // allocated size of SHIELD paths array defiShield** shields_; // SHIELD data int numNoShields_; // number of NOSHIELD paths used int numShieldNet_; // number of SHIELDNETS used in array. long long shieldNetsAllocated_; // number of SHIELDNETS allocated in array. char** shieldNet_; // name of the SHIELDNET int numPolys_; // 5.6 char** polygonNames_; // 5.6 layerName for POLYGON long long polysAllocated_; // 5.6 struct defiPoints** polygons_; // 5.6 int* polyMasks_; char** polyRouteStatus_; char** polyShapeTypes_; char** polyRouteStatusShieldNames_; int numRects_; // 5.6 long long rectsAllocated_; // 5.6 char** rectNames_; // 5.6 int* xl_; int* yl_; int* xh_; int* yh_; int* rectMasks_; char** rectRouteStatus_; char** rectRouteStatusShieldNames_; char** rectShapeTypes_; struct defiPoints** viaPts_; // 5.8 char** viaNames_; int numPts_; long long ptsAllocated_; int* viaOrients_; int* viaMasks_; char** viaRouteStatus_; char** viaRouteStatusShieldNames_; char** viaShapeTypes_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiNonDefault.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiNonDefault_h #define defiNonDefault_h #include #include "defiKRDefs.hpp" #include "defiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defiNonDefault { public: defiNonDefault(defrData *data); void Init(); void Destroy(); ~defiNonDefault(); void clear(); void setName(const char* name); void setHardspacing(); void addLayer(const char* name); void addWidth(double num); void addDiagWidth(double num); void addSpacing(double num); void addWireExt(double num); void addVia(const char* name); void addViaRule(const char* name); void addMinCuts(const char* name, int numCuts); void addProperty(const char* name, const char* value, const char type); void addNumProperty(const char* name, const double d, const char* value, const char type); void end(); const char* name() const; int hasHardspacing() const; int numProps() const; const char* propName(int index) const; const char* propValue(int index) const; double propNumber(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; // A non default rule can have one or more layers. // The layer information is kept in an array. int numLayers() const ; const char* layerName(int index) const ; double layerWidth(int index) const ; // Will be obsoleted in 5.7 int layerWidthVal(int index) const ; int hasLayerDiagWidth(int index) const; double layerDiagWidth(int index) const; // Will be obsoleted in 5.7 int layerDiagWidthVal(int index) const; int hasLayerSpacing(int index) const ; double layerSpacing(int index) const ; // Will be obsoleted in 5.7 int layerSpacingVal(int index) const ; int hasLayerWireExt(int index) const ; double layerWireExt(int index) const ; // Will be obsoleted in 5.7 int layerWireExtVal(int index) const ; int numVias() const ; const char* viaName(int index) const ; int numViaRules() const ; const char* viaRuleName(int index) const ; int numMinCuts() const; const char* cutLayerName(int index) const; int numCuts(int index) const; // Debug print void print(FILE* f) const; protected: char* name_; char hardSpacing_; // Layer information int numLayers_; int layersAllocated_; char** layerName_; double* width_; char* hasDiagWidth_; double* diagWidth_; char* hasSpacing_; double* spacing_; char* hasWireExt_; double* wireExt_; int numVias_; int viasAllocated_; char** viaNames_; int numViaRules_; int viaRulesAllocated_; char** viaRuleNames_; int numMinCuts_; int minCutsAllocated_; char** cutLayerName_; int* numCuts_; int numProps_; int propsAllocated_; char** names_; char** values_; double* dvalues_; char* types_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiPartition.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiPartition_h #define defiPartition_h #include #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; class defiPartition { public: defiPartition(defrData *data); void Init(); void Destroy(); ~defiPartition(); void clear(); void setName(const char* name); void addTurnOff(const char* setup, const char* hold); void setFromClockPin(const char* inst, const char* pin); void setFromCompPin(const char* inst, const char* pin); void setFromIOPin(const char* inst); void setToClockPin(const char* inst, const char* pin); void setToCompPin(const char* inst, const char* pin); void set(char dir, char typ, const char* inst, const char* pin); void setToIOPin(const char* inst); void setMin(double min, double max); void setMax(double min, double max); void addPin(const char* name); void addRiseMin(double d); void addRiseMax(double d); void addFallMin(double d); void addFallMax(double d); void addRiseMinRange(double l, double h); void addRiseMaxRange(double l, double h); void addFallMinRange(double l, double h); void addFallMaxRange(double l, double h); const char* name() const; char direction() const; const char* itemType() const; // "CLOCK" or "IO" or "COMP" const char* pinName() const; const char* instName() const; int numPins() const; const char* pin(int index) const; int isSetupRise() const; int isSetupFall() const; int isHoldRise() const; int isHoldFall() const; int hasMin() const; int hasMax() const; int hasRiseMin() const; int hasFallMin() const; int hasRiseMax() const; int hasFallMax() const; int hasRiseMinRange() const; int hasFallMinRange() const; int hasRiseMaxRange() const; int hasFallMaxRange() const; double partitionMin() const; double partitionMax() const; double riseMin() const; double fallMin() const; double riseMax() const; double fallMax() const; double riseMinLeft() const; double fallMinLeft() const; double riseMaxLeft() const; double fallMaxLeft() const; double riseMinRight() const; double fallMinRight() const; double riseMaxRight() const; double fallMaxRight() const; // debug print void print(FILE* f) const; protected: char* name_; int nameLength_; char setup_; char hold_; char hasMin_; char hasMax_; char direction_; // 'F' or 'T' char type_; // 'L'-clock 'I'-IO 'C'-comp char* inst_; int instLength_; char* pin_; int pinLength_; double min_, max_; int numPins_; int pinsAllocated_; char** pins_; char hasRiseMin_; char hasFallMin_; char hasRiseMax_; char hasFallMax_; char hasRiseMinRange_; char hasFallMinRange_; char hasRiseMaxRange_; char hasFallMaxRange_; double riseMin_; double fallMin_; double riseMax_; double fallMax_; double riseMinLeft_; double fallMinLeft_; double riseMaxLeft_; double fallMaxLeft_; double riseMinRight_; double fallMinRight_; double riseMaxRight_; double fallMaxRight_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiPath.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013-2014, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiPath_h #define defiPath_h #include #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE // TX_DIR:TRANSLATION ON class defrData; struct defiPnt { int x; int y; int ext; }; // 5.4.1 1-D & 2-D Arrays of Vias in SPECIALNET Section struct defiViaData { int numX; int numY; int stepX; int stepY; }; struct defiViaRect { int deltaX1; int deltaY1; int deltaX2; int deltaY2; }; // value returned by the next() routine. enum defiPath_e { DEFIPATH_DONE = 0, DEFIPATH_LAYER, DEFIPATH_VIA, DEFIPATH_VIAROTATION, DEFIPATH_WIDTH, DEFIPATH_POINT, DEFIPATH_FLUSHPOINT, DEFIPATH_TAPER, DEFIPATH_SHAPE, DEFIPATH_STYLE, DEFIPATH_TAPERRULE, DEFIPATH_VIADATA, DEFIPATH_RECT, DEFIPATH_VIRTUALPOINT, DEFIPATH_MASK, DEFIPATH_VIAMASK } ; class defiPath { public: defiPath(defrData *data); // This is 'data ownership transfer' constructor. defiPath(defiPath *defiPathRef); void Init(); void Destroy(); ~defiPath(); void clear(); void reverseOrder(); // To traverse the path and get the parts. void initTraverse() const; // Initialize the traverse. void initTraverseBackwards() const; // Initialize the traverse in reverse. int next() const; // Get the next element. int prev() const; // Get the next element in reverse. const char* getLayer() const;// Get the layer. const char* getTaperRule() const;// Get the rule. const char* getVia() const; // Get the via. const char* getShape() const;// Get the shape. int getTaper() const;// Get the taper. int getStyle() const;// Get the style. int getViaRotation() const; // Get the via rotation. void getViaRect(int* deltaX1, int* deltaY1, int* deltaX2, int* deltaY2) const; const char* getViaRotationStr() const; // Return via rotation in string format void getViaData(int* numX, int* numY, int* stepX, int* stepY) const; // 5.4.1 int getWidth() const; // Get the width. void getPoint(int* x, int* y) const;// Get the point. void getFlushPoint(int* x, int* y, int* ext) const;// Get the point. void getVirtualPoint(int* x, int* y) const; int getMask() const; int getViaTopMask() const; int getViaCutMask() const; int getViaBottomMask() const; int getRectMask() const; // These routines are called by the parser to fill the path. void addWidth(int w); void addPoint(int x, int y); void addFlushPoint(int x, int y, int ext); void addVirtualPoint(int x, int y); void addLayer(const char* layer); void addVia(const char* name); void addViaRotation(int orient); void addViaRect(int deltaX1, int deltaY1, int deltaX2, int deltaY2); void addMask(int colorMask); void addViaMask(int colorMask); void addViaData(int numX, int numY, int stepX, int stepY); // 5.4.1 void setTaper(); void addTaperRule(const char* rule); void addShape(const char* shape); void addStyle(int style); // debug printing void print(FILE* fout) const; void bumpSize(int size); protected: int currentType() const; int* keys_; // type of item in path void** data_; // extra data int numUsed_; // number of items used in array int numAllocated_; // allocated size of keys and data int* pointer_; // traversal pointer, allocated because used // as iterator in const traversal functions. int numX_; int numY_; int stepX_; int stepY_; int deltaX_; int deltaY_; int mask_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiPinCap.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiPinCap_h #define defiPinCap_h #include "defiKRDefs.hpp" #include "defiMisc.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; class defiPinCap { public: void setPin(int p); void setCap(double d); int pin() const; double cap() const; void print(FILE* f) const; protected: int pin_; // pin num double cap_; // capacitance }; // 5.5 class defiPinAntennaModel { public: defiPinAntennaModel(defrData *data); void Init(); ~defiPinAntennaModel(); void clear(); void Destroy(); void setAntennaModel(int oxide); void addAPinGateArea(int value, const char* layer); void addAPinMaxAreaCar(int value, const char* layer); void addAPinMaxSideAreaCar(int value, const char* layer); void addAPinMaxCutCar(int value, const char* layer); char* antennaOxide() const; int hasAPinGateArea() const; // ANTENNAPINGATEAREA int numAPinGateArea() const; int APinGateArea(int index) const; int hasAPinGateAreaLayer(int index) const; const char* APinGateAreaLayer(int index) const; int hasAPinMaxAreaCar() const; // ANTENNAPINMAXAREACAR int numAPinMaxAreaCar() const; int APinMaxAreaCar(int index) const; int hasAPinMaxAreaCarLayer(int index) const; const char* APinMaxAreaCarLayer(int index) const; int hasAPinMaxSideAreaCar() const; // ANTENNAPINMAXSIDEAREACAR int numAPinMaxSideAreaCar() const; int APinMaxSideAreaCar(int index) const; int hasAPinMaxSideAreaCarLayer(int index) const; const char* APinMaxSideAreaCarLayer(int index) const; int hasAPinMaxCutCar() const; // ANTENNAPINMAXCUTCAR int numAPinMaxCutCar() const; int APinMaxCutCar(int index) const; int hasAPinMaxCutCarLayer(int index) const; const char* APinMaxCutCarLayer(int index) const; protected: char* oxide_; int numAPinGateArea_; // 5.4 int APinGateAreaAllocated_; int* APinGateArea_; // 5.4 AntennaPinGateArea char** APinGateAreaLayer_; // 5.4 Layer int numAPinMaxAreaCar_; // 5.4 int APinMaxAreaCarAllocated_; int* APinMaxAreaCar_; // 5.4 AntennaPinMaxAreaCar char** APinMaxAreaCarLayer_; // 5.4 Layer int numAPinMaxSideAreaCar_; // 5.4 int APinMaxSideAreaCarAllocated_; int* APinMaxSideAreaCar_; // 5.4 AntennaPinMaxSideAreaCar char** APinMaxSideAreaCarLayer_; // 5.4 Layer int numAPinMaxCutCar_; // 5.4 int APinMaxCutCarAllocated_; int* APinMaxCutCar_; // 5.4 AntennaPinMaxCutCar char** APinMaxCutCarLayer_; // 5.4 Layer defrData *defData; }; class defiPinPort { // 5.7 public: defiPinPort(defrData *data); void Init(); ~defiPinPort(); void clear(); void addLayer(const char* layer); void addLayerSpacing(int minSpacing); void addLayerMask(int mask); void addLayerDesignRuleWidth(int effectiveWidth); void addLayerPts(int xl, int yl, int xh, int yh); void addPolygon(const char* layerName); void addPolySpacing(int minSpacing); void addPolyMask(int mask); void addPolyDesignRuleWidth(int effectiveWidth); void addPolygonPts(defiGeometries* geom); void addVia(const char* via, int viaX, int viaY, int color = 0); void setPlacement(int typ, int x, int y, int orient); int numLayer() const; const char* layer(int index) const; void bounds(int index, int* xl, int* yl, int* xh, int* yh) const; int hasLayerSpacing(int index) const; int hasLayerDesignRuleWidth(int index) const; int layerSpacing(int index) const; int layerMask(int index) const; int layerDesignRuleWidth(int index) const; int numPolygons() const; const char* polygonName(int index) const; defiPoints getPolygon(int index) const; int hasPolygonSpacing(int index) const; int hasPolygonDesignRuleWidth(int index) const; int polygonSpacing(int index) const; int polygonDesignRuleWidth(int index) const; int polygonMask(int index) const; int numVias() const; const char* viaName(int index) const; int viaPtX (int index) const; int viaPtY (int index) const; int viaTopMask (int index) const; int viaCutMask (int index) const; int viaBottomMask (int index) const; int hasPlacement() const; int isPlaced() const; int isCover() const; int isFixed() const; int placementX() const; int placementY() const; int orient() const; const char* orientStr() const; protected: int layersAllocated_; int numLayers_; char** layers_; int *layerMinSpacing_; int *layerEffectiveWidth_; int *xl_, *yl_, *xh_, *yh_; int *layerMask_; int polysAllocated_; int numPolys_; char** polygonNames_; int *polyMinSpacing_; int *polyMask_; int *polyEffectiveWidth_; defiPoints** polygons_; int viasAllocated_; int numVias_; char** viaNames_; int *viaX_; int *viaY_; int *viaMask_; char placeType_; int x_, y_; char orient_; defrData *defData; }; class defiPin { public: defiPin(defrData *data); void Init(); ~defiPin(); void Destroy(); void Setup(const char* pinName, const char* netName); void setDirection(const char* dir); void setUse(const char* use); // 5.6 setLayer is changed to addLayer due to multiple LAYER are allowed // in 5.6 void addLayer(const char* layer); void addLayerMask(int mask); // 5.8 void addLayerSpacing(int minSpacing); // 5.6 void addLayerDesignRuleWidth(int effectiveWidth); // 5.6 void addLayerPts(int xl, int yl, int xh, int yh); void addPolygon(const char* layerName); // 5.6 void addPolyMask(int mask); // 5.8 void addPolySpacing(int minSpacing); // 5.6 void addPolyDesignRuleWidth(int effectiveWidth); // 5.6 void addPolygonPts(defiGeometries* geom); // 5.6 void setNetExpr(const char* netExpr); // 5.6 void setSupplySens(const char* pinName); // 5.6 void setGroundSens(const char* pinName); // 5.6 void setPlacement(int typ, int x, int y, int orient); void setSpecial(); void addAntennaModel(int oxide); // 5.5 void addAPinPartialMetalArea(int value, const char* layer); void addAPinPartialMetalSideArea(int value, const char* layer); void addAPinGateArea(int value, const char* layer); void addAPinDiffArea(int value, const char* layer); void addAPinMaxAreaCar(int value, const char* layer); void addAPinMaxSideAreaCar(int value, const char* layer); void addAPinPartialCutArea(int value, const char* layer); void addAPinMaxCutCar(int value, const char* layer); void addVia(const char* via, int viaX, int viaY, int color = 0); // 5.7 // 5.7 port statements, which may have LAYER, POLYGON, &| VIA void addPort(); // 5.7 void addPortLayer(const char* layer); // 5.7 void addPortLayerSpacing(int minSpacing); // 5.7 void addPortLayerDesignRuleWidth(int effectiveWidth); // 5.7 void addPortLayerPts(int xl, int yl, int xh, int yh); // 5.7 void addPortLayerMask(int color); // 5.8 void addPortPolygon(const char* layerName); // 5.7 void addPortPolySpacing(int minSpacing); // 5.7 void addPortPolyDesignRuleWidth(int effectiveWidth); // 5.7 void addPortPolygonPts(defiGeometries* geom); // 5.7 void addPortPolyMask(int color); // 5.8 void addPortVia(const char* via, int viaX, int viaY, int color = 0); // 5.7 void setPortPlacement(int typ, int x, int y, int orient); // 5.7 - 5.8 void clear(); void changePinName(const char* pinName); // For OA to modify the pinName const char* pinName() const; const char* netName() const; // optional parts int hasDirection() const; int hasUse() const; int hasLayer() const; int hasPlacement() const; int isUnplaced() const; int isPlaced() const; int isCover() const; int isFixed() const; int placementX() const; int placementY() const; const char* direction() const; const char* use() const; int numLayer() const; const char* layer(int index) const; void bounds(int index, int* xl, int* yl, int* xh, int* yh) const; int layerMask(int index) const; // 5.8 int hasLayerSpacing(int index) const; // 5.6 int hasLayerDesignRuleWidth(int index) const; // 5.6 int layerSpacing(int index) const; // 5.6 int layerDesignRuleWidth(int index) const; // 5.6 int numPolygons() const; // 5.6 const char* polygonName(int index) const; // 5.6 defiPoints getPolygon(int index) const; // 5.6 int polygonMask(int index) const; // 5.8 int hasPolygonSpacing(int index) const; // 5.6 int hasPolygonDesignRuleWidth(int index) const; // 5.6 int polygonSpacing(int index) const; // 5.6 int polygonDesignRuleWidth(int index) const; // 5.6 int hasNetExpr() const; // 5.6 int hasSupplySensitivity() const; // 5.6 int hasGroundSensitivity() const; // 5.6 const char* netExpr() const; // 5.6 const char* supplySensitivity() const; // 5.6 const char* groundSensitivity() const; // 5.6 int orient() const; const char* orientStr() const; int hasSpecial() const; int numVias() const; // 5.7 const char* viaName(int index) const; // 5.7 int viaTopMask(int index) const; // 5.8 int viaCutMask(int index) const; // 5.8 int viaBottomMask(int index) const; // 5.8 int viaPtX (int index) const; // 5.7 int viaPtY (int index) const; // 5.7 // 5.4 int hasAPinPartialMetalArea() const; // ANTENNAPINPARTIALMETALAREA int numAPinPartialMetalArea() const; int APinPartialMetalArea(int index) const; int hasAPinPartialMetalAreaLayer(int index) const; const char* APinPartialMetalAreaLayer(int index) const; int hasAPinPartialMetalSideArea() const; // ANTENNAPINPARTIALMETALSIDEAREA int numAPinPartialMetalSideArea() const; int APinPartialMetalSideArea(int index) const; int hasAPinPartialMetalSideAreaLayer(int index) const; const char* APinPartialMetalSideAreaLayer(int index) const; int hasAPinDiffArea() const; // ANTENNAPINDIFFAREA int numAPinDiffArea() const; int APinDiffArea(int index) const; int hasAPinDiffAreaLayer(int index) const; const char* APinDiffAreaLayer(int index) const; int hasAPinPartialCutArea() const; // ANTENNAPINPARTIALCUTAREA int numAPinPartialCutArea() const; int APinPartialCutArea(int index) const; int hasAPinPartialCutAreaLayer(int index) const; const char* APinPartialCutAreaLayer(int index) const; // 5.5 int numAntennaModel() const; defiPinAntennaModel* antennaModel(int index) const; // 5.7 int hasPort() const; int numPorts() const; defiPinPort* pinPort(int index) const; void print(FILE* f) const; protected: int pinNameLength_; // allocated size of pin name char* pinName_; int netNameLength_; // allocated size of net name char* netName_; char hasDirection_; char hasUse_; char placeType_; char orient_; // orient 0-7 int useLength_; // allocated size of length char* use_; int directionLength_; // allocated size of direction char* direction_; char** layers_; // 5.6, changed to array int *xl_, *yl_, *xh_, *yh_; // 5.6, changed to arrays int *layerMinSpacing_; // 5.6, SPACING in LAYER int *layerEffectiveWidth_; // 5.6, DESIGNRULEWIDTH in LAYER int layersAllocated_; // 5.6 int numLayers_; // 5.6 int *layerMask_; // 5.8 char** polygonNames_; // 5.6 layerName for POLYGON int *polyMinSpacing_; // 5.6, SPACING in POLYGON int *polyEffectiveWidth_; // 5.6, DESIGNRULEWIDTH in POLYGON int *polyMask_; // 5.8 int numPolys_; // 5.6 int polysAllocated_; // 5.6 defiPoints** polygons_; // 5.6 int x_, y_; // placement int hasSpecial_; int numVias_; // 5.7 int viasAllocated_; // 5.7 char** viaNames_; // 5.7 int *viaX_; // 5.7 int *viaY_; // 5.7 int *viaMask_; // 5.8 int numPorts_; // 5.7 int portsAllocated_; // 5.7 defiPinPort ** pinPort_; // 5.7 // 5.5 AntennaModel int numAntennaModel_; int antennaModelAllocated_; defiPinAntennaModel** antennaModel_; int numAPinPartialMetalArea_; // 5.4 int APinPartialMetalAreaAllocated_; int* APinPartialMetalArea_; // 5.4 AntennaPinPartialMetalArea char** APinPartialMetalAreaLayer_; // 5.4 Layer int numAPinPartialMetalSideArea_; // 5.4 int APinPartialMetalSideAreaAllocated_; int* APinPartialMetalSideArea_; // 5.4 AntennaPinPartialMetalSideArea char** APinPartialMetalSideAreaLayer_; // 5.4 Layer int numAPinDiffArea_; // 5.4 int APinDiffAreaAllocated_; int* APinDiffArea_; // 5.4 AntennaPinDiffArea char** APinDiffAreaLayer_; // 5.4 Layer int numAPinPartialCutArea_; // 5.4 int APinPartialCutAreaAllocated_; int* APinPartialCutArea_; // 5.4 AntennaPinPartialCutArea char** APinPartialCutAreaLayer_; // 5.4 Layer int netExprLength_; // 5.6 char hasNetExpr_; // 5.6 char* netExpr_; // 5.6 int supplySensLength_; // 5.6 char hasSupplySens_; // 5.6 char* supplySens_; // 5.6 int groundSensLength_; // 5.6 char hasGroundSens_; // 5.6 char* groundSens_; // 5.6 defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiPinProp.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiPinProp_h #define defiPinProp_h #include "defiKRDefs.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; class defiPinProp { public: defiPinProp(defrData *data); void Init(); ~defiPinProp(); void Destroy(); void clear(); void setName(const char* inst, const char* pin); void addProperty(const char* name, const char* value, const char type); void addNumProperty(const char* name, const double d, const char* value, const char type); int isPin() const; const char* instName() const; const char* pinName() const; int numProps() const; const char* propName(int index) const; const char* propValue(int index) const; double propNumber(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; void print(FILE* f) const; protected: char isPin_; int instNameSize_; char* instName_; int pinNameSize_; char* pinName_; int numProps_; int propsAllocated_; char** propNames_; char** propValues_; double* propDValues_; char* propTypes_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiProp.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiProp_h #define defiProp_h #include "defiKRDefs.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; // Struct holds the data for one property. class defiProp { public: defiProp(defrData *data); void Init(); void Destroy(); ~defiProp(); void setPropType(const char* typ, const char* string); void setRange(double left, double right); void setNumber(double num); void setPropInteger(); void setPropReal(); void setPropString(); void setPropQString(const char* string); void setPropNameMapString(const char* string); void clear(); const char* string() const; const char* propType() const; const char* propName() const; char dataType() const; // either I:integer R:real S:string Q:quotedstring N:nameMapString int hasNumber() const; int hasRange() const; int hasString() const; int hasNameMapString() const; double number() const; double left() const; double right() const; void bumpSize(int size); void bumpName(int size); void print(FILE* f) const; protected: char* propType_; // "design" ... char* propName_; // name. int nameSize_; // allocated size of name. char hasRange_; // either 0:NO or 1:YES. char hasNumber_; // either 0:NO or 1:YES. char hasNameMapString_; char dataType_; // either I:integer R:real S:string Q:quotedstring. // N:nameMapString char* stringData_; // if it is a string the data is here. int stringLength_; // allocated size of stringData. double left_, right_; // if it has a range the numbers are here. double d_; // if it is a real or int the number is here. defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiPropType.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiPropType_h #define defiPropType_h #include "defiKRDefs.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE // Struct holds the data type for one property, if the property is // either REAL or INTEGER. class defiPropType { public: defiPropType(); void Init(); void Destroy(); ~defiPropType(); void setPropType(const char* name, const char type); void Clear(); const char propType(char* name) const; void bumpProps(); protected: int numProperties_; int propertiesAllocated_; char** propNames_; // name. char* propTypes_; // 'R' == "REAL", 'I' == "INTEGER" }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiRegion.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiRegion_h #define defiRegion_h #include "defiKRDefs.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; // Struct holds the data for one property. class defiRegion { public: defiRegion(defrData *data); void Init(); void Destroy(); ~defiRegion(); void clear(); void setup(const char* name); void addRect(int xl, int yl, int xh, int yh); void addProperty(const char* name, const char* value, const char type); void addNumProperty(const char* name, const double d, const char* value, const char type); void setType(const char* type); // 5.4.1 const char* name() const; int numProps() const; const char* propName(int index) const; const char* propValue(int index) const; double propNumber(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; int hasType() const; // 5.4.1 const char* type() const; // 5.4.1 int numRectangles() const; int xl(int index) const; int yl(int index) const; int xh(int index) const; int yh(int index) const; void print(FILE* f) const; protected: char* name_; int nameLength_; int numRectangles_; int rectanglesAllocated_; int* xl_; int* yl_; int* xh_; int* yh_; int numProps_; int propsAllocated_; char** propNames_; char** propValues_; double* propDValues_; char* propTypes_; char* type_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiRowTrack.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiRowTrack_h #define defiRowTrack_h #include "defiKRDefs.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; class defiRow{ public: defiRow(defrData *data); void Init(); ~defiRow(); void Destroy(); void clear(); void setup(const char* name, const char* macro, double x, double y, int orient); void setDo(double x_num, double y_num, double x_step, double y_step); void setHasDoStep(); void addProperty(const char* name, const char* value, const char type); void addNumProperty(const char* name, const double d, const char* value, const char type); const char* name() const; const char* macro() const; double x() const; double y() const; int orient() const; const char* orientStr() const; int hasDo() const; // 5.6, DO is optional double xNum() const; double yNum() const; int hasDoStep() const; // 5.6, STEP is optional in DO double xStep() const; double yStep() const; int numProps() const; const char* propName(int index) const; const char* propValue(int index) const; double propNumber(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; void print(FILE* f) const; protected: int nameLength_; char* name_; int macroLength_; char* macro_; double x_; double y_; double xNum_; double yNum_; int orient_; double xStep_; double yStep_; int hasDo_; int hasDoStep_; int numProps_; int propsAllocated_; char** propNames_; char** propValues_; double* propDValues_; char* propTypes_; defrData *defData; }; class defiTrack{ public: defiTrack(defrData *data); void Init(); ~defiTrack(); void Destroy(); void setup(const char* macro); void setDo(double x, double x_num, double x_step); void addLayer(const char* layer); void addMask(int colorMask, int sameMask); const char* macro() const; double x() const; double xNum() const; double xStep() const; int numLayers() const; const char* layer(int index) const; int firstTrackMask() const; int sameMask() const; void print(FILE* f) const; protected: int macroLength_; // allocated size of macro_; char* macro_; double x_; double xNum_; double xStep_; int layersLength_; // allocated size of layers_ int numLayers_; // number of places used in layers_ char** layers_; int firstTrackMask_; int samemask_; defrData *defData; }; class defiGcellGrid { public: defiGcellGrid(defrData *data); void Init(); ~defiGcellGrid(); void Destroy(); void setup(const char* macro, int x, int xNum, double xStep); const char* macro() const; int x() const; int xNum() const; double xStep() const; void print(FILE* f) const; protected: int macroLength_; char* macro_; int x_; int xNum_; double xStep_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiScanchain.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiScanchain_h #define defiScanchain_h #include "defiKRDefs.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; class defiOrdered { public: defiOrdered(defrData *data); ~defiOrdered(); void addOrdered(const char* inst); void addIn(const char* pin); void addOut(const char* pin); void setOrderedBits(int bits); // 5.4.1 void bump(); void Init(); void Destroy(); void clear(); int num() const; char** inst() const; char** in() const; char** out() const; int* bits() const; // 5.4.1 protected: int num_; int allocated_; char** inst_; char** in_; char** out_; int* bits_; // 5.4.1 defrData *defData; }; // Struct holds the data for one Scan chain. // class defiScanchain { public: defiScanchain(defrData *data); void Init(); void Destroy(); ~defiScanchain(); void setName(const char* name); void clear(); void addOrderedList(); void addOrderedInst(const char* inst); void addOrderedIn(const char* inPin); void addOrderedOut(const char* outPin); void setOrderedBits(int bits); // 5.4.1 void addFloatingInst(const char* inst); void addFloatingIn(const char* inPin); void addFloatingOut(const char* outPin); void setFloatingBits(int bits); // 5.4.1 void setStart(const char* inst, const char* pin); void setStop(const char* inst, const char* pin); void setCommonIn(const char* pin); void setCommonOut(const char* pin); void setPartition(const char* partName, int maxBits); // 5.4.1 const char* name() const; int hasStart() const; int hasStop() const; int hasFloating() const; int hasOrdered() const; int hasCommonInPin() const; int hasCommonOutPin() const; int hasPartition() const; // 5.4.1 int hasPartitionMaxBits() const; // 5.4.1 // If the pin part of these routines were not supplied in the DEF // then a NULL pointer will be returned. void start(char** inst, char** pin) const; void stop(char** inst, char** pin) const; // There could be many ORDERED constructs in the DEF. The data in // each ORDERED construct is stored in its own array. The numOrderedLists() // routine tells how many lists there are. int numOrderedLists() const; // This routine will return an array of instances and // an array of in and out pins. // The number if things in the arrays is returned in size. // The inPin and outPin entry is optional for each instance. // If an entry is not given, then that char* is NULL. // For example if the second instance has // instnam= "FOO" and IN="A", but no OUT given, then inst[1] points // to "FOO" inPin[1] points to "A" and outPin[1] is a NULL pointer. void ordered(int index, int* size, char*** inst, char*** inPin, char*** outPin, int** bits) const; // All of the floating constructs in the scan chain are // stored in this one array. // If the IN or OUT of an entry is not supplied then the array will have // a NULL pointer in that place. void floating(int* size, char*** inst, char*** inPin, char*** outPin, int** bits) const; const char* commonInPin() const; const char* commonOutPin() const; const char* partitionName() const; // 5.4.1 int partitionMaxBits() const; // 5.4.1 void print(FILE* f) const; protected: char* name_; char hasStart_; char hasStop_; int nameLength_; int numOrderedAllocated_; int numOrdered_; defiOrdered** ordered_; int numFloatingAllocated_; int numFloating_; char** floatInst_; // Array of floating names char** floatIn_; char** floatOut_; int* floatBits_; // 5.4.1 char* stopInst_; char* stopPin_; char* startInst_; char* startPin_; char* commonInPin_; char* commonOutPin_; char hasPartition_; // 5.4.1 char* partName_; // 5.4.1 int maxBits_; // 5.4.1 defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiSite.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiSite_h #define defiSite_h #include "defiKRDefs.hpp" #include "defiMisc.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; /* * Struct holds the data for one site. * It is also used for a canplace and cannotoccupy. */ class defiSite { public: defiSite(defrData *data); void Init(); ~defiSite(); void Destroy(); void clear(); void setName(const char* name); void setLocation(double xorg, double yorg); void setOrient(int orient); void setDo(double x_num, double y_num, double x_step, double y_step); double x_num() const; double y_num() const; double x_step() const; double y_step() const; double x_orig() const; double y_orig() const; int orient() const; const char* orientStr() const; const char* name() const; void print(FILE* f) const; void bumpName(int size); protected: char* siteName_; // Name of this. int nameSize_; // allocated size of siteName_ double x_orig_, y_orig_; // Origin double x_step_, y_step_; // Array step size. double x_num_, y_num_; int orient_; // orientation defrData *defData; }; /* Struct holds the data for a Box */ class defiBox { public: // Use the default destructor and constructor. // 5.6 changed to use it own constructor & destructor defiBox(); void Init(); void Destroy(); ~defiBox(); // NOTE: 5.6 // The following methods are still here for backward compatibility // For new reader they should use numPoints & getPoint to get the // data. int xl() const; int yl() const; int xh() const; int yh() const; void addPoint(defiGeometries* geom); defiPoints getPoint() const; void print(FILE* f) const; protected: int xl_, yl_; int xh_, yh_; defiPoints* points_; // 5.6 }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiSlot.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiSLOT_h #define defiSLOT_h #include #include "defiKRDefs.hpp" #include "defiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; class defiSlot { public: defiSlot(defrData *data); void Init(); void Destroy(); ~defiSlot(); void clear(); void clearPoly(); void setLayer(const char* name); void addRect(int xl, int yl, int xh, int yh); void addPolygon(defiGeometries* geom); int hasLayer() const; const char* layerName() const; int numRectangles() const; int xl(int index) const; int yl(int index) const; int xh(int index) const; int yh(int index) const; int numPolygons() const; // 5.6 defiPoints getPolygon(int index) const; // 5.6 void print(FILE* f) const; protected: int hasLayer_; char* layerName_; int layerNameLength_; int numRectangles_; int rectsAllocated_; int* xl_; int* yl_; int* xh_; int* yh_; int numPolys_; // 5.6 int polysAllocated_; // 5.6 defiPoints** polygons_; // 5.6 defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiTimingDisable.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiTimingDisable_h #define defiTimingDisable_h #include #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE // A Timing disable can be a from-to or a thru or a macro. // A macro is either a fromto macro or a thru macro. class defrData; class defiTimingDisable { public: defiTimingDisable(defrData *data); void Init(); void Destroy(); ~defiTimingDisable(); void clear(); void setFromTo(const char* fromInst, const char* fromPin, const char* toInst, const char* toPin); void setThru(const char* fromInst, const char* fromPin); void setMacro(const char* name); void setMacroThru(const char* thru); void setMacroFromTo(const char* fromPin, const char* toPin); void setReentrantPathsFlag(); int hasMacroThru() const; int hasMacroFromTo() const; int hasThru() const; int hasFromTo() const; int hasReentrantPathsFlag() const; const char* fromPin() const; const char* toPin() const; const char* fromInst() const; const char* toInst() const; const char* macroName() const; const char* thruPin() const; // Also macro thru const char* thruInst() const; // debug print void print(FILE* f) const; protected: char* fromInst_; // also macro name and thru inst int fromInstLength_; char* toInst_; int toInstLength_; char* fromPin_; // also macro thru and thru pin int fromPinLength_; char* toPin_; int toPinLength_; int hasFromTo_; int hasThru_; int hasMacro_; int hasReentrantPathsFlag_; defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiUser.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** /* * User header file for the DEF Interface. This includes * all of the header files which are relevant to both the * reader and the writer. * * defrReader.h and defwWriter.h include this file, so that * an application only needs to include either defwReader.h * or defwWriter.h. */ #ifndef DEFI_USER_H #define DEFI_USER_H /* General utilities. */ /* #include "defiMalloc.hpp" */ /* #include "defiUtils.hpp" */ /* * API objects */ #include "defiDebug.hpp" #include "defiProp.hpp" #include "defiSite.hpp" #include "defiComponent.hpp" #include "defiNet.hpp" #include "defiPath.hpp" #include "defiPinCap.hpp" #include "defiRowTrack.hpp" #include "defiVia.hpp" #include "defiRegion.hpp" #include "defiGroup.hpp" #include "defiAssertion.hpp" #include "defiScanchain.hpp" #include "defiIOTiming.hpp" #include "defiFPC.hpp" #include "defiTimingDisable.hpp" #include "defiPartition.hpp" #include "defiPinProp.hpp" #include "defiBlockage.hpp" #include "defiSlot.hpp" #include "defiFill.hpp" #include "defiNonDefault.hpp" #include "defiPropType.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE /* NEW CALLBACK - If you are creating a new .cpp and .hpp file to * describe a new class of object in the parser, then add a reference * to the .hpp here. * * You must also add an entry for the .h and the .hpp in the package_list * file of the ../../../release directory. */ END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiUtil.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiUtil_h #define defiUtil_h #include "defiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE /* Return codes Orient and Rotation */ #define DEF_ORIENT_N 0 #define DEF_ORIENT_W 1 #define DEF_ORIENT_S 2 #define DEF_ORIENT_E 3 #define DEF_ORIENT_FN 4 #define DEF_ORIENT_FW 5 #define DEF_ORIENT_FS 6 #define DEF_ORIENT_FE 7 const char* defiOrientStr(int orient); END_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defiVia.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defiVia_h #define defiVia_h #include "defiKRDefs.hpp" #include #include "defiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrData; // Struct holds the data for one property. class defiVia { public: defiVia(defrData *data); void Init(); void clear(); void Destroy(); ~defiVia(); void setup(const char* name); void addPattern(const char* patt); void addLayer(const char* layer, int xl, int yl, int xh, int yh, int colorMask = 0); // 5.6 void addPolygon(const char* layer, defiGeometries* geom, int colorMask = 0); void addViaRule(char* viaRuleName, int xSize, int ySize, char* botLayer, char* cutLayer, char* topLayer, int xSpacing, int ySpacing, int xBotEnc, int yBotEnc, int xTopEnc, int yTopEnc); void addRowCol(int numCutRows, int numCutCols); void addOrigin(int xOffset, int yOffset); void addOffset(int xBotOs, int yBotOs, int xTopOs, int yTopOs); void addCutPattern(char* cutPattern); const char* name() const; const char* pattern() const; int hasPattern() const; int numLayers() const; void layer(int index, char** layer, int* xl, int* yl, int* xh, int* yh) const; int numPolygons() const; // 5.6 const char* polygonName(int index) const; // 5.6 defiPoints getPolygon(int index) const; // 5.6 int hasViaRule() const; void viaRule(char** viaRuleName, int* xSize, int* ySize, char** botLayer, char** cutLayer, char** topLayer, int* xCutSpacing, int* yCutSpacing, int* xBotEnc, int* yBotEnc, int* xTopEnc, int* yTopEnc) const; int hasRowCol() const; void rowCol(int* numCutRows, int* numCutCols) const; int hasOrigin() const; void origin(int* xOffset, int* yOffset) const; int hasOffset() const; void offset(int* xBotOffset, int* yBotOffset, int* xTopOffset, int* yTopOffset) const; int hasCutPattern() const; const char* cutPattern() const; int hasRectMask(int index) const; int rectMask(int index) const; int hasPolyMask(int index) const; int polyMask(int index) const; void print(FILE* f) const; protected: char* name_; int nameLength_; char* pattern_; int patternLength_; char** layers_; int hasPattern_; int* xl_; int* yl_; int* xh_; int* yh_; int layersLength_; int numLayers_; int numPolys_; // 5.6 char** polygonNames_; // 5.6 layerName for POLYGON int polysAllocated_; // 5.6 defiPoints** polygons_; // 5.6 char* viaRule_; // 5.6 int viaRuleLength_; // 5.6 int hasViaRule_; // 5.6 int xSize_; // 5.6 int ySize_; // 5.6 char* botLayer_; // 5.6 char* cutLayer_; // 5.6 char* topLayer_; // 5.6 int botLayerLength_; // 5.6 int cutLayerLength_; // 5.6 int topLayerLength_; // 5.6 int xCutSpacing_; // 5.6 int yCutSpacing_; // 5.6 int xBotEnc_; // 5.6 int yBotEnc_; // 5.6 int xTopEnc_; // 5.6 int yTopEnc_; // 5.6 int rows_; // 5.6 int cols_; // 5.6 int xOffset_; // 5.6 int yOffset_; // 5.6 int xBotOffset_; // 5.6 int yBotOffset_; // 5.6 int xTopOffset_; // 5.6 int yTopOffset_; // 5.6 char* cutPattern_; // 5.6 int cutPatternLength_; // 5.6 int hasCutPattern_; // 5.6 int* rectMask_; // 5.8 int* polyMask_; // 5.8 defrData *defData; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defrCallBacks.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef DEFRCALLBACKS_H #define DEFRCALLBACKS_H 1 #include "defiKRDefs.hpp" #include "defrReader.hpp" #include "defrReader.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class defrCallbacks { public: defrCallbacks(); void SetUnusedCallbacks(defrVoidCbkFnType f); defrStringCbkFnType DesignCbk; defrStringCbkFnType TechnologyCbk; defrVoidCbkFnType DesignEndCbk; defrPropCbkFnType PropCbk; defrVoidCbkFnType PropDefEndCbk; defrVoidCbkFnType PropDefStartCbk; defrStringCbkFnType ArrayNameCbk; defrStringCbkFnType FloorPlanNameCbk; defrDoubleCbkFnType UnitsCbk; defrStringCbkFnType DividerCbk; defrStringCbkFnType BusBitCbk; defrSiteCbkFnType SiteCbk; defrSiteCbkFnType CanplaceCbk; defrSiteCbkFnType CannotOccupyCbk; defrIntegerCbkFnType ComponentStartCbk; defrVoidCbkFnType ComponentEndCbk; defrComponentCbkFnType ComponentCbk; defrComponentMaskShiftLayerCbkFnType ComponentMaskShiftLayerCbk; defrIntegerCbkFnType NetStartCbk; defrVoidCbkFnType NetEndCbk; defrNetCbkFnType NetCbk; defrStringCbkFnType NetNameCbk; defrStringCbkFnType NetSubnetNameCbk; defrStringCbkFnType NetNonDefaultRuleCbk; defrNetCbkFnType NetPartialPathCbk; defrPathCbkFnType PathCbk; defrDoubleCbkFnType VersionCbk; defrStringCbkFnType VersionStrCbk; defrStringCbkFnType PinExtCbk; defrStringCbkFnType ComponentExtCbk; defrStringCbkFnType ViaExtCbk; defrStringCbkFnType NetConnectionExtCbk; defrStringCbkFnType NetExtCbk; defrStringCbkFnType GroupExtCbk; defrStringCbkFnType ScanChainExtCbk; defrStringCbkFnType IoTimingsExtCbk; defrStringCbkFnType PartitionsExtCbk; defrStringCbkFnType HistoryCbk; defrBoxCbkFnType DieAreaCbk; defrPinCapCbkFnType PinCapCbk; defrPinCbkFnType PinCbk; defrIntegerCbkFnType StartPinsCbk; defrVoidCbkFnType PinEndCbk; defrIntegerCbkFnType DefaultCapCbk; defrRowCbkFnType RowCbk; defrTrackCbkFnType TrackCbk; defrGcellGridCbkFnType GcellGridCbk; defrIntegerCbkFnType ViaStartCbk; defrVoidCbkFnType ViaEndCbk; defrViaCbkFnType ViaCbk; defrIntegerCbkFnType RegionStartCbk; defrVoidCbkFnType RegionEndCbk; defrRegionCbkFnType RegionCbk; defrIntegerCbkFnType SNetStartCbk; defrVoidCbkFnType SNetEndCbk; defrNetCbkFnType SNetCbk; defrNetCbkFnType SNetPartialPathCbk; defrNetCbkFnType SNetWireCbk; defrIntegerCbkFnType GroupsStartCbk; defrVoidCbkFnType GroupsEndCbk; defrStringCbkFnType GroupNameCbk; defrStringCbkFnType GroupMemberCbk; defrGroupCbkFnType GroupCbk; defrIntegerCbkFnType AssertionsStartCbk; defrVoidCbkFnType AssertionsEndCbk; defrAssertionCbkFnType AssertionCbk; defrIntegerCbkFnType ConstraintsStartCbk; defrVoidCbkFnType ConstraintsEndCbk; defrAssertionCbkFnType ConstraintCbk; defrIntegerCbkFnType ScanchainsStartCbk; defrVoidCbkFnType ScanchainsEndCbk; defrScanchainCbkFnType ScanchainCbk; defrIntegerCbkFnType IOTimingsStartCbk; defrVoidCbkFnType IOTimingsEndCbk; defrIOTimingCbkFnType IOTimingCbk; defrIntegerCbkFnType FPCStartCbk; defrVoidCbkFnType FPCEndCbk; defrFPCCbkFnType FPCCbk; defrIntegerCbkFnType TimingDisablesStartCbk; defrVoidCbkFnType TimingDisablesEndCbk; defrTimingDisableCbkFnType TimingDisableCbk; defrIntegerCbkFnType PartitionsStartCbk; defrVoidCbkFnType PartitionsEndCbk; defrPartitionCbkFnType PartitionCbk; defrIntegerCbkFnType PinPropStartCbk; defrVoidCbkFnType PinPropEndCbk; defrPinPropCbkFnType PinPropCbk; defrIntegerCbkFnType CaseSensitiveCbk; defrIntegerCbkFnType BlockageStartCbk; defrVoidCbkFnType BlockageEndCbk; defrBlockageCbkFnType BlockageCbk; defrIntegerCbkFnType SlotStartCbk; defrVoidCbkFnType SlotEndCbk; defrSlotCbkFnType SlotCbk; defrIntegerCbkFnType FillStartCbk; defrVoidCbkFnType FillEndCbk; defrFillCbkFnType FillCbk; defrIntegerCbkFnType NonDefaultStartCbk; defrVoidCbkFnType NonDefaultEndCbk; defrNonDefaultCbkFnType NonDefaultCbk; defrIntegerCbkFnType StylesStartCbk; defrVoidCbkFnType StylesEndCbk; defrStylesCbkFnType StylesCbk; defrStringCbkFnType ExtensionCbk; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defrData.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013 - 2015, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: arakhman $ // $Revision: #6 $ // $Date: 2013/08/09 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #include #include #include #include #include "defrReader.hpp" #include "defrCallBacks.hpp" #include "defrSettings.hpp" #ifndef defrData_h #define defrData_h #define CURRENT_VERSION 5.8 #define RING_SIZE 10 #define IN_BUF_SIZE 16384 #define TOKEN_SIZE 4096 #define MSG_SIZE 100 BEGIN_LEFDEF_PARSER_NAMESPACE struct defCompareStrings { bool operator()(const std::string &lhs, const std::string &rhs) const { return std::strcmp(lhs.c_str(), rhs.c_str()) < 0; } }; typedef std::map defAliasMap; typedef std::map defDefineMap; typedef union { double dval ; int integer ; char * string ; int keyword ; // really just a nop struct defpoint pt; defTOKEN *tk; } YYSTYPE; #define YYSTYPE_IS_DECLARED class defrData { public: defrData(const defrCallbacks *pCallbacks, const defrSettings *pSettings, defrSession *pSession); ~defrData(); inline int defGetKeyword(const char* name, int *result); inline int defGetAlias(const std::string &name, std::string &result); inline int defGetDefine(const std::string &name, std::string &result); void reload_buffer(); int GETC(); void UNGETC(char ch); char* ringCopy(const char* string); int DefGetTokenFromStack(char *s); inline void print_lines(long long lines); const char * lines2str(long long lines); static inline void IncCurPos(char **curPos, char **buffer, int *bufferSize); int DefGetToken(char **buffer, int *bufferSize); static void uc_array(char *source, char *dest); void StoreAlias(); int defyylex(YYSTYPE *pYylval); int sublex(YYSTYPE *pYylval); int amper_lookup(YYSTYPE *pYylval, char *tkn); void defError(int msgNum, const char *s); void defyyerror(const char *s); void defInfo(int msgNum, const char *s); void defWarning(int msgNum, const char *s); void defiError(int check, int msgNum, const char* mess); const char *DEFCASE(const char* ch); void pathIsDone(int shield, int reset, int netOsnet, int *needCbk); const char *upperCase(const char* str); inline int checkErrors(); int validateMaskInput(int input, int warningIndex, int getWarningsIndex); int validateMaskShiftInput(const char* shiftMask, int warningIndex, int getWarningsIndex); static double convert_defname2num(char *versionName); static int numIsInt (char* volt); int defValidNum(int values); inline static const char *defkywd(int num); FILE* defrLog; char defPropDefType; // save the current type of the property char* ch; char* defMsg; char* deftoken; char* uc_token; char* last; char* magic; char* next; char* pv_deftoken; char* rowName; // to hold the rowName for message char* shieldName; // to hold the shieldNetName char* shiftBuf; char* warningMsg; double save_x; double save_y; double lVal; double rVal; int aOxide; // keep track for oxide int assertionWarnings; int bit_is_keyword; int bitsNum; // Scanchain Bits value int blockageWarnings; int by_is_keyword; int caseSensitiveWarnings; int componentWarnings; int constraintWarnings; int cover_is_keyword; int defIgnoreVersion; // ignore checking version number int defInvalidChar; int defMsgCnt; int defMsgPrinted; // number of msgs output so far int defPrintTokens; int defRetVal; int def_warnings; int defaultCapWarnings; int do_is_keyword; int dumb_mode; int errors; int fillWarnings; int first_buffer; int fixed_is_keyword; int gcellGridWarnings; int hasBlkLayerComp; // only 1 BLOCKAGE/LAYER/COMP int hasBlkLayerSpac; // only 1 BLOCKAGE/LAYER/SPACING int hasBlkLayerTypeComp; // SLOTS or FILLS int hasBlkPlaceComp; // only 1 BLOCKAGE/PLACEMENT/COMP int hasBlkPlaceTypeComp; // SOFT or PARTIAL int hasBusBit; // keep track BUSBITCHARS is in the file int hasDes; // keep track DESIGN is in the file int hasDivChar; // keep track DIVIDERCHAR is in the file int hasDoStep; int hasNameCase; // keep track NAMESCASESENSITIVE is in the file int hasOpenedDefLogFile; int hasPort; // keep track is port defined in a Pin int hasVer; // keep track VERSION is in the file int hasFatalError; // don't report errors after the file end. int iOTimingWarnings; int input_level; int mask_is_keyword; int mustjoin_is_keyword; int names_case_sensitive; // always true in 5.6 int needNPCbk; // if cbk for net path is needed int needSNPCbk; // if cbk for snet path is needed int netOsnet; // net = 1 & snet = 2 int netWarnings; int new_is_keyword; int nl_token; int no_num; int nonDefaultWarnings; int nondef_is_keyword; int ntokens; int orient_is_keyword; int pinExtWarnings; int pinWarnings; int real_num; int rect_is_keyword; int regTypeDef; // keep track that region type is defined int regionWarnings; int ringPlace; int routed_is_keyword; int rowWarnings; int sNetWarnings; int scanchainWarnings; int shield; // To identify if the path is shield for 5.3 int shiftBufLength; int specialWire_mask; int step_is_keyword; int stylesWarnings; int trackWarnings; int unitsWarnings; int versionWarnings; int viaRule; // keep track the viarule has called first int viaWarnings; int virtual_is_keyword; int deftokenLength; long long nlines; std::vector History_text; defAliasMap def_alias_set; defDefineMap def_defines_set; char* specialWire_routeStatus; char* specialWire_routeStatusName; char* specialWire_shapeType; double VersionNum; double xStep; double yStep; //defrParser vars. defiPath PathObj; defiProp Prop; defiSite Site; defiComponent Component; defiComponentMaskShiftLayer ComponentMaskShiftLayer; defiNet Net; defiPinCap PinCap; defiSite CannotOccupy; defiSite Canplace; defiBox DieArea; defiPin Pin; defiRow Row; defiTrack Track; defiGcellGrid GcellGrid; defiVia Via; defiRegion Region; defiGroup Group; defiAssertion Assertion; defiScanchain Scanchain; defiIOTiming IOTiming; defiFPC FPC; defiTimingDisable TimingDisable; defiPartition Partition; defiPinProp PinProp; defiBlockage Blockage; defiSlot Slot; defiFill Fill; defiNonDefault NonDefault; defiStyles Styles; defiGeometries Geometries; int doneDesign; // keep track if the Design is done parsing // Flags to control what happens int NeedPathData; defiSubnet* Subnet; int msgLimit[DEF_MSGS]; char buffer[IN_BUF_SIZE]; char* ring[RING_SIZE]; int ringSizes[RING_SIZE]; std::string stack[20]; /* the stack itself */ YYSTYPE yylval; const defrCallbacks *callbacks; const defrSettings *settings; defrSession *session; char lineBuffer[MSG_SIZE]; FILE* File; }; class defrContext { public: defrContext(int ownConf = 0); defrSettings *settings; defrCallbacks *callbacks; defrSession *session; defrData *data; int ownConfig; const char *init_call_func; }; int defrData::checkErrors() { if (errors > 20) { defError(6011, "Too many syntax errors have been reported."); errors = 0; return 1; } return 0; } END_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defrReader.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013-2016, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef DEFRREADER_H #define DEFRREADER_H #include #include "defiKRDefs.hpp" #include "defiDefs.hpp" #include "defiUser.hpp" #define DEF_MSGS 4013 #define CBMAX 150 // Number of callbacks. BEGIN_LEFDEF_PARSER_NAMESPACE // An enum describing all of the types of reader callbacks. typedef enum { defrUnspecifiedCbkType = 0, defrDesignStartCbkType, defrTechNameCbkType, defrPropCbkType, defrPropDefEndCbkType, defrPropDefStartCbkType, defrFloorPlanNameCbkType, defrArrayNameCbkType, defrUnitsCbkType, defrDividerCbkType, defrBusBitCbkType, defrSiteCbkType, defrComponentStartCbkType, defrComponentCbkType, defrComponentEndCbkType, defrNetStartCbkType, defrNetCbkType, defrNetNameCbkType, defrNetNonDefaultRuleCbkType, defrNetSubnetNameCbkType, defrNetEndCbkType, defrPathCbkType, defrVersionCbkType, defrVersionStrCbkType, defrComponentExtCbkType, defrPinExtCbkType, defrViaExtCbkType, defrNetConnectionExtCbkType, defrNetExtCbkType, defrGroupExtCbkType, defrScanChainExtCbkType, defrIoTimingsExtCbkType, defrPartitionsExtCbkType, defrHistoryCbkType, defrDieAreaCbkType, defrCanplaceCbkType, defrCannotOccupyCbkType, defrPinCapCbkType, defrDefaultCapCbkType, defrStartPinsCbkType, defrPinCbkType, defrPinEndCbkType, defrRowCbkType, defrTrackCbkType, defrGcellGridCbkType, defrViaStartCbkType, defrViaCbkType, defrViaEndCbkType, defrRegionStartCbkType, defrRegionCbkType, defrRegionEndCbkType, defrSNetStartCbkType, defrSNetCbkType, defrSNetPartialPathCbkType, defrSNetWireCbkType, defrSNetEndCbkType, defrGroupsStartCbkType, defrGroupNameCbkType, defrGroupMemberCbkType, defrGroupCbkType, defrGroupsEndCbkType, defrAssertionsStartCbkType, defrAssertionCbkType, defrAssertionsEndCbkType, defrConstraintsStartCbkType, defrConstraintCbkType, defrConstraintsEndCbkType, defrScanchainsStartCbkType, defrScanchainCbkType, defrScanchainsEndCbkType, defrIOTimingsStartCbkType, defrIOTimingCbkType, defrIOTimingsEndCbkType, defrFPCStartCbkType, defrFPCCbkType, defrFPCEndCbkType, defrTimingDisablesStartCbkType, defrTimingDisableCbkType, defrTimingDisablesEndCbkType, defrPartitionsStartCbkType, defrPartitionCbkType, defrPartitionsEndCbkType, defrPinPropStartCbkType, defrPinPropCbkType, defrPinPropEndCbkType, defrBlockageStartCbkType, defrBlockageCbkType, defrBlockageEndCbkType, defrSlotStartCbkType, defrSlotCbkType, defrSlotEndCbkType, defrFillStartCbkType, defrFillCbkType, defrFillEndCbkType, defrCaseSensitiveCbkType, defrNonDefaultStartCbkType, defrNonDefaultCbkType, defrNonDefaultEndCbkType, defrStylesStartCbkType, defrStylesCbkType, defrStylesEndCbkType, defrExtensionCbkType, // NEW CALLBACK - If you are creating a new callback, you must add // a unique item to this enum for each callback routine. When the // callback is called in def.y you have to supply this enum item // as an argument in the call. defrComponentMaskShiftLayerCbkType, defrDesignEndCbkType } defrCallbackType_e; // Declarations of function signatures for each type of callback. // These declarations are type-safe when compiling with ANSI C // or C++; you will only be able to register a function pointer // with the correct signature for a given type of callback. // // Each callback function is expected to return 0 if successful. // A non-zero return code will cause the reader to abort. // // The defrDesignStart and defrDesignEnd callback is only called once. // Other callbacks may be called multiple times, each time with a different // set of data. // // For each callback, the Def API will make the callback to the // function supplied by the client, which should either make a copy // of the Def object, or store the data in the client's own data structures. // The Def API will delete or reuse each object after making the callback, // so the client should not keep a pointer to it. // // All callbacks pass the user data pointer provided in defrRead() // or defrSetUserData() back to the client; this can be used by the // client to obtain access to the rest of the client's data structures. // // The user data pointer is obtained using defrGetUserData() immediately // prior to making each callback, so the client is free to change the // user data on the fly if necessary. // // Callbacks with the same signature are passed a callback type // parameter, which allows an application to write a single callback // function, register that function for multiple callbacks, then // switch based on the callback type to handle the appropriate type of // data. // A declaration of the signature of all callbacks that return nothing. typedef int (*defrVoidCbkFnType) (defrCallbackType_e, void* v, defiUserData); // A declaration of the signature of all callbacks that return a string. typedef int (*defrStringCbkFnType) (defrCallbackType_e, const char *string, defiUserData); // A declaration of the signature of all callbacks that return a integer. typedef int (*defrIntegerCbkFnType) (defrCallbackType_e, int number, defiUserData); // A declaration of the signature of all callbacks that return a double. typedef int (*defrDoubleCbkFnType) (defrCallbackType_e, double number, defiUserData); // A declaration of the signature of all callbacks that return a defiProp. typedef int (*defrPropCbkFnType) (defrCallbackType_e, defiProp *prop, defiUserData); // A declaration of the signature of all callbacks that return a defiSite. typedef int (*defrSiteCbkFnType) (defrCallbackType_e, defiSite *site, defiUserData); // A declaration of the signature of all callbacks that return a defComponent. typedef int (*defrComponentCbkFnType) (defrCallbackType_e, defiComponent *comp, defiUserData); // A declaration of the signature of all callbacks that return a defComponentMaskShiftLayer. typedef int (*defrComponentMaskShiftLayerCbkFnType) (defrCallbackType_e, defiComponentMaskShiftLayer *comp, defiUserData); // A declaration of the signature of all callbacks that return a defNet. typedef int (*defrNetCbkFnType) (defrCallbackType_e, defiNet *net, defiUserData); // A declaration of the signature of all callbacks that return a defPath. typedef int (*defrPathCbkFnType) (defrCallbackType_e, defiPath *path, defiUserData); // A declaration of the signature of all callbacks that return a defiBox. typedef int (*defrBoxCbkFnType) (defrCallbackType_e, defiBox *box, defiUserData); // A declaration of the signature of all callbacks that return a defiPinCap. typedef int (*defrPinCapCbkFnType) (defrCallbackType_e, defiPinCap *pincap, defiUserData); // A declaration of the signature of all callbacks that return a defiPin. typedef int (*defrPinCbkFnType) (defrCallbackType_e, defiPin *pin, defiUserData); // A declaration of the signature of all callbacks that return a defiRow. typedef int (*defrRowCbkFnType) (defrCallbackType_e, defiRow *row, defiUserData); // A declaration of the signature of all callbacks that return a defiTrack. typedef int (*defrTrackCbkFnType) (defrCallbackType_e, defiTrack *track, defiUserData); // A declaration of the signature of all callbacks that return a defiGcellGrid. typedef int (*defrGcellGridCbkFnType) (defrCallbackType_e, defiGcellGrid *grid, defiUserData); // A declaration of the signature of all callbacks that return a defiVia. typedef int (*defrViaCbkFnType) (defrCallbackType_e, defiVia *, defiUserData); // A declaration of the signature of all callbacks that return a defiRegion. typedef int (*defrRegionCbkFnType) (defrCallbackType_e, defiRegion *, defiUserData); // A declaration of the signature of all callbacks that return a defiGroup. typedef int (*defrGroupCbkFnType) (defrCallbackType_e, defiGroup *, defiUserData); // A declaration of the signature of all callbacks that return a defiAssertion. typedef int (*defrAssertionCbkFnType) (defrCallbackType_e, defiAssertion *, defiUserData); // A declaration of the signature of all callbacks that return a defiScanChain. typedef int (*defrScanchainCbkFnType) (defrCallbackType_e, defiScanchain *, defiUserData); // A declaration of the signature of all callbacks that return a defiIOTiming. typedef int (*defrIOTimingCbkFnType) (defrCallbackType_e, defiIOTiming *, defiUserData); // A declaration of the signature of all callbacks that return a defiFPC. typedef int (*defrFPCCbkFnType) (defrCallbackType_e, defiFPC *, defiUserData); // A declaration of the signature of all callbacks that return a defiTimingDisable. typedef int (*defrTimingDisableCbkFnType) (defrCallbackType_e, defiTimingDisable *, defiUserData); // A declaration of the signature of all callbacks that return a defiPartition. typedef int (*defrPartitionCbkFnType) (defrCallbackType_e, defiPartition *, defiUserData); // A declaration of the signature of all callbacks that return a defiPinProp. typedef int (*defrPinPropCbkFnType) (defrCallbackType_e, defiPinProp *, defiUserData); // A declaration of the signature of all callbacks that return a defiBlockage. typedef int (*defrBlockageCbkFnType) (defrCallbackType_e, defiBlockage *, defiUserData); // A declaration of the signature of all callbacks that return a defiSlot. typedef int (*defrSlotCbkFnType) (defrCallbackType_e, defiSlot *, defiUserData); // A declaration of the signature of all callbacks that return a defiFill. typedef int (*defrFillCbkFnType) (defrCallbackType_e, defiFill *, defiUserData); // A declaration of the signature of all callbacks that return a defiNonDefault. typedef int (*defrNonDefaultCbkFnType) (defrCallbackType_e, defiNonDefault *, defiUserData); // A declaration of the signature of all callbacks that return a defiStyles. typedef int (*defrStylesCbkFnType) (defrCallbackType_e, defiStyles *, defiUserData); // NEW CALLBACK - Each callback must return user data, enum, and // OUR-DATA item. We must define a callback function type for // each type of OUR-DATA. Some routines return a string, some // return an integer, and some return a pointer to a class. // If you create a new class, then you must create a new function // type here to return that class to the user. // The reader initialization. Must be called before defrRead(). extern int defrInit (); extern int defrInitSession (int startSession = 1); // obsoleted now. extern int defrReset (); //Sets all parser memory into init state. extern int defrClear(); // Change the comment character in the DEF file. The default // is '#' extern void defrSetCommentChar (char c); // Functions to call to set specific actions in the parser. extern void defrSetAddPathToNet (); extern void defrSetAllowComponentNets (); extern int defrGetAllowComponentNets (); extern void defrSetCaseSensitivity (int caseSense); // Functions to keep track of callbacks that the user did not // supply. Normally all parts of the DEF file that the user // does not supply a callback for will be ignored. These // routines tell the parser count the DEF constructs that are // present in the input file, but did not trigger a callback. // This should help you find any "important" DEF constructs that // you are ignoring. extern void defrSetRegisterUnusedCallbacks (); extern void defrPrintUnusedCallbacks (FILE* log); // Obsoleted now. extern int defrReleaseNResetMemory (); // This function clear session data. extern void defrClearSession(); // The main reader function. // The file should already be opened. This requirement allows // the reader to be used with stdin or a pipe. The file name // is only used for error messages. extern int defrRead (FILE *file, const char *fileName, defiUserData userData, int case_sensitive); // Set/get the client-provided user data. defi doesn't look at // this data at all, it simply passes the opaque defiUserData pointer // back to the application with each callback. The client can // change the data at any time, and it will take effect on the // next callback. The defi reader and writer maintain separate // user data pointers. extern void defrSetUserData (defiUserData); extern defiUserData defrGetUserData (); // Functions to call to register a callback function or get the function //pointer after it has been registered. // // Register one function for all callbacks with the same signature extern void defrSetArrayNameCbk (defrStringCbkFnType); extern void defrSetAssertionCbk (defrAssertionCbkFnType); extern void defrSetAssertionsStartCbk (defrIntegerCbkFnType); extern void defrSetAssertionsEndCbk (defrVoidCbkFnType); extern void defrSetBlockageCbk (defrBlockageCbkFnType); extern void defrSetBlockageStartCbk (defrIntegerCbkFnType); extern void defrSetBlockageEndCbk (defrVoidCbkFnType); extern void defrSetBusBitCbk (defrStringCbkFnType); extern void defrSetCannotOccupyCbk (defrSiteCbkFnType); extern void defrSetCanplaceCbk (defrSiteCbkFnType); extern void defrSetCaseSensitiveCbk (defrIntegerCbkFnType); extern void defrSetComponentCbk (defrComponentCbkFnType); extern void defrSetComponentExtCbk (defrStringCbkFnType); extern void defrSetComponentStartCbk (defrIntegerCbkFnType); extern void defrSetComponentEndCbk (defrVoidCbkFnType); extern void defrSetConstraintCbk (defrAssertionCbkFnType); extern void defrSetConstraintsStartCbk (defrIntegerCbkFnType); extern void defrSetConstraintsEndCbk (defrVoidCbkFnType); extern void defrSetDefaultCapCbk (defrIntegerCbkFnType); extern void defrSetDesignCbk (defrStringCbkFnType); extern void defrSetDesignEndCbk (defrVoidCbkFnType); extern void defrSetDieAreaCbk (defrBoxCbkFnType); extern void defrSetDividerCbk (defrStringCbkFnType); extern void defrSetExtensionCbk (defrStringCbkFnType); extern void defrSetFillCbk (defrFillCbkFnType); extern void defrSetFillStartCbk (defrIntegerCbkFnType); extern void defrSetFillEndCbk (defrVoidCbkFnType); extern void defrSetFPCCbk (defrFPCCbkFnType); extern void defrSetFPCStartCbk (defrIntegerCbkFnType); extern void defrSetFPCEndCbk (defrVoidCbkFnType); extern void defrSetFloorPlanNameCbk (defrStringCbkFnType); extern void defrSetGcellGridCbk (defrGcellGridCbkFnType); extern void defrSetGroupNameCbk (defrStringCbkFnType); extern void defrSetGroupMemberCbk (defrStringCbkFnType); extern void defrSetComponentMaskShiftLayerCbk (defrComponentMaskShiftLayerCbkFnType); extern void defrSetGroupCbk (defrGroupCbkFnType); extern void defrSetGroupExtCbk (defrStringCbkFnType); extern void defrSetGroupsStartCbk (defrIntegerCbkFnType); extern void defrSetGroupsEndCbk (defrVoidCbkFnType); extern void defrSetHistoryCbk (defrStringCbkFnType); extern void defrSetIOTimingCbk (defrIOTimingCbkFnType); extern void defrSetIOTimingsStartCbk (defrIntegerCbkFnType); extern void defrSetIOTimingsEndCbk (defrVoidCbkFnType); extern void defrSetIoTimingsExtCbk (defrStringCbkFnType); extern void defrSetNetCbk (defrNetCbkFnType); extern void defrSetNetNameCbk (defrStringCbkFnType); extern void defrSetNetNonDefaultRuleCbk (defrStringCbkFnType); extern void defrSetNetConnectionExtCbk (defrStringCbkFnType); extern void defrSetNetExtCbk (defrStringCbkFnType); extern void defrSetNetPartialPathCbk (defrNetCbkFnType); extern void defrSetNetSubnetNameCbk (defrStringCbkFnType); extern void defrSetNetStartCbk (defrIntegerCbkFnType); extern void defrSetNetEndCbk (defrVoidCbkFnType); extern void defrSetNonDefaultCbk (defrNonDefaultCbkFnType); extern void defrSetNonDefaultStartCbk (defrIntegerCbkFnType); extern void defrSetNonDefaultEndCbk (defrVoidCbkFnType); extern void defrSetPartitionCbk (defrPartitionCbkFnType); extern void defrSetPartitionsExtCbk (defrStringCbkFnType); extern void defrSetPartitionsStartCbk (defrIntegerCbkFnType); extern void defrSetPartitionsEndCbk (defrVoidCbkFnType); extern void defrSetPathCbk (defrPathCbkFnType); extern void defrSetPinCapCbk (defrPinCapCbkFnType); extern void defrSetPinCbk (defrPinCbkFnType); extern void defrSetPinExtCbk (defrStringCbkFnType); extern void defrSetPinPropCbk (defrPinPropCbkFnType); extern void defrSetPinPropStartCbk (defrIntegerCbkFnType); extern void defrSetPinPropEndCbk (defrVoidCbkFnType); extern void defrSetPropCbk (defrPropCbkFnType); extern void defrSetPropDefEndCbk (defrVoidCbkFnType); extern void defrSetPropDefStartCbk (defrVoidCbkFnType); extern void defrSetRegionCbk (defrRegionCbkFnType); extern void defrSetRegionStartCbk (defrIntegerCbkFnType); extern void defrSetRegionEndCbk (defrVoidCbkFnType); extern void defrSetRowCbk (defrRowCbkFnType); extern void defrSetSNetCbk (defrNetCbkFnType); extern void defrSetSNetStartCbk (defrIntegerCbkFnType); extern void defrSetSNetEndCbk (defrVoidCbkFnType); extern void defrSetSNetPartialPathCbk (defrNetCbkFnType); extern void defrSetSNetWireCbk (defrNetCbkFnType); extern void defrSetScanChainExtCbk (defrStringCbkFnType); extern void defrSetScanchainCbk (defrScanchainCbkFnType); extern void defrSetScanchainsStartCbk (defrIntegerCbkFnType); extern void defrSetScanchainsEndCbk (defrVoidCbkFnType); extern void defrSetSiteCbk (defrSiteCbkFnType); extern void defrSetSlotCbk (defrSlotCbkFnType); extern void defrSetSlotStartCbk (defrIntegerCbkFnType); extern void defrSetSlotEndCbk (defrVoidCbkFnType); extern void defrSetStartPinsCbk (defrIntegerCbkFnType); extern void defrSetStylesCbk (defrStylesCbkFnType); extern void defrSetStylesStartCbk (defrIntegerCbkFnType); extern void defrSetStylesEndCbk (defrVoidCbkFnType); extern void defrSetPinEndCbk (defrVoidCbkFnType); extern void defrSetTechnologyCbk (defrStringCbkFnType); extern void defrSetTimingDisableCbk (defrTimingDisableCbkFnType); extern void defrSetTimingDisablesStartCbk (defrIntegerCbkFnType); extern void defrSetTimingDisablesEndCbk (defrVoidCbkFnType); extern void defrSetTrackCbk (defrTrackCbkFnType); extern void defrSetUnitsCbk (defrDoubleCbkFnType); extern void defrSetVersionCbk (defrDoubleCbkFnType); extern void defrSetVersionStrCbk (defrStringCbkFnType); extern void defrSetViaCbk (defrViaCbkFnType); extern void defrSetViaExtCbk (defrStringCbkFnType); extern void defrSetViaStartCbk (defrIntegerCbkFnType); extern void defrSetViaEndCbk (defrVoidCbkFnType); // NEW CALLBACK - For each new callback you create, you must // create a routine that allows the user to set it. Add the // setting routines here. //Set all of the callbacks that have not yet been set to the following //function. This is especially useful if you want to check to see //if you forgot anything. extern void defrUnsetCallbacks (); // Functions to call to unregister a callback function. extern void defrUnsetArrayNameCbk (); extern void defrUnsetAssertionCbk (); extern void defrUnsetAssertionsStartCbk (); extern void defrUnsetAssertionsEndCbk (); extern void defrUnsetBlockageCbk (); extern void defrUnsetBlockageStartCbk (); extern void defrUnsetBlockageEndCbk (); extern void defrUnsetBusBitCbk (); extern void defrUnsetCannotOccupyCbk (); extern void defrUnsetCanplaceCbk (); extern void defrUnsetCaseSensitiveCbk (); extern void defrUnsetComponentCbk (); extern void defrUnsetComponentExtCbk (); extern void defrUnsetComponentStartCbk (); extern void defrUnsetComponentEndCbk (); extern void defrUnsetConstraintCbk (); extern void defrUnsetConstraintsStartCbk (); extern void defrUnsetConstraintsEndCbk (); extern void defrUnsetDefaultCapCbk (); extern void defrUnsetDesignCbk (); extern void defrUnsetDesignEndCbk (); extern void defrUnsetDieAreaCbk (); extern void defrUnsetDividerCbk (); extern void defrUnsetExtensionCbk (); extern void defrUnsetFillCbk (); extern void defrUnsetFillStartCbk (); extern void defrUnsetFillEndCbk (); extern void defrUnsetFPCCbk (); extern void defrUnsetFPCStartCbk (); extern void defrUnsetFPCEndCbk (); extern void defrUnsetFloorPlanNameCbk (); extern void defrUnsetGcellGridCbk (); extern void defrUnsetGroupCbk (); extern void defrUnsetGroupExtCbk (); extern void defrUnsetGroupMemberCbk (); extern void defrUnsetComponentMaskShiftLayerCbk (); extern void defrUnsetGroupNameCbk (); extern void defrUnsetGroupsStartCbk (); extern void defrUnsetGroupsEndCbk (); extern void defrUnsetHistoryCbk (); extern void defrUnsetIOTimingCbk (); extern void defrUnsetIOTimingsStartCbk (); extern void defrUnsetIOTimingsEndCbk (); extern void defrUnsetIOTimingsExtCbk (); extern void defrUnsetNetCbk (); extern void defrUnsetNetNameCbk (); extern void defrUnsetNetNonDefaultRuleCbk (); extern void defrUnsetNetConnectionExtCbk (); extern void defrUnsetNetExtCbk (); extern void defrUnsetNetPartialPathCbk (); extern void defrUnsetNetSubnetNameCbk (); extern void defrUnsetNetStartCbk (); extern void defrUnsetNetEndCbk (); extern void defrUnsetNonDefaultCbk (); extern void defrUnsetNonDefaultStartCbk (); extern void defrUnsetNonDefaultEndCbk (); extern void defrUnsetPartitionCbk (); extern void defrUnsetPartitionsExtCbk (); extern void defrUnsetPartitionsStartCbk (); extern void defrUnsetPartitionsEndCbk (); extern void defrUnsetPathCbk (); extern void defrUnsetPinCapCbk (); extern void defrUnsetPinCbk (); extern void defrUnsetPinEndCbk (); extern void defrUnsetPinExtCbk (); extern void defrUnsetPinPropCbk (); extern void defrUnsetPinPropStartCbk (); extern void defrUnsetPinPropEndCbk (); extern void defrUnsetPropCbk (); extern void defrUnsetPropDefEndCbk (); extern void defrUnsetPropDefStartCbk (); extern void defrUnsetRegionCbk (); extern void defrUnsetRegionStartCbk (); extern void defrUnsetRegionEndCbk (); extern void defrUnsetRowCbk (); extern void defrUnsetScanChainExtCbk (); extern void defrUnsetScanchainCbk (); extern void defrUnsetScanchainsStartCbk (); extern void defrUnsetScanchainsEndCbk (); extern void defrUnsetSiteCbk (); extern void defrUnsetSlotCbk (); extern void defrUnsetSlotStartCbk (); extern void defrUnsetSlotEndCbk (); extern void defrUnsetSNetWireCbk (); extern void defrUnsetSNetCbk (); extern void defrUnsetSNetStartCbk (); extern void defrUnsetSNetEndCbk (); extern void defrUnsetSNetPartialPathCbk (); extern void defrUnsetStartPinsCbk (); extern void defrUnsetStylesCbk (); extern void defrUnsetStylesStartCbk (); extern void defrUnsetStylesEndCbk (); extern void defrUnsetTechnologyCbk (); extern void defrUnsetTimingDisableCbk (); extern void defrUnsetTimingDisablesStartCbk (); extern void defrUnsetTimingDisablesEndCbk (); extern void defrUnsetTrackCbk (); extern void defrUnsetUnitsCbk (); extern void defrUnsetVersionCbk (); extern void defrUnsetVersionStrCbk (); extern void defrUnsetViaCbk (); extern void defrUnsetViaExtCbk (); extern void defrUnsetViaStartCbk (); extern void defrUnsetViaEndCbk (); // Routine to set all unused callbacks. This is useful for checking //to see if you missed something. extern void defrSetUnusedCallbacks (defrVoidCbkFnType func); // Return the current line number in the input file. extern int defrLineNumber (); extern long long defrLongLineNumber (); // Routine to set the message logging routine for errors #ifndef DEFI_LOG_FUNCTION typedef void (*DEFI_LOG_FUNCTION) (const char*); #endif extern void defrSetLogFunction(DEFI_LOG_FUNCTION); // Routine to set the message logging routine for warnings #ifndef DEFI_WARNING_LOG_FUNCTION typedef void (*DEFI_WARNING_LOG_FUNCTION) (const char*); #endif extern void defrSetWarningLogFunction(DEFI_WARNING_LOG_FUNCTION); // Routine to set the message logging routine for errors // Used in re-enterable environment. #ifndef DEFI_LOG_FUNCTION typedef void (*DEFI_CONTEXT_LOG_FUNCTION) (defiUserData userData, const char*); #endif extern void defrSetContextLogFunction(DEFI_CONTEXT_LOG_FUNCTION); // Routine to set the message logging routine for warnings // Used in re-enterable environment. #ifndef DEFI_WARNING_LOG_FUNCTION typedef void (*DEFI_CONTEXT_WARNING_LOG_FUNCTION) (defiUserData userData, const char*); #endif extern void defrSetContextWarningLogFunction(DEFI_CONTEXT_WARNING_LOG_FUNCTION); // Routine to set the user defined malloc routine typedef void* (*DEFI_MALLOC_FUNCTION) (size_t); extern void defrSetMallocFunction(DEFI_MALLOC_FUNCTION); // Routine to set the user defined realloc routine typedef void* (*DEFI_REALLOC_FUNCTION) (void*, size_t); extern void defrSetReallocFunction(DEFI_REALLOC_FUNCTION); // Routine to set the user defined free routine typedef void (*DEFI_FREE_FUNCTION) (void *); extern void defrSetFreeFunction(DEFI_FREE_FUNCTION); // Routine to set the line number of the file that is parsing routine (takes int) typedef void (*DEFI_LINE_NUMBER_FUNCTION) (int); extern void defrSetLineNumberFunction(DEFI_LINE_NUMBER_FUNCTION); // Routine to set the line number of the file that is parsing routine (takes long long) typedef void (*DEFI_LONG_LINE_NUMBER_FUNCTION) (long long); extern void defrSetLongLineNumberFunction(DEFI_LONG_LINE_NUMBER_FUNCTION); // Routine to set the line number of the file that is parsing routine (takes int) // Used in re-enterable environment. typedef void (*DEFI_CONTEXT_LINE_NUMBER_FUNCTION) (defiUserData userData, int); extern void defrSetContextLineNumberFunction(DEFI_CONTEXT_LINE_NUMBER_FUNCTION); // Routine to set the line number of the file that is parsing routine (takes long long // Used in re-enterable environment. typedef void (*DEFI_CONTEXT_LONG_LINE_NUMBER_FUNCTION) (defiUserData userData, long long); extern void defrSetContextLongLineNumberFunction(DEFI_CONTEXT_LONG_LINE_NUMBER_FUNCTION); // Set the number of lines before calling the line function callback routine // Default is 10000 extern void defrSetDeltaNumberLines (int); // Routine to set the read function typedef size_t (*DEFI_READ_FUNCTION) (FILE*, char*, size_t); extern void defrSetReadFunction(DEFI_READ_FUNCTION); extern void defrUnsetReadFunction (); // Routine to set the defrWarning.log to open as append instead for write // New in 5.7 extern void defrSetOpenLogFileAppend (); extern void defrUnsetOpenLogFileAppend (); // Routine to set the magic comment found routine typedef void (*DEFI_MAGIC_COMMENT_FOUND_FUNCTION) (); extern void defrSetMagicCommentFoundFunction(DEFI_MAGIC_COMMENT_FOUND_FUNCTION); // Routine to set the magic comment string extern void defrSetMagicCommentString(char *); // Routine to disable string property value process, default it will process // the value string extern void defrDisablePropStrProcess (); // Testing purposes only extern void defrSetNLines(long long n); // Routine to set the max number of warnings for a perticular section extern void defrSetAssertionWarnings(int warn); extern void defrSetBlockageWarnings(int warn); extern void defrSetCaseSensitiveWarnings(int warn); extern void defrSetComponentWarnings(int warn); extern void defrSetConstraintWarnings(int warn); extern void defrSetDefaultCapWarnings(int warn); extern void defrSetGcellGridWarnings(int warn); extern void defrSetIOTimingWarnings(int warn); extern void defrSetNetWarnings(int warn); extern void defrSetNonDefaultWarnings(int warn); extern void defrSetPinExtWarnings(int warn); extern void defrSetPinWarnings(int warn); extern void defrSetRegionWarnings(int warn); extern void defrSetRowWarnings(int warn); extern void defrSetScanchainWarnings(int warn); extern void defrSetSNetWarnings(int warn); extern void defrSetStylesWarnings(int warn); extern void defrSetTrackWarnings(int warn); extern void defrSetUnitsWarnings(int warn); extern void defrSetVersionWarnings(int warn); extern void defrSetViaWarnings(int warn); // Handling output messages extern void defrDisableParserMsgs(int nMsg, int* msgs); extern void defrEnableParserMsgs(int nMsg, int* msgs); extern void defrEnableAllMsgs(); extern void defrSetTotalMsgLimit(int totNumMsgs); extern void defrSetLimitPerMsg(int msgId, int numMsg); // Return codes for the user callbacks. //The user should return one of these values. #define PARSE_OK 0 // continue parsing #define STOP_PARSE 1 // stop parsing with no error message #define PARSE_ERROR 2 // stop parsing, print an error message // Add this alias to the list for the parser extern void defrAddAlias (const char* key, const char* value, int marked); END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defrSettings.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013-2014, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: arakhman $ // $Revision: #6 $ // $Date: 2013/08/09 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef defrSettings_h #define defrSettings_h #include "defrReader.hpp" #include #include #include #define DEF_DEBUG_IDS 100 BEGIN_LEFDEF_PARSER_NAMESPACE struct defCompareCStrings { bool operator()(const char* lhs, const char* rhs) const { return std::strcmp(lhs, rhs) < 0; } }; typedef std::map defKeywordMap; class defrSettings { public: defrSettings(); void init_symbol_table(); defKeywordMap Keyword_set; int defiDeltaNumberLines; //////////////////////////////////// // // Flags to control number of warnings to print out, max will be 999 // //////////////////////////////////// int AssertionWarnings; int BlockageWarnings; int CaseSensitiveWarnings; int ComponentWarnings; int ConstraintWarnings; int DefaultCapWarnings; int FillWarnings; int GcellGridWarnings; int IOTimingWarnings; int LogFileAppend; int NetWarnings; int NonDefaultWarnings; int PinExtWarnings; int PinWarnings; int RegionWarnings; int RowWarnings; int TrackWarnings; int ScanchainWarnings; int SNetWarnings; int StylesWarnings; int UnitsWarnings; int VersionWarnings; int ViaWarnings; int nDDMsgs; int* disableDMsgs; int totalDefMsgLimit; // to save the user set total msg limit to output int AddPathToNet; int AllowComponentNets; char CommentChar; int DisPropStrProcess; int reader_case_sensitive_set; DEFI_READ_FUNCTION ReadFunction; DEFI_LOG_FUNCTION ErrorLogFunction; DEFI_WARNING_LOG_FUNCTION WarningLogFunction; DEFI_CONTEXT_LOG_FUNCTION ContextErrorLogFunction; DEFI_CONTEXT_WARNING_LOG_FUNCTION ContextWarningLogFunction; DEFI_MAGIC_COMMENT_FOUND_FUNCTION MagicCommentFoundFunction; DEFI_MALLOC_FUNCTION MallocFunction; DEFI_REALLOC_FUNCTION ReallocFunction; DEFI_FREE_FUNCTION FreeFunction; DEFI_LINE_NUMBER_FUNCTION LineNumberFunction; DEFI_LONG_LINE_NUMBER_FUNCTION LongLineNumberFunction; DEFI_CONTEXT_LINE_NUMBER_FUNCTION ContextLineNumberFunction; DEFI_CONTEXT_LONG_LINE_NUMBER_FUNCTION ContextLongLineNumberFunction; int UnusedCallbacks[CBMAX]; int MsgLimit[DEF_MSGS]; }; class defrSession { public: defrSession(); char* FileName; int reader_case_sensitive; defiUserData UserData; defiPropType CompProp; defiPropType CompPinProp; defiPropType DesignProp; defiPropType GroupProp; defiPropType NDefProp; defiPropType NetProp; defiPropType RegionProp; defiPropType RowProp; defiPropType SNetProp; }; END_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defwWriter.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef DEFW_WRITER_H #define DEFW_WRITER_H #include #include #include "defiKRDefs.hpp" #include "defiDefs.hpp" #include "defiUser.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE /* Return codes for writing functions: */ #define DEFW_OK 0 #define DEFW_UNINITIALIZED 1 #define DEFW_BAD_ORDER 2 #define DEFW_BAD_DATA 3 #define DEFW_ALREADY_DEFINED 4 #define DEFW_WRONG_VERSION 5 #define DEFW_OBSOLETE 6 #define DEFW_TOO_MANY_STMS 7 // the number defined at the beginning of the // section is smaller than the actual number // of statements defined in that section /* orient 0 = N 1 = W 2 = S 3 = E 4 = FN 5 = FW 6 = FS 7 = FE */ /* This routine will write a new line */ extern int defwNewLine(); /* The DEF writer initialization. Must be called first. * Either this routine or defwInitCbk should be call only. * Can't call both routines in one program. * This routine is for user who does not want to use the callback machanism. * Returns 0 if successful. */ extern int defwInit ( FILE* f, int vers1, int version2, const char* caseSensitive, /* NAMESCASESENSITIVE */ const char* dividerChar, /* DIVIDERCHAR */ const char* busBitChars, /* BUSBITCHARS */ const char* designName, /* DESIGN */ const char* technology, /* optional(NULL) - TECHNOLOGY */ const char* array, /* optional(NULL) - ARRAYNAME */ const char* floorplan, /* optional(NULL) - FLOORPLAN */ double units ); /* optional (set to -1 to ignore) */ /* The DEF writer initialization. Must be called first. * Either this routine or defwInit should be call only. * Can't call both routines in one program. * This routine is for user who choose to use the callback machanism. * If user uses the callback for the writer, they need to provide * callbacks for Version, NamesCaseSensitive, BusBitChars and DividerChar. * These sections are required by the def. If any of these callbacks * are missing, defaults will be used. * Returns 0 if successful. */ extern int defwInitCbk (FILE* f); /* This routine must be called after the defwInit. * This routine is required. * Returns 0 if successful. * The routine can be called only once. */ extern int defwVersion (int vers1, int vers2); /* This routine must be called after the defwInit. * This routine is required. * Returns 0 if successful. * The routine can be called only once. */ extern int defwCaseSensitive ( const char* caseSensitive ); /* This routine must be called after the defwInit. * This routine is required. * Returns 0 if successful. * The routine can be called only once. */ extern int defwBusBitChars ( const char* busBitChars ); /* This routine must be called after the defwInit. * This routine is required. * Returns 0 if successful. * The routine can be called only once. */ extern int defwDividerChar ( const char* dividerChar ); /* This routine must be called after the defwInit. * This routine is required. * Returns 0 if successful. * The routine can be called only once. */ extern int defwDesignName ( const char* name ); /* This routine must be called after the defwInit. * This routine is optional. * Returns 0 if successful. * The routine can be called only once. */ extern int defwTechnology ( const char* technology ); /* This routine must be called after the defwInit. * This routine is optional. * Returns 0 if successful. * The routine can be called only once. */ extern int defwArray ( const char* array ); /* This routine must be called after the defwInit. * This routine is optional. * Returns 0 if successful. * The routine can be called only once. */ extern int defwFloorplan ( const char* floorplan ); /* This routine must be called after the defwInit. * This routine is optional. * Returns 0 if successful. * The routine can be called only once. */ extern int defwUnits ( int units ); /* This routine must be called after the defwInit. * This routine is optional. * Returns 0 if successful. * The routine can be called 0 to many times. */ extern int defwHistory ( const char* string ); /* This routine must be called after the history routines (if any). * This routine is optional. * Returns 0 if successful. * The routine can be called only once. */ extern int defwStartPropDef ( void ); /* This routine must be called after defwStartPropDef. * This routine can be called multiple times. * It adds integer property definition to the statement. * Returns 0 if successfull. * The objType can be LIBRARY or VIA or MACRO or PIN. */ extern int defwIntPropDef( const char* objType, // LIBRARY | LAYER | VIA | VIARULE | // NONDEFAULTRULE | MACRO | PIN const char* propName, double leftRange, /* optional(0) - RANGE */ double rightRange, /* optional(0) */ int propValue); /* optional(NULL) */ /* This routine must be called after defwStartPropDef. * This routine can be called multiple times. * It adds real property definition to the statement. * Returns 0 if successfull. * The objType can be LIBRARY or VIA or MACRO or PIN. */ extern int defwRealPropDef( const char* objType, // LIBRARY | LAYER | VIA | VIARULE | // NONDEFAULTRULE | MACRO | PIN const char* propName, double leftRange, /* optional(0) - RANGE */ double rightRange, /* optional(0) */ double propValue); /* optional(NULL) */ /* This routine must be called after defwStartPropDef. * This routine can be called multiple times. * It adds string property definition to the statement. * Returns 0 if successfull. * The objType can be LIBRARY or VIA or MACRO or PIN. */ extern int defwStringPropDef( const char* objType, // LIBRARY | LAYER | VIA | VIARULE | // NONDEFAULTRULE | MACRO | PIN const char* propName, double leftRange, /* optional(0) - RANGE */ double rightRange, /* optional(0) */ const char* propValue); /* optional(NULL) */ /* This routine must be called after all the properties have been * added to the file. * If you called defwPropertyDefinitions then this routine is NOT optional. * Returns 0 if successful. * The routine can be called only once. */ extern int defwEndPropDef ( void ); /* This routine can be called after defwRow, defwRegion, defwComponent, * defwPin, defwSpecialNet, defwNet, and defwGroup * This routine is optional, it adds string property to the statement. * Returns 0 if successful. * This routine can be called 0 to many times */ extern int defwStringProperty(const char* propName, const char* propValue); /* This routine can be called after defwRow, defwRegion, defwComponent, * defwPin, defwSpecialNet, defwNet, and defwGroup * This routine is optional, it adds real property to the statement. * Returns 0 if successful. * This routine can be called 0 to many times */ extern int defwRealProperty(const char* propName, double propValue); /* This routine can be called after defwRow, defwRegion, defwComponent, * defwPin, defwSpecialNet, defwNet, and defwGroup * This routine is optional, it adds int property to the statement. * Returns 0 if successful. * This routine can be called 0 to many times */ extern int defwIntProperty(const char* propName, int propValue); /* This routine must be called after the property definitions (if any). * This routine is optional. * Returns 0 if successful. * The routine can be called only once. */ extern int defwDieArea ( int xl, /* point1 - x */ int yl, /* point1 - y */ int xh, /* point2 - x */ int yh ); /* point2 - y */ /* This routine must be called after the property definitions (if any). * This routine is optional. * This routine is the same as defwDieArea, but accept more than 2 points * This is a 5.6 syntax * Returns 0 if successful. * The routine can be called only once. */ extern int defwDieAreaList ( int num_points, /* number of points on list */ int* xl, /* all the x points */ int* yh); /* all the y points */ /* This routine must be called after the Die Area (if any). * This routine is optional. * Returns 0 if successful. * The integer "orient" and operation of the do is explained in * the documentation. * In 5.6, the DO syntax is optional and the STEP syntax is optional in DO */ extern int defwRow ( const char* rowName, const char* rowType, int x_orig, int y_orig, int orient, int do_count, /* optional (0) */ int do_increment, /* optional (0) */ int xstep, /* optional (0) */ int ystep); /* optional (0) */ /* This routine must be called after the Die Area (if any). * This routine is optional. * Returns 0 if successful. * This routine is the same as defwRow, excpet orient is a char* */ extern int defwRowStr ( const char* rowName, const char* rowType, int x_orig, int y_orig, const char* orient, int do_count, /* optional (0) */ int do_increment, /* optional (0) */ int xstep, /* optional (0) */ int ystep); /* optional (0) */ /* This routine must be called after the defwRow (if any). * This routine is optional. * Returns 0 if successful. * The operation of the do is explained in the documentation. */ extern int defwTracks ( const char* master, /* X | Y */ int doStart, /* start */ int doCount, /* numTracks */ int doStep, /* space */ int numLayers, /* number of layers */ const char** layers, /* list of layers */ int mask = 0, /* optional */ int sameMask = 0); /* optional */ /* This routine must be called after the defwTracks (if any). * This routine is optional. * Returns 0 if successful. * The operation of the do is explained in the documentation. */ extern int defwGcellGrid ( const char* master, /* X | Y */ int doStart, /* start */ int doCount, /* numColumns | numRows */ int doStep); /* space */ /* This routine must be called after the defwTracks (if any). * This section of routines is optional. * Returns 0 if successful. * The routine starts the default capacitance section. All of the * capacitances must follow. * The count is the number of defwDefaultCap calls to follow. * The routine can be called only once. * This api is obsolete in 5.4. */ extern int defwStartDefaultCap ( int count ); /* This routine is called once for each default cap. The calls must * be preceeded by a call to defwStartDefaultCap and must be * terminated by a call to defwEndDefaultCap. * Returns 0 if successful. * This api is obsolete in 5.4. */ extern int defwDefaultCap ( int pins, /* MINPINS */ double cap); /* WIRECAP */ /* This routine must be called after the defwDefaultCap calls (if any). * Returns 0 if successful. * If the count in StartDefaultCap is not the same as the number of * calls to DefaultCap then DEFW_BAD_DATA will return returned. * The routine can be called only once. * This api is obsolete in 5.4. */ extern int defwEndDefaultCap ( void ); /* This routine must be called after the defwDefaultCap calls (if any). * The operation of the do is explained in the documentation. * This routine is optional. * Returns 0 if successful. * The routine can be called many times. */ extern int defwCanPlace(const char* master, /* sitename */ int xOrig, int yOrig, int orient, /* 0 to 7 */ int doCnt, /* numX */ int doInc, /* numY */ int xStep, /* spaceX */ int yStep); /* spaceY */ /* This routine must be called after the defwDefaultCap calls (if any). * The operation of the do is explained in the documentation. * This routine is optional. * Returns 0 if successful. * The routine can be called many times. * This routine is the same as defwCanPlace, except orient is a char* */ extern int defwCanPlaceStr(const char* master, /* sitename */ int xOrig, int yOrig, const char* orient, /* 0 to 7 */ int doCnt, /* numX */ int doInc, /* numY */ int xStep, /* spaceX */ int yStep); /* spaceY */ /* This routine must be called after the defwCanPlace calls (if any). * The operation of the do is explained in the documentation. * This routine is optional. * Returns 0 if successful. * The routine can be called many times. */ extern int defwCannotOccupy(const char* master, /* sitename */ int xOrig, int yOrig, int orient, /* 0 to 7 */ int doCnt, /* numX */ int doInc, /* numY */ int xStep, /* spaceX */ int yStep); /* spaceY */ /* This routine must be called after the defwCanPlace calls (if any). * The operation of the do is explained in the documentation. * This routine is optional. * Returns 0 if successful. * The routine can be called many times. * This routine is the same as defwCannotOccupy, except orient is a char* */ extern int defwCannotOccupyStr(const char* master, /* sitename */ int xOrig, int yOrig, const char* orient, /* 0 to 7 */ int doCnt, /* numX */ int doInc, /* numY */ int xStep, /* spaceX */ int yStep); /* spaceY */ /* This routine must be called after defwCannotOccupy (if any). * This section of routines is optional. * Returns 0 if successful. * The routine starts the via section. All of the vias must follow. * The count is the number of defwVia calls to follow. * The routine can be called only once. */ extern int defwStartVias( int count ); /* These routines enter each via into the file. * These routines must be called after the defwStartVias call. * defwViaName should be called first, follow either by defwViaPattern or * defwViaLayer. At the end of each via, defwOneViaEnd should be called * These routines are for [- viaName [+ PATTERNNAME patternName + RECT layerName * pt pt]...;]... * Returns 0 if successful. * The routines can be called many times. */ extern int defwViaName(const char* name); extern int defwViaPattern(const char* patternName); /* This routine can be called multiple times. */ /* mask is 5.8 syntax */ extern int defwViaRect(const char* layerName, int xl, /* xl from the RECT */ int yl, /* yl from the RECT */ int xh, /* xh from the RECT */ int yh, /* yh from the RECT */ int mask = 0); /* optional */ /* This is a 5.6 syntax * This routine can be called multiple times. */ /* mask is 5.8 syntax */ extern int defwViaPolygon(const char* layerName, int num_polys, double* xl, double* yl, int mask = 0); /* These routine must be called after defwViaName. * Either this routine or defwViaPattern can be called after each * defwViaName is called. * This is a 5.6 syntax * Returns 0 if successful * The routine can be called only once per defwViaName called. */ extern int defwViaViarule(const char* viaRuleName, double xCutSize, double yCutSize, const char* botMetalLayer, const char* cutLayer, const char* topMetalLayer, double xCutSpacing, double yCutSpacing, double xBotEnc, double yBotEnc, double xTopEnc, double yTopEnc); /* This routine can call only after defwViaViarule. * It can only be called once. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwViaViaruleRowCol(int numCutRows, int numCutCols); /* This routine can call only after defwViaViarule. * It can only be called once. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwViaViaruleOrigin(int xOffset, int yOffset); /* This routine can call only after defwViaViarule. * It can only be called once. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwViaViaruleOffset(int xBotOffset, int yBotOffset, int xTopOffset, int yTopOffset); /* This routine can call only after defwViaViarule. * It can only be called once. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwViaViarulePattern(const char* cutPattern); extern int defwOneViaEnd(); /* This routine must be called after the defwVia calls. * Returns 0 if successful. * If the count in StartVias is not the same as the number of * calls to Via or ViaPattern then DEFW_BAD_DATA will return returned. * The routine can be called only once. */ extern int defwEndVias( void ); /* This routine must be called after via section (if any). * This section of routines is optional. * Returns 0 if successful. * The routine starts the region section. All of the regions must follow. * The count is the number of defwRegion calls to follow. * The routine can be called only once. */ extern int defwStartRegions( int count ); /* This routine enter each region into the file. * This routine must be called after the defwStartRegions call. * Returns 0 if successful. * The routine can be called many times. */ extern int defwRegionName(const char* name); /* This routine enter the region point to the region name. * This routine must be called after the defwRegionName call. * Returns 0 if successful. * The routine can be called many times. */ extern int defwRegionPoints(int xl, int yl, int xh, int yh); /* This routine enter the region type, FENCE | GUIDE. * This routine must be called after the defwRegionName call. * This is a 5.4.1 syntax. * Returns 0 if successful. * The routine can be called only once. */ extern int defwRegionType(const char* type); /* FENCE | GUIDE */ /* This routine must be called after the defwRegion calls. * Returns 0 if successful. * If the count in StartRegions is not the same as the number of * calls to Region or RegionPattern then DEFW_BAD_DATA will return returned. * The routine can be called only once. */ extern int defwEndRegions( void ); /* This is a 5.8 syntax. * Returns 0 if successful. * The routine can be called only once. */ extern int defwComponentMaskShiftLayers(const char** layerNames, int numLayerName); /* This routine must be called after the regions section (if any). * This section of routines is NOT optional. * Returns 0 if successful. * The routine starts the components section. All of the components * must follow. * The count is the number of defwComponent calls to follow. * The routine can be called only once. */ extern int defwStartComponents( int count ); /* This routine enter each component into the file. * This routine must be called after the defwStartComponents call. * The optional fields will be ignored if they are set to zero * (except for weight which must be set to -1.0). * Returns 0 if successful. * The routine can be called many times. */ extern int defwComponent(const char* instance, /* compName */ const char* master, /* modelName */ int numNetName, // optional(0) - # netNames defined const char** netNames, /* optional(NULL) - list */ const char* eeq, /* optional(NULL) - EEQMASTER */ const char* genName, /* optional(NULL) - GENERATE */ const char* genParemeters, /* optional(NULL) - parameters */ const char* source, // optional(NULL) - NETLIST | DIST | // USER | TIMING int numForeign, // optional(0) - # foreigns, // foreignx, foreigny & orients const char** foreigns, /* optional(NULL) - list */ int* foreignX, int* foreignY, /* optional(0) - list foreign pts */ int* foreignOrients, /* optional(-1) - 0 to 7 */ const char* status, // optional(NULL) - FIXED | COVER | // PLACED | UNPLACED int statusX, int statusY, /* optional(0) - status pt */ int statusOrient, /* optional(-1) - 0 to 7 */ double weight, /* optional(0) */ const char* region, // optional(NULL) - either xl, yl, // xh, yh or region int xl, int yl, /* optional(0) - region pt1 */ int xh, int yh); /* optional(0) - region pt2 */ /* This routine enter each component into the file. * This routine must be called after the defwStartComponents call. * The optional fields will be ignored if they are set to zero * (except for weight which must be set to -1.0). * Returns 0 if successful. * The routine can be called many times. * This routine is the same as defwComponent, except orient is a char** */ extern int defwComponentStr(const char* instance, /* compName */ const char* master, /* modelName */ int numNetName, // optional(0) - # netNames defined // const char** netNames, /* optional(NULL) - list */ const char* eeq, /* optional(NULL) - EEQMASTER */ const char* genName, /* optional(NULL) - GENERATE */ const char* genParemeters, /* optional(NULL) - parameters */ const char* source, // optional(NULL) - NETLIST | DIST | // USER | TIMING int numForeign, // optional(0) - # foreigns, // foreignx, foreigny & orients const char** foreigns, /* optional(NULL) - list */ int* foreignX, int* foreignY, /* optional(0) - list foreign pts */ const char** foreignOrients, /* optional(NULL) */ const char* status, // optional(NULL) - FIXED | COVER | // PLACED | UNPLACED int statusX, int statusY, /* optional(0) - status pt */ const char* statusOrient, /* optional(NULL) */ double weight, /* optional(0) */ const char* region, // optional(NULL) - either xl, yl, // xh, yh or region int xl, int yl, /* optional(0) - region pt1 */ int xh, int yh); /* optional(0) - region pt2 */ /* This is a 5.8 syntax. * Returns 0 if successful. * The routine can be called only once. */ extern int defwComponentMaskShift(int shiftLayerMasks); /* This routine must be called after either the defwComponent or * defwComponentStr. * This routine can only called once per component. * Either this routine or defwComponentHaloSoft can be called, but not both * This routine is optional. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwComponentHalo(int left, int bottom, int right, int top); /* This routine must be called after either the defwComponent or * defwComponentStr. * This routine can only called once per component. * This routine is just like defwComponentHalo, except it writes the option SOFT * Either this routine or defwComponentHalo can be called, but not both * This routine is optional. * This is a 5.7 syntax. * Returns 0 if successful. */ extern int defwComponentHaloSoft(int left, int bottom, int right, int top); /* This routine must be called after either the defwComponent or * defwComponentStr. * This routine can only called once per component. * This routine is optional. * This is a 5.7 syntax. * Returns 0 if successful. */ extern int defwComponentRouteHalo(int haloDist, const char* minLayer, const char* maxLayer); /* This routine must be called after the defwComponent calls. * Returns 0 if successful. * If the count in StartComponents is not the same as the number of * calls to Component then DEFW_BAD_DATA will return returned. * The routine can be called only once. */ extern int defwEndComponents( void ); /* This routine must be called after the components section (if any). * This section of routines is optional. * Returns 0 if successful. * The routine starts the pins section. All of the pins must follow. * The count is the number of defwPin calls to follow. * The routine can be called only once. */ extern int defwStartPins( int count ); /* This routine enter each pin into the file. * This routine must be called after the defwStartPins call. * The optional fields will be ignored if they are set to zero. * Returns 0 if successful. * The routine can be called many times. * NOTE: Use defwPinLayer to write out layer with SPACING or DESIGNRULEWIDTH */ extern int defwPin(const char* name, /* pinName */ const char* net, /* netName */ int special, /* 0 - ignore, 1 - special */ const char* direction, // optional(NULL) - INPUT | OUTPUT | // INOUT | FEEDTHRU const char* use, // optional(NULL) - SIGNAL | POWER | // GROUND | CLOCK | TIEOFF | ANALOG const char* status, // optional(NULL) - FIXED | PLACED | // COVER int statusX, int statusY, /* optional(0) - status point */ int orient, /* optional(-1) - status orient */ const char* layer, /* optional(NULL) - layerName */ int xl, int yl, /* optional(0) - layer point1 */ int xh, int yh); /* optional(0) - layer point2 */ /* This routine enter each pin into the file. * This routine must be called after the defwStartPins call. * The optional fields will be ignored if they are set to zero. * Returns 0 if successful. * The routine can be called many times. * This routine is the same as defwPin, except orient is a char* * NOTE: Use defwPinLayer to write out layer with SPACING or DESIGNRULEWIDTH */ extern int defwPinStr(const char* name, /* pinName */ const char* net, /* netName */ int special, /* 0 - ignore, 1 - special */ const char* direction, // optional(NULL) - INPUT | OUTPUT | // INOUT | FEEDTHRU const char* use, // optional(NULL) - SIGNAL | POWER | // GROUND | CLOCK | TIEOFF | ANALOG const char* status, // optional(NULL) - FIXED | PLACED | // COVER int statusX, int statusY, /* optional(0) - status point */ const char* orient, /* optional(NULL) */ const char* layer, /* optional(NULL) - layerName */ int xl, int yl, /* optional(0) - layer point1 */ int xh, int yh); /* optional(0) - layer point2 */ /* This routine should be called if the layer has either SPACING or * DESIGNRULEWIDTH. If this routine is used and the pin has only one * layer, the layer in defwPin or defwPinStr has to be null, otherwise * the layer will be written out twice. * This routine must be called after defwPin or defwPinStr. * This is a 5.6 syntax. * This routine is optional. * Returns 0 if successful. * This routine can be called multiple times within a pin. */ extern int defwPinLayer(const char* layerName, int spacing, /* optional(0) - SPACING & DESIGNRULEWIDTH */ int designRuleWidth, /* are mutually exclusive */ int xl, int yl, int xh, int yh, int mask = 0); /* This routine must be called after defwPin or defwPinStr. * This routine is to write out layer with polygon. * This is a 5.6 syntax. * This routine is optional. * Returns 0 if successful. * The routine can be called multiple times within a pin. */ extern int defwPinPolygon(const char* layerName, int spacing, /* optional(0) - SPACING & DESIGNRULEWIDTH */ int designRuleWidth, /* are mutually exclusive */ int num_polys, double* xl, double* yl, int mask = 0); /* This routine must be called after defwPin or defwPinStr. * This routine is to write out layer with via. * This is a 5.7 syntax. * This routine is optional. * Returns 0 if successful. * The routine can be called multiple times within a pin. */ extern int defwPinVia(const char* viaName, int xl, int yl, int mask = 0); /* This routine must be called after defwPin or defwPinStr. * This routine is to write out pin with port. * This is a 5.7 syntax. * This routine is optional. * Returns 0 if successful. * The routine can be called multiple times within a pin. */ extern int defwPinPort(); /* This routine is called after defwPinPort. * This is a 5.7 syntax. * This routine is optional. * Returns 0 if successful. * This routine can be called multiple times within a pin. */ extern int defwPinPortLayer(const char* layerName, int spacing, /* optional(0) - SPACING & DESIGNRULEWIDTH */ int designRuleWidth, /* are mutually exclusive */ int xl, int yl, int xh, int yh, int mask = 0); /* This routine must be called after defwPinPort. * This is a 5.7 syntax. * This routine is optional. * Returns 0 if successful. * The routine can be called multiple times within a pin. */ extern int defwPinPortPolygon(const char* layerName, int spacing, /* optional(0) - SPACING & DESIGNRULEWIDTH */ int designRuleWidth, /* are mutually exclusive */ int num_polys, double* xl, double* yl, int mask = 0); /* This routine must be called after defwPinPort. * This is a 5.7 syntax. * This routine is optional. * Returns 0 if successful. * The routine can be called multiple times within a pin. */ extern int defwPinPortVia(const char* viaName, int xl, int yl, int mask = 0); /* This routine must be called after defwPinPort. * This is a 5.7 syntax. * This routine is optional. * Returns 0 if successful. * The routine can be called many times. * NOTE: Use defwPinLayer to write out layer with SPACING or DESIGNRULEWIDTH */ extern int defwPinPortLocation( const char* status, /* FIXED | PLACED | COVER */ int statusX, int statusY, /* status point */ const char* orient); /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.6 syntax. * The routine can be called only once per pin. */ extern int defwPinNetExpr(const char* pinExpr); /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.6 syntax. * The routine can be called only once per pin. */ extern int defwPinSupplySensitivity(const char* pinName); /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.6 syntax. * The routine can be called only once per pin. */ extern int defwPinGroundSensitivity(const char* pinName); /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.4 syntax. * The routine can be called multiple times. */ extern int defwPinAntennaPinPartialMetalArea(int value, const char* layerName); /* optional(NULL) */ /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.4 syntax. * The routine can be called multiple times. */ extern int defwPinAntennaPinPartialMetalSideArea(int value, const char* layerName); /* optional(NULL) */ /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.4 syntax. * The routine can be called multiple times. */ extern int defwPinAntennaPinPartialCutArea(int value, const char* layerName); /* optional(NULL) */ /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.4 syntax. * The routine can be called multiple times. */ extern int defwPinAntennaPinDiffArea(int value, const char* layerName); /* optional(NULL) */ /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.5 syntax. * The oxide can be either OXIDE1, OXIDE2, OXIDE3, or OXIDE4. * Each oxide value can be called only once after defwPin. */ extern int defwPinAntennaModel(const char* oxide); /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.4 syntax. * The routine can be called multiple times. */ extern int defwPinAntennaPinGateArea(int value, const char* layerName); /* optional(NULL) */ /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.4 syntax. * The routine can be called multiple times. */ extern int defwPinAntennaPinMaxAreaCar(int value, const char* layerName); /* optional(NULL) */ /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.4 syntax. * The routine can be called multiple times. */ extern int defwPinAntennaPinMaxSideAreaCar(int value, const char* layerName); /* optional(NULL) */ /* This routine must be called after defwPin. * Returns 0 if successful. * This is a 5.4 syntax. * The routine can be called multiple times. */ extern int defwPinAntennaPinMaxCutCar(int value, const char* layerName); /* optional(NULL) */ /* This routine must be called after the defwPin calls. * Returns 0 if successful. * If the count in StartPins is not the same as the number of * calls to Pin then DEFW_BAD_DATA will return returned. * The routine can be called only once. */ extern int defwEndPins( void ); /* This routine must be called after the pin section (if any). * This section of routines is optional. * Returns 0 if successful. * The routine starts the pinproperties section. All of the pinproperties * must follow. * The count is the number of defwPinProp calls to follow. * The routine can be called only once. */ extern int defwStartPinProperties( int count ); /* This routine enter each pinproperty into the file. * This routine must be called after the defwStartPinProperties call. * The optional fields will be ignored if they are set to zero. * Returns 0 if successful. * The routine can be called many times. */ extern int defwPinProperty(const char* name, /* compName | PIN */ const char* pinName); /* pinName */ /* This routine must be called after the defwPinProperty calls. * Returns 0 if successful. * If the count in StartPins is not the same as the number of * calls to Pin then DEFW_BAD_DATA will return returned. * The routine can be called only once. */ extern int defwEndPinProperties( void ); /* Routines to enter a special net or nets into the file. * You must first call defwStartSpecialNets with the number of * nets. This section is required, even if you do not have any nets. * For each net you should call defwSpecialNet followed by * one or more defwSpecialNetConnection calls. * After the connections come the options. Options are * NOT required. * Each net is completed by calling defwSpecialNetEndOneNet(). * The nets section is finished by calling defwEndNets(). */ extern int defwStartSpecialNets(int count); /* This routine must be called after the defwStartSpecialNets it is for * - netName */ extern int defwSpecialNet(const char* name); /* netName */ /* This routine is for compNameRegExpr, pinName, and SYNTHESIZED */ /* It can be called multiple times */ extern int defwSpecialNetConnection(const char* inst, /* compNameRegExpr */ const char* pin, /* pinName */ int synthesized); /* 0 - ignore, 1 - SYNTHESIZED */ /* This routine is for + FIXEDBUMP * This is a 5.4.1 syntax */ extern int defwSpecialNetFixedbump(); /* This routine is for + VOLTAGE volts */ extern int defwSpecialNetVoltage(double v); /* This routine is for + SPACING layerName spacing [RANGE minwidth maxwidth */ extern int defwSpecialNetSpacing(const char* layer, /* layerName */ int spacing, /* spacing */ double minwidth, /* optional(0) - minwidth */ double maxwidth); /* optional(0) - maxwidth */ /* This routine is for + WIDTH layerName width */ extern int defwSpecialNetWidth(const char* layer, /* layerName */ int width); /* width */ /* This routine is for + SOURCE {NETLIST | DIST | USER | TIMING} */ extern int defwSpecialNetSource(const char* name); /* This routine is for + ORIGINAL netName */ extern int defwSpecialNetOriginal(const char* name); /* netName */ /* This routine is for + PATTERN {STEINER | BALANCED | WIREDLOGIC | TRUNK} */ extern int defwSpecialNetPattern(const char* name); /* This routine is for + USE {SIGNAL | POWER | GROUND | CLOCK | TIEOFF | ANALOG | SCAN | RESET} */ extern int defwSpecialNetUse(const char* name); /* This routine is for + WEIGHT weight */ extern int defwSpecialNetWeight(double value); /* This routine is for + ESTCAP wireCapacitance */ extern int defwSpecialNetEstCap(double value); /* Paths are a special type of option. A path must begin * with a defwSpecialNetPathStart and end with a defwSpecialNetPathEnd(). * The individual parts of the path can be entered in * any order. */ extern int defwSpecialNetPathStart(const char* typ); // ROUTED | FIXED | COVER | // SHIELD | NEW extern int defwSpecialNetShieldNetName(const char* name); /* shieldNetName */ extern int defwSpecialNetPathLayer(const char* name); /* layerName */ extern int defwSpecialNetPathWidth(int width); /* This routine is optional. * This is a 5.6 syntax. */ extern int defwSpecialNetPathStyle(int styleNum); extern int defwSpecialNetPathShape(const char* shapeType); // RING | STRIPE | // FOLLOWPIN | IOWIRE | COREWIRE | BLOCKWIRE | FILLWIRE | BLOCKAGEWIRE /* This routine is optional. This is a 5.8 syntax. * Returns 0 if successful. */ extern int defwSpecialNetPathMask(int colorMask); /* x and y location of the path */ extern int defwSpecialNetPathPoint(int numPts, /* number of connected points */ double* pointx, /* point x list */ double* pointy); /* point y list */ extern int defwSpecialNetPathVia(const char* name); /* viaName */ /* This routine is called after defwSpecialNetPath * This is a 5.4.1 syntax */ extern int defwSpecialNetPathViaData(int numX, int numY, int stepX, int stepY); /* x and y location of the path */ extern int defwSpecialNetPathPointWithWireExt( int numPts, /* number of connected points */ double* pointx, /* point x list */ double* pointy, /* point y list */ double* optValue); /* optional(NULL) value */ extern int defwSpecialNetPathEnd(); /* This is a 5.6 syntax * This routine can be called multiple times. */ extern int defwSpecialNetPolygon(const char* layerName, int num_polys, double* xl, double* yl); /* This is a 5.6 syntax * This routine can be called multiple times. */ extern int defwSpecialNetRect(const char* layerName, int xl, int yl, int xh, int yh); extern int defwSpecialNetVia(const char* layerName); extern int defwSpecialNetViaWithOrient(const char* layerName, int orient); extern int defwSpecialNetViaPoints(int num_points, double* xl, double* yl); /* This routine is called at the end of each net */ extern int defwSpecialNetEndOneNet(); /* 5.3 for special net */ /* Shields are a special type of option. A shield must begin * with a defwSpecialNetShieldStart and end with a defwSpecialNetShieldEnd(). * The individual parts of the shield can be entered in * any order. */ extern int defwSpecialNetShieldStart(const char* name); extern int defwSpecialNetShieldLayer(const char* name); /* layerName */ extern int defwSpecialNetShieldWidth(int width); /* width */ extern int defwSpecialNetShieldShape(const char* shapeType); // RING | STRIPE | // FOLLOWPIN | IOWIRE | COREWIRE | BLOCKWIRE | FILLWIRE | BLOCKAGEWIRE /* x and y location of the path */ extern int defwSpecialNetShieldPoint(int numPts, /* # of connected points */ double* pointx, /* point x list */ double* pointy); /* point y list */ extern int defwSpecialNetShieldVia(const char* name); /* viaName */ /* A 5.4.1 syntax */ extern int defwSpecialNetShieldViaData(int numX, int numY, int stepX, int stepY); extern int defwSpecialNetShieldEnd(); /* end 5.3 */ /* This routine is called at the end of the special net section */ extern int defwEndSpecialNets(); /* Routines to enter a net or nets into the file. * You must first call defwNets with the number of nets. * This section is required, even if you do not have any nets. * For each net you should call defwNet followed by one or * more defwNetConnection calls. * After the connections come the options. Options are * NOT required. * Each net is completed by calling defwNetEndOneNet(). * The nets section is finished by calling defwEndNets(). */ extern int defwStartNets(int count); /* This routine must be called after the defwStartNets, it is for - netName */ extern int defwNet(const char* name); /* This routine is for { compName | PIN } pinName [+ SYNTHESIZED] */ /* It can be called multiple times */ extern int defwNetConnection(const char* inst, /* compName */ const char* pin, /* pinName */ int synthesized); /* 0 - ignore, 1 - SYNTHESIZED */ /* This routine is for MUSTJOIN, compName, pinName */ extern int defwNetMustjoinConnection(const char* inst, /* compName */ const char* pin); /* pinName */ /* This routine is for + VPIN vpinName [LAYER layerName pt pt * [{ PLACED | FIXED | COVER } pt orient] */ extern int defwNetVpin(const char* vpinName, const char* layerName, /* optional(NULL) */ int layerXl, int layerYl, /* layer point1 */ int layerXh, int layerYh, /* layer point2 */ const char* status, /* optional(NULL) */ int statusX, int statusY, /* optional(0) - status point */ int orient); /* optional(-1) */ /* This routine is for + VPIN vpinName [LAYER layerName pt pt * [{ PLACED | FIXED | COVER } pt orient] * This routine is the same as defwNetVpin, except orient is a char* */ extern int defwNetVpinStr(const char* vpinName, const char* layerName, /* optional(NULL) */ int layerXl, int layerYl, /* layer point1 */ int layerXh, int layerYh, /* layer point2 */ const char* status, /* optional(NULL) */ int statusX, int statusY, /* optional(0) - status point */ const char* orient); /* optional(NULL) */ /* This routine can be called either within net or subnet. * it is for NONDEFAULTRULE rulename */ extern int defwNetNondefaultRule(const char* name); /* This routine is for + XTALK num */ extern int defwNetXtalk(int xtalk); /* This routine is for + FIXEDBUMP * This is a 5.4.1 syntax */ extern int defwNetFixedbump(); /* This routine is for + FREQUENCY * This is a 5.4.1 syntax */ extern int defwNetFrequency(double frequency); /* This routine is for + SOURCE {NETLIST | DIST | USER | TEST | TIMING} */ extern int defwNetSource(const char* name); /* This routine is for + ORIGINAL netname */ extern int defwNetOriginal(const char* name); /* This routine is for + USE {SIGNAL | POWER | GROUND | CLOCK | TIEOFF | * ANALOG} */ extern int defwNetUse(const char* name); /* This routine is for + PATTERN {STEINER | BALANCED | WIREDLOGIC} */ extern int defwNetPattern(const char* name); /* This routine is for + ESTCAP wireCapacitance */ extern int defwNetEstCap(double value); /* This routine is for + WEIGHT weight */ extern int defwNetWeight(double value); /* 5.3 for net */ /* This routine is for + SHIELDNET weight */ extern int defwNetShieldnet(const char* name); /* Noshield are a special type of option. A noshield must begin * with a defwNetNoshieldStart and end with a defwNetNoshieldEnd(). * The individual parts of the noshield can be entered in * any order. */ extern int defwNetNoshieldStart(const char* name); /* x and y location of the path */ extern int defwNetNoshieldPoint(int numPts, /* number of connected points */ const char** pointx, /* point x list */ const char** pointy); /* point y list */ extern int defwNetNoshieldVia(const char* name); /* viaName */ extern int defwNetNoshieldEnd(); /* end 5.3 */ /* Subnet are a special type of option. A subnet must begin * with a defwNetSubnetStart and end with a defwNetSubnetEnd(). * Routines to call within the subnet are: defwNetSubnetPin, * defwNetNondefaultRule and defwNetPathStart... */ extern int defwNetSubnetStart(const char* name); /* This routine is called after the defwNetSubnet, it is for * [({compName | PIN} pinName) | (VPIN vpinName)]... */ extern int defwNetSubnetPin(const char* compName, /* compName | PIN | VPIN */ const char* pinName); /* pinName | vpinName */ extern int defwNetSubnetEnd(); /* Paths are a special type of option. A path must begin * with a defwNetPathStart and end with a defwPathEnd(). * The individual parts of the path can be entered in * any order. */ extern int defwNetPathStart(const char* typ); // ROUTED | FIXED | COVER | // NOSHIELD | NEW extern int defwNetPathWidth(int w); /* width */ extern int defwNetPathLayer(const char* name, /* layerName */ int isTaper, /* 0 - ignore, 1 - TAPER */ const char* rulename); /* only one, isTaper or */ /*rulename can be assigned */ /* This routine is optional. * This is a 5.6 syntax. */ extern int defwNetPathStyle(int styleNum); /* This routine is optional. * This is a 5.8 syntax. */ extern int defwNetPathMask(int maskNum); extern int defwNetPathRect(int deltaX1, int deltaY1, int deltaX2, int deltaY2); extern int defwNetPathVirtual(int x, int y); /* x and y location of the path */ extern int defwNetPathPoint(int numPts, /* number of connected points */ double* pointx, /* point x list */ double* pointy); /* point y list */ extern int defwNetPathPointWithExt(int numPts, double* pointx, double* pointy, double* optValue); extern int defwNetPathVia(const char* name); /* viaName */ extern int defwNetPathViaWithOrient(const char* name, int orient); /* optional(-1) */ extern int defwNetPathViaWithOrientStr(const char* name, const char* orient); /* optional(Null) */ extern int defwNetPathEnd(); /* This routine is called at the end of each net */ extern int defwNetEndOneNet(); /* This routine is called at the end of the net section */ extern int defwEndNets(); /* This section of routines is optional. * Returns 0 if successful. * The routine starts the I/O Timing section. All of the iotimings options * must follow. * The count is the number of defwIOTiming calls to follow. * The routine can be called only once. * This api is obsolete in 5.4. */ extern int defwStartIOTimings(int count); /* This routine can be called after defwStaratIOTiming * It is for - - {(comp pin) | (PIN name)} * This api is obsolete in 5.4. */ extern int defwIOTiming(const char* inst, /* compName | PIN */ const char* pin); /* pinName */ /* This routine is for + { RISE | FALL } VARIABLE min max * This api is obsolete in 5.4. */ extern int defwIOTimingVariable(const char* riseFall, /* RISE | FALL */ int num1, /* min */ int num2); /* max */ /* This routine is for + { RISE | FALL } SLEWRATE min max * This api is obsolete in 5.4. */ extern int defwIOTimingSlewrate(const char* riseFall, /* RISE | FALL */ int num1, /* min */ int num2); /* max */ /* This routine is for + DRIVECELL macroName [[FROMPIN pinName] TOPIN pinName] * [PARALLEL numDrivers] * This api is obsolete in 5.4. */ extern int defwIOTimingDrivecell(const char* name, /* macroName*/ const char* fromPin, /* optional(NULL) */ const char* toPin, /* optional(NULL) */ int numDrivers); /* optional(0) */ /* This routine is for + CAPACITANCE capacitance * This api is obsolete in 5.4. */ extern int defwIOTimingCapacitance(double num); /* This api is obsolete in 5.4. */ extern int defwEndIOTimings(); /* Routines to enter scan chains. This section is optional * The section must start with a defwStartScanchains() call and * end with a defwEndScanchain() call. * Each scan chain begins with a defwScanchain() call. * The rest of the calls follow. */ extern int defwStartScanchains(int count); /* This routine can be called after defwStartScanchains * It is for - chainName */ extern int defwScanchain(const char* name); /* This routine is for + COMMONSCANPINS [IN pin] [OUT pin] */ extern int defwScanchainCommonscanpins( const char* inst1, /* optional(NULL) - IN | OUT*/ const char* pin1, /* can't be null if inst1 is set */ const char* inst2, /* optional(NULL) - IN | OUT */ const char* pin2); /* can't be null if inst2 is set */ /* This routine is for + PARTITION paratitionName [MAXBITS maxBits] */ /* This is 5.4.1 syntax */ extern int defwScanchainPartition(const char* name, int maxBits); /* optional(-1) */ /* This routine is for + START {fixedInComp | PIN } [outPin] */ extern int defwScanchainStart(const char* inst, /* fixedInComp | PIN */ const char* pin); /* outPin */ /* This routine is for + STOP {fixedOutComp | PIN } [inPin] */ extern int defwScanchainStop(const char* inst, /* fixedOutComp | PIN */ const char* pin); /* inPin */ /* This routine is for + FLOATING {floatingComp [IN pin] [OUT pin]} * This is a 5.4.1 syntax */ extern int defwScanchainFloating(const char* name, /* floatingComp */ const char* inst1, /* optional(NULL) - IN | OUT */ const char* pin1, /* can't be null if inst1 is set */ const char* inst2, /* optional(NULL) - IN | OUT */ const char* pin2); /* can't be null if inst2 is set */ /* This routine is for + FLOATING {floatingComp [IN pin] [OUT pin]} * This is a 5.4.1 syntax. * This routine is the same as defwScanchainFloating. But also added * the option BITS. */ extern int defwScanchainFloatingBits(const char* name, /* floatingComp */ const char* inst1, /* optional(NULL) - IN | OUT */ const char* pin1, /* can't be null if inst1 is set */ const char* inst2, /* optional(NULL) - IN | OUT */ const char* pin2, /* can't be null if inst2 is set */ int bits); /* optional (-1) */ /* This routine is for + ORDERED {fixedComp [IN pin] [OUT pin] * fixedComp [IN pin] [OUT pin]. * When this routine is called for the 1st time within a scanchain, * both name1 and name2 are required. Only name1 is required is the * routine is called more than once. */ extern int defwScanchainOrdered(const char* name1, const char* inst1, /* optional(NULL) - IN | OUT */ const char* pin1, /* can't be null if inst1 is set */ const char* inst2, /* optional(NULL) - IN | OUT */ const char* pin2, /* can't be null if inst2 is set */ const char* name2, const char* inst3, /* optional(NULL) - IN | OUT */ const char* pin3, /* can't be null if inst3 is set */ const char* inst4, /* optional(NULL) - IN | OUT */ const char* pin4); /* can't be null if inst4 is set */ /* This routine is for + ORDERED {fixedComp [IN pin] [OUT pin] * fixedComp [IN pin] [OUT pin]. * When this routine is called for the 1st time within a scanchain, * both name1 and name2 are required. Only name1 is required is the * routine is called more than once. * This is a 5.4.1 syntax. * This routine is the same as defwScanchainOrdered. But also added * the option BITS */ extern int defwScanchainOrderedBits(const char* name1, const char* inst1, /* optional(NULL) - IN | OUT */ const char* pin1, /* can't be null if inst1 is set */ const char* inst2, /* optional(NULL) - IN | OUT */ const char* pin2, /* can't be null if inst2 is set */ int bits1, /* optional(-1) */ const char* name2, const char* inst3, /* optional(NULL) - IN | OUT */ const char* pin3, /* can't be null if inst3 is set */ const char* inst4, /* optional(NULL) - IN | OUT */ const char* pin4, /* can't be null if inst4 is set */ int bits2); /* optional(-1) */ extern int defwEndScanchain(); /* Routines to enter constraints. This section is optional * The section must start with a defwStartConstrains() call and * end with a defwEndConstraints() call. * Each contraint will call the defwConstraint...(). * This api is obsolete in 5.4. */ extern int defwStartConstraints (int count); /* optional */ /* The following routines are for - {operand [+ RISEMAX time] [+ FALLMAX time] * [+ RISEMIN time] [+ FALLMIN time] | WIREDLOGIC netName MAXDIST distance };} * operand - NET netName | PATH comp fromPin comp toPin | SUM (operand, ...) * The following apis are obsolete in 5.4. */ extern int defwConstraintOperand(); /* begin an operand */ extern int defwConstraintOperandNet(const char* netName); /* NET */ extern int defwConstraintOperandPath(const char* comp1, /* PATH - comp|PIN */ const char* fromPin, const char* comp2, const char* toPin); extern int defwConstraintOperandSum(); /* SUM */ extern int defwConstraintOperandSumEnd(); /* mark the end of SUM */ extern int defwConstraintOperandTime(const char* timeType, // RISEMAX | FALLMAX | RISEMIN | FALLMIN int time); extern int defwConstraintOperandEnd(); /* mark the end of operand */ /* This routine is for - WIRELOGIC netName MAXDIST distance */ extern int defwConstraintWiredlogic(const char* netName, int distance); extern int defwEndConstraints (); /* Routines to enter groups. This section is optional * The section must start with a defwStartGroups() call and * end with a defwEndGroups() call. * Each group will call the defwGroup...(). */ extern int defwStartGroups (int count); /* optional */ /* This routine is for - groupName compNameRegExpr ... */ extern int defwGroup(const char* groupName, int numExpr, const char** groupExpr); /* This routine is for + SOFT [MAXHALFPERIMETER value] [MAXX value] * [MAXY value] */ extern int defwGroupSoft(const char* type1, /* MAXHALFPERIMETER | MAXX | MAXY */ double value1, const char* type2, double value2, const char* type3, double value3); /* This routine is for + REGION {pt pt | regionName} */ extern int defwGroupRegion(int xl, int yl, /* either the x & y or */ int xh, int yh, /* regionName only, can't */ const char* regionName); /* be both */ extern int defwEndGroups(); /* Routines to enter Blockages. This section is optional * The section must start with a defwStartBlockages() call and * end with a defwEndBlockages() call. * Each blockage will call the defwBlockages...(). * This is a 5.4 syntax. */ extern int defwStartBlockages(int count); /* count = numBlockages */ /* This routine is for - layerName * This routine is called per entry within a blockage for layer. * This is a 5.4 syntax. */ extern int defwBlockagesLayer(const char* layerName); /* This routine is for - slots * This routine is called per entry within a blockage layer, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockagesLayerSlots(); /* This routine is for - fills * This routine is called per entry within a blockage layer, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockagesLayerFills(); /* This routine is for - pushdown * This routine is called per entry within a blockage layer, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockagesLayerPushdown(); /* This routine is for - exceptpgnet * This routine is called per entry within a blockage layer, can't be more then one. * This is a 5.7 syntax. */ extern int defwBlockagesLayerExceptpgnet(); /* This routine is for - component * This routine called per entry within a blockage layer, can't be more than one. * This is a 5.6 syntax. */ extern int defwBlockagesLayerComponent(const char* compName); /* This routine is for - spacing * Either this routine or defwBlockagesDesignRuleWidth is called per entry * within a blockage layer, can't be more than one. * This is a 5.6 syntax. */ extern int defwBlockagesLayerSpacing(int minSpacing); /* This routine is for - designrulewidth * Either this routine or defwBlockagesSpacing is called per entry * within a blockage layer, can't be more than one. * This is a 5.6 syntax. */ extern int defwBlockagesLayerDesignRuleWidth(int effectiveWidth); /* This routine is for - mask. * This routine called per entry within a blockage layer, can't be more than one. * This is a 5.8 syntax. */ extern int defwBlockagesLayerMask(int maskColor); /* This routine is for - layerName & compName * Either this routine, defBlockageLayerSlots, defBlockageLayerFills, * or defwBlockagePlacement is called per entry within * a blockage, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockageLayer(const char* layerName, const char* compName); /* optional(NULL) */ /* This routine is for - layerName & slots * Either this routine, defBlockageLayer, defBlockageLayerFills, * defwBlockagePlacement, or defwBlockagePushdown is called per entry within * a blockage, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockageLayerSlots(const char* layerName); /* This routine is for - layerName & fills * Either this routine, defBlockageLayer, defBlockageLayerSlots, * defwBlockagePlacement, or defwBlockagePushdown is called per entry within * a blockage, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockageLayerFills(const char* layerName); /* This routine is for - layerName & pushdown * Either this routine, defBlockageLayer, defBlockageLayerSlots, * defwBlockagePlacement, or defwBlockageFills is called per entry within * a blockage, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockageLayerPushdown(const char* layerName); /* This routine is for - exceptpgnet * Either this routine, defBlockageLayer, defBlockageLayerSlots, * defwBlockagePlacement, or defwBlockageFills is called per entry within * a blockage, can't be more then one. * This is a 5.7 syntax. */ extern int defwBlockageLayerExceptpgnet(const char* layerName); /* This routine is for - spacing * Either this routine or defwBlockageDesignRuleWidth is called per entry * within a blockage, can't be more than one. * This is a 5.6 syntax. */ extern int defwBlockageSpacing(int minSpacing); /* This routine is for - designrulewidth * Either this routine or defwBlockageSpacing is called per entry * within a blockage, can't be more than one. * This is a 5.6 syntax. */ extern int defwBlockageDesignRuleWidth(int effectiveWidth); /* This routine is for - placement * This routine is called per entry within blockage for placement. * This is a 5.4 syntax. * 11/25/2002 - bug fix: submitted by Craig Files (cfiles@ftc.agilent.com) * this routine allows to call blockage without a component. */ extern int defwBlockagesPlacement(); /* This routine is for - component * This routine is called per entry within blockage placement, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockagesPlacementComponent(const char* compName); /* This routine is for - Pushdown * This routine is called per entry within blockage placement, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockagesPlacementPushdown(); /* This routine is for - soft * Either this routine or defwBlockagesPlacementPartial * is called per entry within blockage placement, can't be more then one. * This is a 5.7 syntax. */ extern int defwBlockagesPlacementSoft(); /* This routine is for - Partial * Either this routine or defwBlockagesPlacementSoft * is called per entry within blockage placement, can't be more then one. * This is a 5.7 syntax. */ extern int defwBlockagesPlacementPartial(double maxDensity); /* This routine is for rectangle. * This routine is optional and can be called multiple time. * This is a 5.4 syntax. */ extern int defwBlockagesRect(int xl, int yl, int xh, int yh); /* This routine is for polygon. * This routine is optional and can be called multiple time. * This is a 5.6 syntax. */ extern int defwBlockagesPolygon(int num_polys, int* xl, int* yl); /* This routine is for - placement * Either this routine or defBlockageLayer * is called per entry within blockage, can't be more then one. * This is a 5.4 syntax. * 11/25/2002 - bug fix: submitted by Craig Files (cfiles@ftc.agilent.com) * this routine allows to call blockage without a component. */ extern int defwBlockagePlacement(); /* This routine is for - placement & component * Either this routine or defwBlockagePlacementPushdown * is called per entry within blockage, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockagePlacementComponent(const char* compName); /* This routine is for - placement & Pushdown * Either this routine or defwBlockagePlacementComponent * is called per entry within blockage, can't be more then one. * This is a 5.4 syntax. */ extern int defwBlockagePlacementPushdown(); /* This routine is for - placement & soft * Either this routine or defwBlockagePlacementPushdown * is called per entry within blockage, can't be more then one. * This is a 5.7 syntax. */ extern int defwBlockagePlacementSoft(); /* This routine is for - placement & Partial * Either this routine or defwBlockagePlacementComponent * is called per entry within blockage, can't be more then one. * This is a 5.7 syntax. */ extern int defwBlockagePlacementPartial(double maxDensity); /* This routine is optional. * This is a 5.8 syntax. */ extern int defwBlockageMask(int maskColor); /* This routine is for rectangle. * This is a 5.4 syntax. */ extern int defwBlockageRect(int xl, int yl, int xh, int yh); /* This routine is for polygon. * This routine is optinal and can be called multiple time. * This is a 5.6 syntax. */ extern int defwBlockagePolygon(int num_polys, int* xl, int* yl); /* This is a 5.4 syntax. */ extern int defwEndBlockages(); /* Routines to enter Slots. This section is optional * The section must start with a defwStartSlots() call and * end with a defwEndSlots() call. * Each slots will call the defwSlots...(). * This is a 5.4 syntax. */ extern int defwStartSlots(int count); /* count = numSlots */ /* This routine is for - layerName & compName * Either this routine, defSlots, defSlotsLayerFills, * or defwSlotsPlacement is called per entry within * a slot, can't be more then one. * This is a 5.4 syntax. */ extern int defwSlotLayer(const char* layerName); /* This routine is for rectangle * This is a 5.4 syntax. */ extern int defwSlotRect(int xl, int yl, int xh, int yh); /* This routine is for rectangle * This is a 5.6 syntax and can be called multiple time. */ extern int defwSlotPolygon(int num_polys, double* xl, double* yl); /* This is a 5.4 syntax. */ extern int defwEndSlots(); /* Routines to enter Fills. This section is optional * The section must start with a defwStartFills() call and * end with a defwEndFills() call. * Each fills will call the defwFills...(). * This is a 5.4 syntax. */ extern int defwStartFills(int count); /* count = numFills */ /* This routine is for - layerName & compName * Either this routine, defFills, defFillsLayerFills, * or defwFillsPlacement is called per entry within * a fill, can't be more then one. * This is a 5.4 syntax. */ extern int defwFillLayer(const char* layerName); /* This routine is optional. * This is a 5.8 syntax. */ extern int defwFillLayerMask(int maskColor); /* This routine has to be called after defwFillLayer * This routine is optional. * This is a 5.7 syntax. */ extern int defwFillLayerOPC(); /* This routine is for rectangle. * This is a 5.4 syntax. */ extern int defwFillRect(int xl, int yl, int xh, int yh); /* This routine is for polygon. * This is a 5.6 syntax and can be called multiple time. */ extern int defwFillPolygon(int num_polys, double* xl, double* yl); /* This routine is for via. * This routine is optional. * This is a 5.7 syntax and can be called multiple time. */ extern int defwFillVia(const char* viaName); /* This routine is optional. * This is a 5.8 syntax. */ extern int defwFillViaMask(int colorMask); /* This routine is for via OPC. * This routine can only be called after defwFillVia. * This routine is optional. * This is a 5.7 syntax and can be called multiple time. */ extern int defwFillViaOPC(); /* This routine is for via OPC. * This routine can only be called after defwFillVia. * This routine is required following defwFillVia. * This is a 5.7 syntax and can be called multiple time. */ extern int defwFillPoints(int num_points, double* xl, double* yl); /* This is a 5.4 syntax. */ extern int defwEndFills(); /* Routines to enter NONDEFAULTRULES. This section is required * The section must start with a defwStartNonDefaultRules() and * end with defwEndNonDefaultRules() call. * This is a 5.6 syntax. */ extern int defwStartNonDefaultRules(int count); /* This routine is for Layer within the NONDEFAULTRULES * This routine can be called multiple times. It is required. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwNonDefaultRule(const char* ruleName, int hardSpacing); /* optional(0) */ /* Routines to enter NONDEFAULTRULES. This section is required * This routine must be called after the defwNonDefaultRule. * This routine can be called multiple times. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwNonDefaultRuleLayer(const char* layerName, int width, int diagWidth, /* optional(0) */ int spacing, /* optional(0) */ int wireExt); /* optional(0) */ /* Routines to enter NONDEFAULTRULES. This section is optional. * This routine must be called after the defwNonDefaultRule. * This routine can be called multiple times. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwNonDefaultRuleVia(const char* viaName); /* Routines to enter NONDEFAULTRULES. This section is optional. * This routine must be called after the defwNonDefaultRule. * This routine can be called multiple times. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwNonDefaultRuleViaRule(const char* viaRuleName); /* Routines to enter NONDEFAULTRULES. This section is optional. * This routine must be called after the defwNonDefaultRule. * This routine can be called multiple times. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwNonDefaultRuleMinCuts(const char* cutLayerName, int numCutS); /* This is a 5.4 syntax. */ extern int defwEndNonDefaultRules(); /* Routines to enter STYLES. This section is required * The section must start with a defwStartStyles() and * end with defwEndStyles() call. * This is a 5.6 syntax. */ extern int defwStartStyles(int count); /* This routine is for Layer within the NONDEFAULTRULES * This routine can be called multiple times. It is required. * This is a 5.6 syntax. * Returns 0 if successful. */ extern int defwStyles(int styleNums, int num_points, double* xp, double* yp); /* This is a 5.4 syntax. */ extern int defwEndStyles(); /* This routine is called after defwInit. * This routine is optional and it can be called only once. * Returns 0 if successful. */ extern int defwStartBeginext(const char* name); /* This routine is called after defwBeginext. * This routine is optional, it can be called only once. * Returns 0 if successful. */ extern int defwBeginextCreator (const char* creatorName); /* This routine is called after defwBeginext. * This routine is optional, it can be called only once. * It gets the current system time and date. * Returns 0 if successful. */ extern int defwBeginextDate (); /* This routine is called after defwBeginext. * This routine is optional, it can be called only once. * Returns 0 if successful. */ extern int defwBeginextRevision (int vers1, int vers2); /* vers1.vers2 */ /* This routine is called after defwBeginext. * This routine is optional, it can be called many times. * It allows user to customize their own syntax. * Returns 0 if successful. */ extern int defwBeginextSyntax (const char* title, const char* string); /* This routine is called after defwInit. * This routine is optional and it can be called only once. * Returns 0 if successful. */ extern int defwEndBeginext(); /* End the DEF file. * This routine IS NOT OPTIONAL. * The routine must be called LAST. */ extern int defwEnd ( void ); /* General routines that can be called anytime after the Init is called. */ extern int defwCurrentLineNumber ( void ); /* * extern void defwError ( const char *, ... ); * extern void defwWarning ( const char *, ... ); * extern void defwVError ( const char *, va_list ); * extern void defwVWarning ( const char *, va_list ); * extern int defwGetCurrentLineNumber (void); * extern const char *defwGetCurrentFileName (void); */ /* This routine will print the error message. */ extern void defwPrintError(int status); /* This routine will allow user to write their own comemnt. It will * automactically add a # infront of the line. */ extern void defwAddComment(const char* comment); /* This routine will indent 3 blank spaces */ extern void defwAddIndent(); END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defwWriterCalls.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2013-2014, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef DEFI_WRITER_H #define DEFI_WRITER_H #include #include #include "defiKRDefs.hpp" #include "defiDefs.hpp" #include "defiUser.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE /* * The main writer function. * The file should already be opened. This requirement allows * the writer to be used with stdin or a pipe. The file name * is only used for error messages. The includeSearchPath is * a colon-delimited list of directories in which to find * include files. */ extern int defwWrite ( FILE *file, const char *fileName, defiUserData userData ); /* * Set all of the callbacks that have not yet been set to a function * that will add up how many times a given def data type was ignored * (ie no callback was done). The statistics can later be printed out. */ extern void defwSetRegisterUnusedCallbacks (void); extern void defwPrintUnusedCallbacks (FILE* log); /* * Set/get the client-provided user data. defi doesn't look at * this data at all, it simply passes the opaque defiUserData pointer * back to the application with each callback. The client can * change the data at any time, and it will take effect on the * next callback. The defi writer and writer maintain separate * user data pointers. */ extern void defwSetUserData ( defiUserData ); extern defiUserData defwGetUserData ( void ); /* * An enum describing all of the types of writer callbacks. */ typedef enum { defwUnspecifiedCbkType = 0, defwVersionCbkType, defwCaseSensitiveCbkType, defwBusBitCbkType, defwDividerCbkType, defwDesignCbkType, defwTechCbkType, defwArrayCbkType, defwFloorPlanCbkType, defwUnitsCbkType, defwHistoryCbkType, defwPropDefCbkType, defwDieAreaCbkType, defwRowCbkType, defwTrackCbkType, defwGcellGridCbkType, defwDefaultCapCbkType, defwCanplaceCbkType, defwCannotOccupyCbkType, defwViaCbkType, defwRegionCbkType, defwComponentCbkType, defwPinCbkType, defwPinPropCbkType, defwSNetCbkType, defwNetCbkType, defwIOTimingCbkType, defwScanchainCbkType, defwConstraintCbkType, defwAssertionCbkType, // pre 5.2 defwGroupCbkType, defwBlockageCbkType, // 5.4 defwExtCbkType, defwDesignEndCbkType /* NEW CALLBACKS - each callback has its own type. For each callback * that you add, you must add an item to this enum. */ } defwCallbackType_e; /* Declarations of function signatures for each type of callback. * These declarations are type-safe when compiling with ANSI C * or C++; you will only be able to register a function pointer * with the correct signature for a given type of callback. * * Each callback function is expected to return 0 if successful. * A non-zero return code will cause the writer to abort. * * The defwDesignStart and defwDesignEnd callback is only called once. * Other callbacks may be called multiple times, each time with a different * set of data. * * For each callback, the Def API will make the callback to the * function supplied by the client, which should either make a copy * of the Def object, or store the data in the client's own data structures. * The Def API will delete or reuse each object after making the callback, * so the client should not keep a pointer to it. * * All callbacks pass the user data pointer provided in defwRead() * or defwSetUserData() back to the client; this can be used by the * client to obtain access to the rest of the client's data structures. * * The user data pointer is obtained using defwGetUserData() immediately * prior to making each callback, so the client is free to change the * user data on the fly if necessary. * * Callbacks with the same signature are passed a callback type * parameter, which allows an application to write a single callback * function, register that function for multiple callbacks, then * switch based on the callback type to handle the appropriate type of * data. */ /* A declaration of the signature of all callbacks that return nothing. */ typedef int (*defwVoidCbkFnType) ( defwCallbackType_e, defiUserData ); /* Functions to call to register a callback function. */ extern void defwSetArrayCbk (defwVoidCbkFnType); extern void defwSetAssertionCbk (defwVoidCbkFnType); extern void defwSetBlockageCbk (defwVoidCbkFnType); extern void defwSetBusBitCbk (defwVoidCbkFnType); extern void defwSetCannotOccupyCbk (defwVoidCbkFnType); extern void defwSetCanplaceCbk (defwVoidCbkFnType); extern void defwSetCaseSensitiveCbk (defwVoidCbkFnType); extern void defwSetComponentCbk (defwVoidCbkFnType); extern void defwSetConstraintCbk (defwVoidCbkFnType); extern void defwSetDefaultCapCbk (defwVoidCbkFnType); extern void defwSetDesignCbk (defwVoidCbkFnType); extern void defwSetDesignEndCbk (defwVoidCbkFnType); extern void defwSetDieAreaCbk (defwVoidCbkFnType); extern void defwSetDividerCbk (defwVoidCbkFnType); extern void defwSetExtCbk (defwVoidCbkFnType); extern void defwSetFloorPlanCbk (defwVoidCbkFnType); extern void defwSetGcellGridCbk (defwVoidCbkFnType); extern void defwSetGroupCbk (defwVoidCbkFnType); extern void defwSetHistoryCbk (defwVoidCbkFnType); extern void defwSetIOTimingCbk (defwVoidCbkFnType); extern void defwSetNetCbk (defwVoidCbkFnType); extern void defwSetPinCbk (defwVoidCbkFnType); extern void defwSetPinPropCbk (defwVoidCbkFnType); extern void defwSetPropDefCbk (defwVoidCbkFnType); extern void defwSetRegionCbk (defwVoidCbkFnType); extern void defwSetRowCbk (defwVoidCbkFnType); extern void defwSetSNetCbk (defwVoidCbkFnType); extern void defwSetScanchainCbk (defwVoidCbkFnType); extern void defwSetTechnologyCbk (defwVoidCbkFnType); extern void defwSetTrackCbk (defwVoidCbkFnType); extern void defwSetUnitsCbk (defwVoidCbkFnType); extern void defwSetVersionCbk (defwVoidCbkFnType); extern void defwSetViaCbk (defwVoidCbkFnType); /* NEW CALLBACK - each callback must have a function to allow the user * to set it. Add the function here. */ /* * Set all of the callbacks that have not yet been set to the following * function. This is especially useful if you want to check to see * if you forgot anything. */ extern void defwSetUnusedCallbacks (defwVoidCbkFnType func); /* Routine to set the message logging routine for errors */ #ifndef DEFI_LOG_FUNCTION typedef void (*DEFI_LOG_FUNCTION) (const char*); #endif extern void defwSetLogFunction ( DEFI_LOG_FUNCTION ); /* Routine to set the message logging routine for warnings */ #ifndef DEFI_WARNING_LOG_FUNCTION typedef void (*DEFI_WARNING_LOG_FUNCTION)(const char*); #endif extern void defwSetWarningLogFunction( DEFI_WARNING_LOG_FUNCTION ); END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/def5.8/defzlib.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2015, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef LEFDEFZIP_H #define LEFDEFZIP_H #include "defiDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE typedef void* defGZFile; class defrContext; // // Name: defrSetReadGZipFunction // Description: Sets GZip read function for the parser // Returns: 0 if no errors // extern void defrSetGZipReadFunction(); // // Name: defOpenGZip // Description: Open a gzip file // Returns: A file pointer // extern defGZFile defrGZipOpen(const char* gzipFile, const char* mode); // // Name: defCloseGZip // Description: Close a gzip file // Returns: 0 if no errors // extern int defrGZipClose(defGZFile filePtr); // // Name: defrReadGZip // Description: Parse a def gzip file // Returns: 0 if no errors // extern int defrReadGZip(defGZFile file, const char* gzipFile, void* uData); // // FUNCTIONS TO BE OBSOLETED. // The API is kept only for compatibility reasons. // // // Name: defGZipOpen // Description: Open a gzip file // Returns: A file pointer // extern defGZFile defGZipOpen(const char* gzipFile, const char* mode); // // Name: defGZipClose // Description: Close a gzip file // Returns: 0 if no errors // extern int defGZipClose(defGZFile filePtr); END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiArray.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiArray_h #define lefiArray_h #include #include "lefiKRDefs.hpp" #include "lefiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class lefiArrayFloorPlan { public: void Init(const char* name); void Destroy(); void addSitePattern(const char* typ, lefiSitePattern* s); int numPatterns() const; lefiSitePattern* pattern(int index) const; char* typ(int index) const; const char* name() const; protected: int numPatterns_; int patternsAllocated_; lefiSitePattern** patterns_; char** types_; char* name_; }; class lefiArray { public: lefiArray(); void Init(); void Destroy(); ~lefiArray(); void setName(const char* name); void addSitePattern(lefiSitePattern* s); void setTableSize(int tsize); void addDefaultCap(int minPins, double cap); void addCanPlace(lefiSitePattern* s); void addCannotOccupy(lefiSitePattern* s); void addTrack(lefiTrackPattern* t); void addGcell(lefiGcellPattern* g); void addFloorPlan(const char* name); void addSiteToFloorPlan(const char* typ, lefiSitePattern* p); void clear(); void bump(void*** arr, int used, int* allocated); int numSitePattern() const; int numCanPlace() const; int numCannotOccupy() const; int numTrack() const; int numGcell() const; int hasDefaultCap() const; const char* name() const; lefiSitePattern* sitePattern(int index) const; lefiSitePattern* canPlace(int index) const; lefiSitePattern* cannotOccupy(int index) const; lefiTrackPattern* track(int index) const; lefiGcellPattern* gcell(int index) const; int tableSize() const; int numDefaultCaps() const; int defaultCapMinPins(int index) const; double defaultCap(int index) const; int numFloorPlans() const; const char* floorPlanName(int index) const; int numSites(int index) const; const char* siteType(int floorIndex, int siteIndex) const; lefiSitePattern* site(int floorIndex, int siteIndex) const; // Debug print void print(FILE* f) const; protected: int nameSize_; char* name_; int patternsAllocated_; int numPatterns_; lefiSitePattern** pattern_; int canAllocated_; int numCan_; lefiSitePattern** canPlace_; int cannotAllocated_; int numCannot_; lefiSitePattern** cannotOccupy_; int tracksAllocated_; int numTracks_; lefiTrackPattern** track_; int gAllocated_; int numG_; lefiGcellPattern** gcell_; int hasDefault_; int tableSize_; int numDefault_; int defaultAllocated_; int* minPins_; double* caps_; int numFloorPlans_; int floorPlansAllocated_; lefiArrayFloorPlan** floors_; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiCrossTalk.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiCrossTalk_h #define lefiCrossTalk_h #include #include "lefiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE // Structure returned for the noise margin callback. // This lef construct has two floating point numbers. struct lefiNoiseMargin { double high; double low; }; class lefiNoiseVictim { public: lefiNoiseVictim(double d); void Init(double d); void Destroy(); ~lefiNoiseVictim(); void clear(); void addVictimNoise(double d); double length() const; int numNoises() const; double noise(int index) const; protected: double length_; int numNoises_; int noisesAllocated_; double* noises_; }; class lefiNoiseResistance { public: lefiNoiseResistance(); void Init(); void Destroy(); ~lefiNoiseResistance(); void clear(); void addResistanceNumber(double d); void addVictimLength(double d); void addVictimNoise(double d); int numNums() const; double num(int index) const; int numVictims() const; lefiNoiseVictim* victim(int index) const; protected: int numNums_; int numsAllocated_; double* nums_; int numVictims_; int victimsAllocated_; lefiNoiseVictim** victims_; }; class lefiNoiseEdge { public: lefiNoiseEdge(); void Init(); void Destroy(); ~lefiNoiseEdge(); void clear(); void addEdge(double d); void addResistance(); void addResistanceNumber(double d); void addVictimLength(double d); void addVictimNoise(double d); double edge(); int numResistances(); lefiNoiseResistance* resistance(int index); protected: double edge_; int numResistances_; int resistancesAllocated_; lefiNoiseResistance** resistances_; }; class lefiNoiseTable { public: lefiNoiseTable(); void Init(); void Destroy(); ~lefiNoiseTable(); void setup(int i); void newEdge(); void addEdge(double d); void addResistance(); void addResistanceNumber(double d); void addVictimLength(double d); void addVictimNoise(double d); void clear(); int num(); int numEdges(); lefiNoiseEdge* edge(int index); protected: int num_; int numEdges_; int edgesAllocated_; lefiNoiseEdge** edges_; }; class lefiCorrectionVictim { public: lefiCorrectionVictim(double d); void Init(double d); void Destroy(); ~lefiCorrectionVictim(); void clear(); void addVictimCorrection(double d); double length(); int numCorrections(); double correction(int index); protected: double length_; int numCorrections_; int correctionsAllocated_; double* corrections_; }; class lefiCorrectionResistance { public: lefiCorrectionResistance(); void Init(); void Destroy(); ~lefiCorrectionResistance(); void clear(); void addResistanceNumber(double d); void addVictimLength(double d); void addVictimCorrection(double d); int numNums(); double num(int index); int numVictims(); lefiCorrectionVictim* victim(int index); protected: int numNums_; int numsAllocated_; double* nums_; int numVictims_; int victimsAllocated_; lefiCorrectionVictim** victims_; }; class lefiCorrectionEdge { public: lefiCorrectionEdge(); void Init(); void Destroy(); ~lefiCorrectionEdge(); void clear(); void addEdge(double d); void addResistance(); void addResistanceNumber(double d); void addVictimLength(double d); void addVictimCorrection(double d); double edge(); int numResistances(); lefiCorrectionResistance* resistance(int index); protected: double edge_; int numResistances_; int resistancesAllocated_; lefiCorrectionResistance** resistances_; }; class lefiCorrectionTable { public: lefiCorrectionTable(); void Init(); void Destroy(); ~lefiCorrectionTable(); void setup(int i); void newEdge(); void addEdge(double d); void addResistance(); void addResistanceNumber(double d); void addVictimLength(double d); void addVictimCorrection(double d); void clear(); int num(); int numEdges(); lefiCorrectionEdge* edge(int index); protected: int num_; int numEdges_; int edgesAllocated_; lefiCorrectionEdge** edges_; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiDebug.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiDebug_h #define lefiDebug_h 1 #include "lefiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE // Set flag extern void lefiSetDebug (int num, int value) ; // Read flag extern int lefiDebug (int num) ; // Error reporting routine extern void lefiError (int check, int msgNum, const char* msg); extern const char* CASE(const char *x); END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiDefs.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** // Definitions header file for the DEF Interface #ifndef LEFI_DEFS_H #define LEFI_DEFS_H #include #include #include "lefiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE //=================== General Types and Definitions ================= #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #ifndef NULL #define NULL (0) #endif typedef struct point lefPOINT; struct point { double x; double y; }; typedef struct rect lefRECT; struct rect { lefPOINT ll,ur; }; typedef struct token lefTOKEN; struct token { lefTOKEN *next; int what; int data; lefPOINT pt; }; #define START_LIST 10001 #define POINT_SPEC 10002 #define VIA_SPEC 10003 #define WIDTH_SPEC 10004 #define LAYER_SPEC 10005 #define SHAPE_SPEC 10006 #ifndef MAXINT #define MAXINT 0x7FFFFFFF #endif #ifndef MININT #define MININT 0x80000000 #endif #ifndef MIN #define MIN(x,y) ((x) < (y)? (x) : (y)) #endif #ifndef MIN #define MAX(x,y) ((x) > (y)? (x) : (y)) #endif #define ROUND(x) ((x) >= 0 ? (int)((x)+0.5) : (int)((x)-0.5)) //TOKEN *TokenFromRect(); //=================== Enumerated Types ============================ typedef int lefiBoolean; // Every type of object has a unique identifier, and each object // which is created knows its type, by storing the lefiObjectType_e // as the first member in the structure. typedef enum { // decrease likelihood of accidentally correct values by starting // at an unusual number lefiInvalidObject = 41713, lefiUnknownObject // void * } lefiObjectType_e; // The memory policy controls how an object which refers to or is composed of // other objects manages those sub-objects, particularly when the parent // object is copied or deleted. The policy is specified as an argument to the // constructor or initializer, and it is stored with the parent object. // // The memory policy is a generalization of the common distinction between // deep and shallow copies. When a shallow copy of a parent object is made, // the copy maintains pointers to the original sub-objects, and the original // parent remains responsible for deleting those sub-objects. When a deep // copy of a parent object is made, the copy maintains pointers to new copies // of each of the sub-objects, and the copy is responsible for deleting the // new sub-objects. // // The lefiPrivateSubObjects policy corresponds to a deep copy, while the the // lefiReferencedSubObjects policy corresponds to a shallow copy. Usually an // initial parent object will be created using lefiPrivateSubObjects. When a // copy is made of that parent object, the copy may either maintain its own // private versions of each sub-object, or it may refer to the original // sub-objects. // // In certain cases, it is useful to create a deep copy of a parent object, // even though the new parent object shouldn't be responsible for the new // sub-objects. In this case, the lefiOrphanSubObjects and // lefiAdoptedSubObjects policies may be used. lefiOrphanSubObjects is // specified while creating the deep copy, and then lefiAdoptedSubObjects is // specified while creating another parent which will take on the // responsibility for the orphans. // // An object's memory policy affects only the sub-objects which it directly // controls. Those sub-objects themselves may have the same memory policy as // their parents, or they may have a different memory policy. When a copy is // made of a child sub-object, the memory policy of the child controls // whether deep or shallow copies are made of the grandchildren. // typedef enum { // decrease likelihood of accidentally correct values by starting // at an unusual number lefiInvalidMemoryPolicy = 23950, lefiPrivateSubObjects, // deep copy + delete lefiReferencedSubObjects, // shallow copy, no delete lefiOrphanSubObjects, // deep copy, no delete lefiAdoptedSubObjects // shallow copy + delete } lefiMemoryPolicy_e; // An opaque pointer for passing user data through from one API // function to another. // A handle which a user can set to point to their own data // on a per-callback basis. (See the comment in lefwWriter.h) #define lefiUserData void * #define lefiUserDataHandle void ** #ifdef __SunOS_4_1_3 extern int strcasecmp(const char*, const char*); #endif #ifdef WIN32 #define strdup _strdup #endif END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiEncryptInt.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef DEFI_ENCRYPTINT_H #define DEFI_ENCRYPTINT_H #include #include "lefiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE // Unable the reader to read encrypted lef file. // This function must be called before lefrRead(). // / extern void lefrEnableReadEncrypted(); END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiKRDefs.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiKRDEFS_h #define lefiKRDEFS_h #define BEGIN_LEFDEF_PARSER_NAMESPACE namespace LefDefParser { #define END_LEFDEF_PARSER_NAMESPACE } #define USE_LEFDEF_PARSER_NAMESPACE using namespace LefDefParser; #endif ================================================ FILE: rsyn/include/lef5.8/lefiLayer.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2015, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiLayer_h #define lefiLayer_h #include #include "lefiKRDefs.hpp" #include "lefiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE typedef enum lefiAntennaEnum { lefiAntennaAR, lefiAntennaDAR, lefiAntennaCAR, lefiAntennaCDAR, lefiAntennaAF, lefiAntennaSAR, lefiAntennaDSAR, lefiAntennaCSAR, lefiAntennaCDSAR, lefiAntennaSAF, lefiAntennaO, lefiAntennaADR } lefiAntennaEnum; class lefiAntennaPWL { public: lefiAntennaPWL(); ~lefiAntennaPWL(); static lefiAntennaPWL* create(); void Init(); void clear(); void Destroy(); void addAntennaPWL(double d, double r); int numPWL() const; double PWLdiffusion(int index); double PWLratio(int index); protected: int numAlloc_; int numPWL_; double* d_; double* r_; }; class lefiLayerDensity { public: lefiLayerDensity(); ~lefiLayerDensity(); void Init(const char* type); void Destroy(); void clear(); void setOneEntry(double entry); void addFrequency(int num, double* frequency); void addWidth(int num, double* width); void addTableEntry(int num, double* entry); void addCutarea(int num, double* cutarea); char* type() const; int hasOneEntry() const; double oneEntry() const; int numFrequency() const; double frequency(int index) const; int numWidths() const; double width(int index) const; int numTableEntries() const; double tableEntry(int index) const; int numCutareas() const; double cutArea(int index) const; protected: char* type_; double oneEntry_; int numFrequency_; double* frequency_; int numWidths_; double* widths_; int numTableEntries_; double* tableEntries_; int numCutareas_; double* cutareas_; }; // 5.5 class lefiParallel { public: lefiParallel(); ~lefiParallel(); void Init(); void clear(); void Destroy(); void addParallelLength(int numLength, double* lengths); void addParallelWidth(double width); void addParallelWidthSpacing(int numSpacing, double* spacings); int numLength() const; int numWidth() const; double length(int iLength) const; double width(int iWidth) const; double widthSpacing(int iWidth, int iWidthSpacing) const; protected: int numLength_; int numWidth_; int numWidthAllocated_; double* length_; double* width_; double* widthSpacing_; }; // 5.5 class lefiInfluence { public: lefiInfluence(); ~lefiInfluence(); void Init(); void clear(); void Destroy(); void addInfluence(double width, double distance, double spacing); int numInfluenceEntry() const; double width(int index) const; double distance(int index) const; double spacing(int index) const; protected: int numAllocated_; int numWidth_; int numDistance_; int numSpacing_; double* width_; double* distance_; double* spacing_; }; // 5.7 class lefiTwoWidths { public: lefiTwoWidths(); ~lefiTwoWidths(); void Init(); void clear(); void Destroy(); void addTwoWidths(double width, double runLength, int numSpacing, double* spacings, int hasPRL = 0); int numWidth() const; double width(int iWidth) const; int hasWidthPRL(int iWidth) const; double widthPRL(int iWidth) const; int numWidthSpacing(int iWidth) const; double widthSpacing(int iWidth, int iWidthSpacing) const; protected: int numWidth_; int numWidthAllocated_; double* width_; double* prl_; int* hasPRL_; int* numWidthSpacing_; // each slot contains number of spacing of slot double* widthSpacing_; int* atNsp_; // accumulate total number of spacing }; // 5.5 class lefiSpacingTable { public: lefiSpacingTable(); ~lefiSpacingTable(); void Init(); void clear(); void Destroy(); void addParallelLength(int numLength, double* lengths); void addParallelWidth(double width); void addParallelWidthSpacing(int numSpacing, double* spacing); void setInfluence(); void addInfluence(double width, double distance, double spacing); void addTwoWidths(double width, double runLength, int numSpacing, double* spacing, int hasPRL = 0); // 5.7 int isInfluence() const; lefiInfluence* influence() const; int isParallel() const; lefiParallel* parallel() const; lefiTwoWidths* twoWidths() const; // 5.7 protected: int hasInfluence_; lefiInfluence* influence_; lefiParallel* parallel_; lefiTwoWidths* twoWidths_; // 5.7 }; // 5.7 class lefiOrthogonal { public: lefiOrthogonal(); ~lefiOrthogonal(); void Init(); void Destroy(); void addOrthogonal(double cutWithin, double ortho); int numOrthogonal() const; double cutWithin(int index) const; double orthoSpacing(int index) const; protected: int numAllocated_; int numCutOrtho_; double* cutWithin_; double* ortho_; }; // 5.5 class lefiAntennaModel { public: lefiAntennaModel(); ~lefiAntennaModel(); void Init(); void Destroy(); void setAntennaModel(int oxide); void setAntennaAreaRatio(double value); void setAntennaCumAreaRatio(double value); void setAntennaAreaFactor(double value); void setAntennaSideAreaRatio(double value); void setAntennaCumSideAreaRatio(double value); void setAntennaSideAreaFactor(double value); void setAntennaValue(lefiAntennaEnum antennaType, double value); void setAntennaDUO(lefiAntennaEnum antennaType); void setAntennaPWL(lefiAntennaEnum antennaType, lefiAntennaPWL* pwl); void setAntennaCumRoutingPlusCut(); // 5.7 void setAntennaGatePlusDiff(double value); // 5.7 void setAntennaAreaMinusDiff(double value); // 5.7 int hasAntennaAreaRatio() const; int hasAntennaDiffAreaRatio() const; int hasAntennaDiffAreaRatioPWL() const; int hasAntennaCumAreaRatio() const; int hasAntennaCumDiffAreaRatio() const; int hasAntennaCumDiffAreaRatioPWL() const; int hasAntennaAreaFactor() const; int hasAntennaAreaFactorDUO() const; int hasAntennaSideAreaRatio() const; int hasAntennaDiffSideAreaRatio() const; int hasAntennaDiffSideAreaRatioPWL() const; int hasAntennaCumSideAreaRatio() const; int hasAntennaCumDiffSideAreaRatio() const; int hasAntennaCumDiffSideAreaRatioPWL() const; int hasAntennaSideAreaFactor() const; int hasAntennaSideAreaFactorDUO() const; int hasAntennaCumRoutingPlusCut() const; // 5.7 int hasAntennaGatePlusDiff() const; // 5.7 int hasAntennaAreaMinusDiff() const; // 5.7 int hasAntennaAreaDiffReducePWL() const; // 5.7 char* antennaOxide() const; double antennaAreaRatio() const; double antennaDiffAreaRatio() const; lefiAntennaPWL* antennaDiffAreaRatioPWL() const; double antennaCumAreaRatio() const; double antennaCumDiffAreaRatio() const; lefiAntennaPWL* antennaCumDiffAreaRatioPWL() const; double antennaAreaFactor() const; double antennaSideAreaRatio() const; double antennaDiffSideAreaRatio() const; lefiAntennaPWL* antennaDiffSideAreaRatioPWL() const; double antennaCumSideAreaRatio() const; double antennaCumDiffSideAreaRatio() const; lefiAntennaPWL* antennaCumDiffSideAreaRatioPWL() const; double antennaSideAreaFactor() const; double antennaGatePlusDiff() const; // 5.7 double antennaAreaMinusDiff() const; // 5.7 lefiAntennaPWL* antennaAreaDiffReducePWL() const; // 5.7 protected: int hasAntennaAreaRatio_; int hasAntennaDiffAreaRatio_; int hasAntennaDiffAreaRatioPWL_; int hasAntennaCumAreaRatio_; int hasAntennaCumDiffAreaRatio_; int hasAntennaCumDiffAreaRatioPWL_; int hasAntennaAreaFactor_; int hasAntennaAreaFactorDUO_; int hasAntennaSideAreaRatio_; int hasAntennaDiffSideAreaRatio_; int hasAntennaDiffSideAreaRatioPWL_; int hasAntennaCumSideAreaRatio_; int hasAntennaCumDiffSideAreaRatio_; int hasAntennaCumDiffSideAreaRatioPWL_; int hasAntennaSideAreaFactor_; int hasAntennaSideAreaFactorDUO_; int hasAntennaCumRoutingPlusCut_; // 5.7 int hasAntennaGatePlusDiff_; // 5.7 int hasAntennaAreaMinusDiff_; // 5.7 char* oxide_; double antennaAreaRatio_; double antennaDiffAreaRatio_; lefiAntennaPWL* antennaDiffAreaRatioPWL_; double antennaCumAreaRatio_; double antennaCumDiffAreaRatio_; lefiAntennaPWL* antennaCumDiffAreaRatioPWL_; double antennaAreaFactor_; double antennaSideAreaRatio_; double antennaDiffSideAreaRatio_; lefiAntennaPWL* antennaDiffSideAreaRatioPWL_; double antennaCumSideAreaRatio_; double antennaCumDiffSideAreaRatio_; lefiAntennaPWL* antennaCumDiffSideAreaRatioPWL_; double antennaSideAreaFactor_; double antennaGatePlusDiff_; // 5.7 double antennaAreaMinusDiff_; // 5.7 lefiAntennaPWL* antennaAreaDiffReducePWL_; // 5.7 }; class lefiLayer { public: lefiLayer(); void Init(); void Destroy(); ~lefiLayer(); void clear(); void setName(const char* name); // calls clear to init void setType(const char* typ); void setPitch(double num); void setMask(int num); // 5.8 void setPitchXY(double xdist, double ydist); // 5.6 void setOffset(double num); void setOffsetXY(double xdist, double ydist); // 5.6 void setWidth(double num); void setArea(double num); void setDiagPitch(double dist); // 5.6 void setDiagPitchXY(double xdist, double ydist); // 5.6 void setDiagWidth(double width); // 5.6 void setDiagSpacing(double spacing); // 5.6 void setSpacingMin(double dist); void setSpacingName(const char* spacingName); // for CUT layer void setSpacingLayerStack(); // 5.7 for CUT layer void setSpacingAdjacent(int numCuts, double distance); // 5.5for CUT layer void setSpacingRange(double left, double right); void setSpacingRangeUseLength(); void setSpacingRangeInfluence(double infLength); void setSpacingRangeInfluenceRange(double min, double max); void setSpacingRangeRange(double min, double max); void setSpacingLength(double num); void setSpacingLengthRange(double min, double max); void setSpacingCenterToCenter(); void setSpacingParallelOverlap(); // 5.7 void setSpacingArea(double cutArea); // 5.7 void setSpacingEol(double width, double within); // 5.7 void setSpacingParSW(double space, double within); // 5.7 void setSpacingParTwoEdges(); // 5.7 void setSpacingAdjacentExcept(); // 5.7 void setSpacingSamenet(); // 5.7 void setSpacingSamenetPGonly(); // 5.7 void setSpacingTableOrtho(); // 5.7 void addSpacingTableOrthoWithin(double cutWithin, double ortho); // 5.7 void setMaxFloatingArea(double num); // 5.7 void setArraySpacingLongArray(); // 5.7 void setArraySpacingWidth(double viaWidth); // 5.7 void setArraySpacingCut(double cutSpacing); // 5.7 void addArraySpacingArray(int aCuts, double aSpacing); // 5.7 void setSpacingNotchLength(double minNotchLength); // 5.7 void setSpacingEndOfNotchWidth (double endOfNotchWidth, double minNotchSpacing, double minNotchLength); // 5.7 void setDirection(const char* dir); void setResistance(double num); void setCapacitance(double num); void setHeight(double num); void setWireExtension(double num); void setThickness(double num); void setShrinkage(double num); void setCapMultiplier(double num); void setEdgeCap(double num); void setAntennaArea(double num); void setAntennaLength(double num); void setCurrentDensity(double num); void setCurrentPoint(double width, double current); void setResistancePoint(double width, double res); void setCapacitancePoint(double width, double cap); void addProp(const char* name, const char* value, const char type); void addNumProp(const char* name, const double d, const char* value, const char type); void addAccurrentDensity(const char* type); void setAcOneEntry(double num); void addAcFrequency(); void addAcCutarea(); void addAcTableEntry(); void addAcWidth(); void addDccurrentDensity(const char* type); void setDcOneEntry(double num); void addDcTableEntry(); void addDcWidth(); void addDcCutarea(); void addNumber(double num); void setMaxwidth(double width); // 5.5 void setMinwidth(double width); // 5.5 void addMinenclosedarea(double area); // 5.5 void addMinenclosedareaWidth(double width); // 5.5 void addMinimumcut(int cuts, double width); // 5.5 void addMinimumcutWithin(double cutDistance); // 5.7 void addMinimumcutConnect(const char* direction); // 5.5 void addMinimumcutLengDis(double length, double distance); // 5.5 void addParellelLength(double length); // 5.5 void addParellelSpacing(double width, double spacing); // 5.5 void addParellelWidth(double width); // 5.5 void setProtrusion(double width, double length, double width2); // 5.5 // 5.6 - minstep switch to multiple and added more options void addMinstep(double distance); // 5.5 void addMinstepType(char* type); // 5.6 void addMinstepLengthsum(double maxLength); // 5.6 void addMinstepMaxedges(int maxEdges); // 5.7 void addMinstepMinAdjLength(double minAdjLength); // 5.7 void addMinstepMinBetLength(double minBetLength); // 5.7 void addMinstepXSameCorners(); // 5.7 int getNumber(); // this is for the parser internal use only // 5.5 SPACINGTABLE void addSpacingTable(); void addSpParallelLength(); void addSpParallelWidth(double width); void addSpParallelWidthSpacing(); void setInfluence(); void setSpTwoWidthsHasPRL(int hasPRL); void addSpInfluence(double width, double distance, double spacing); void addSpTwoWidths(double width, double runLength); // 5.7 // 5.6 void addEnclosure(char* enclRule, double overhang1, double overhang2); void addEnclosureWidth(double minWidth); void addEnclosureExceptEC(double cutWithin); // 5.7 void addEnclosureLength(double minLength); // 5.7 void addEnclosureExtraCut(); // 5.7+ void addPreferEnclosure(char* enclRule, double overhang1, double overhang2); void addPreferEnclosureWidth(double minWidth); void setResPerCut(double value); void setDiagMinEdgeLength(double value); void setMinSize(lefiGeometries* geom); // 5.8 // POLYROUTING, MIMCAP, TSV, PASSIVATION, NWELL void setLayerType(const char* lType) ; int hasType() const ; int hasLayerType() const ; // 5.8 - Some layers can be another types // ROUTING can be POLYROUTING or MIMCAP // CUT can be TSV or PASSIVATION // MASTERSLICE can be NWELL int hasMask() const ; // 5.8 int hasPitch() const ; int hasXYPitch() const ; // 5.6 int hasOffset() const ; int hasXYOffset() const ; // 5.6 int hasWidth() const ; int hasArea() const ; int hasDiagPitch() const; // 5.6 int hasXYDiagPitch() const; // 5.6 int hasDiagWidth() const; // 5.6 int hasDiagSpacing() const; // 5.6 int hasSpacingNumber() const ; int hasSpacingName(int index) const ; int hasSpacingLayerStack(int index) const ; // 5.7 int hasSpacingAdjacent(int index) const ; int hasSpacingCenterToCenter(int index) const ; int hasSpacingRange(int index) const ; int hasSpacingRangeUseLengthThreshold(int index) const; int hasSpacingRangeInfluence(int index) const; int hasSpacingRangeInfluenceRange(int index) const; int hasSpacingRangeRange(int index) const; int hasSpacingLengthThreshold(int index) const; int hasSpacingLengthThresholdRange(int index) const; int hasSpacingParallelOverlap(int index) const; // 5.7 int hasSpacingArea(int index) const; // 5.7 int hasSpacingEndOfLine(int index) const; // 5.7 int hasSpacingParellelEdge(int index) const; // 5.7 int hasSpacingTwoEdges(int index) const; // 5.7 int hasSpacingAdjacentExcept(int index) const; // 5.7 int hasSpacingSamenet(int index) const; // 5.7 int hasSpacingSamenetPGonly(int index) const; // 5.7 int hasSpacingNotchLength(int index) const; // 5.7 int hasSpacingEndOfNotchWidth(int index) const; // 5.7 int hasDirection() const ; int hasResistance() const ; int hasResistanceArray() const ; int hasCapacitance() const ; int hasCapacitanceArray() const ; int hasHeight() const ; int hasThickness() const ; int hasWireExtension() const ; int hasShrinkage() const ; int hasCapMultiplier() const ; int hasEdgeCap() const ; int hasAntennaLength() const ; int hasAntennaArea() const ; int hasCurrentDensityPoint() const ; int hasCurrentDensityArray() const ; int hasAccurrentDensity() const; int hasDccurrentDensity() const; int numProps() const; const char* propName(int index) const; const char* propValue(int index) const; double propNumber(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; int numSpacing() const; char* name() const ; const char* type() const ; const char* layerType() const ; // 5.8 double pitch() const ; int mask() const; // 5.8 double pitchX() const ; // 5.6 double pitchY() const ; // 5.6 double offset() const ; double offsetX() const ; // 5.6 double offsetY() const ; // 5.6 double width() const ; double area() const ; double diagPitch() const ; // 5.6 double diagPitchX() const ; // 5.6 double diagPitchY() const ; // 5.6 double diagWidth() const ; // 5.6 double diagSpacing() const ; // 5.6 double spacing(int index) const ; char* spacingName(int index) const ; // for CUT layer int spacingAdjacentCuts(int index) const ; // 5.5 - for CUT layer double spacingAdjacentWithin(int index) const ; // 5.5 - for CUT layer double spacingArea(int index) const; // 5.7 - for CUT layer double spacingRangeMin(int index) const ; double spacingRangeMax(int index) const ; double spacingRangeInfluence(int index) const ; double spacingRangeInfluenceMin(int index) const ; double spacingRangeInfluenceMax(int index) const ; double spacingRangeRangeMin(int index) const ; double spacingRangeRangeMax(int index) const ; double spacingLengthThreshold(int index) const; double spacingLengthThresholdRangeMin(int index) const; double spacingLengthThresholdRangeMax(int index) const; // 5.7 Spacing endofline double spacingEolWidth(int index) const; double spacingEolWithin(int index) const; double spacingParSpace(int index) const; double spacingParWithin(int index) const; // 5.7 Spacing Notch double spacingNotchLength(int index) const; double spacingEndOfNotchWidth(int index) const; double spacingEndOfNotchSpacing(int index) const; double spacingEndOfNotchLength(int index) const; // 5.5 Minimum cut rules int numMinimumcut() const; int minimumcut(int index) const; double minimumcutWidth(int index) const; int hasMinimumcutWithin(int index) const; // 5.7 double minimumcutWithin(int index) const; // 5.7 int hasMinimumcutConnection(int index) const; // FROMABOVE|FROMBELOW const char* minimumcutConnection(int index) const; // FROMABOVE|FROMBELOW int hasMinimumcutNumCuts(int index) const; double minimumcutLength(int index) const; double minimumcutDistance(int index) const; const char* direction() const ; double resistance() const ; double capacitance() const ; double height() const ; double wireExtension() const ; double thickness() const ; double shrinkage() const ; double capMultiplier() const ; double edgeCap() const ; double antennaLength() const ; double antennaArea() const ; double currentDensityPoint() const ; void currentDensityArray(int* numPoints, double** widths, double** current) const ; void capacitanceArray(int* numPoints, double** widths, double** resValues) const ; void resistanceArray(int* numPoints, double** widths, double** capValues) const ; int numAccurrentDensity() const; lefiLayerDensity* accurrent(int index) const; int numDccurrentDensity() const; lefiLayerDensity* dccurrent(int index) const; // 3/23/2000 - Wanda da Rosa. The following are for 5.4 Antenna. // Only 5.4 or 5.3 are allowed in a lef file, but not both void setAntennaAreaRatio(double value); void setAntennaCumAreaRatio(double value); void setAntennaAreaFactor(double value); void setAntennaSideAreaRatio(double value); void setAntennaCumSideAreaRatio(double value); void setAntennaSideAreaFactor(double value); void setAntennaValue(lefiAntennaEnum antennaType, double value); void setAntennaDUO(lefiAntennaEnum antennaType); void setAntennaPWL(lefiAntennaEnum antennaType, lefiAntennaPWL* pwl); void setAntennaCumRoutingPlusCut(); // 5.7 void setAntennaGatePlusDiff(double value); // 5.7 void setAntennaAreaMinusDiff(double value); // 5.7 void addAntennaModel (int aOxide); // 5.5 // 5.5 int numAntennaModel() const; lefiAntennaModel* antennaModel(int index) const; // The following is 8/21/01 5.4 enhancements void setSlotWireWidth(double num); void setSlotWireLength(double num); void setSlotWidth(double num); void setSlotLength(double num); void setMaxAdjacentSlotSpacing(double num); void setMaxCoaxialSlotSpacing(double num); void setMaxEdgeSlotSpacing(double num); void setSplitWireWidth(double num); void setMinimumDensity(double num); void setMaximumDensity(double num); void setDensityCheckWindow(double length, double width); void setDensityCheckStep(double num); void setFillActiveSpacing(double num); int hasSlotWireWidth() const; int hasSlotWireLength() const; int hasSlotWidth() const; int hasSlotLength() const; int hasMaxAdjacentSlotSpacing() const; int hasMaxCoaxialSlotSpacing() const; int hasMaxEdgeSlotSpacing() const; int hasSplitWireWidth() const; int hasMinimumDensity() const; int hasMaximumDensity() const; int hasDensityCheckWindow() const; int hasDensityCheckStep() const; int hasFillActiveSpacing() const; int hasMaxwidth() const; // 5.5 int hasMinwidth() const; // 5.5 int hasMinstep() const; // 5.5 int hasProtrusion() const; // 5.5 double slotWireWidth() const; double slotWireLength() const; double slotWidth() const; double slotLength() const; double maxAdjacentSlotSpacing() const; double maxCoaxialSlotSpacing() const; double maxEdgeSlotSpacing() const; double splitWireWidth() const; double minimumDensity() const; double maximumDensity() const; double densityCheckWindowLength() const; double densityCheckWindowWidth() const; double densityCheckStep() const; double fillActiveSpacing() const; double maxwidth() const; // 5.5 double minwidth() const; // 5.5 double protrusionWidth1() const; // 5.5 double protrusionLength() const; // 5.5 double protrusionWidth2() const; // 5.5 int numMinstep() const; // 5.6 double minstep(int index) const; // 5.5, 5.6 switch to multiple int hasMinstepType(int index) const; // 5.6 char* minstepType(int index) const; // 5.6 int hasMinstepLengthsum(int index) const; // 5.6 double minstepLengthsum(int index) const; // 5.6 int hasMinstepMaxedges(int index) const; // 5.7 int minstepMaxedges(int index) const; // 5.7 int hasMinstepMinAdjLength(int index) const; // 5.7 double minstepMinAdjLength(int index) const; // 5.7 int hasMinstepMinBetLength(int index) const; // 5.7 double minstepMinBetLength(int index) const; // 5.7 int hasMinstepXSameCorners(int index) const; // 5.7 // 5.5 MINENCLOSEDAREA int numMinenclosedarea() const; double minenclosedarea(int index) const; int hasMinenclosedareaWidth(int index) const; double minenclosedareaWidth(int index) const; // 5.5 SPACINGTABLE FOR LAYER ROUTING int numSpacingTable(); lefiSpacingTable* spacingTable(int index); // 5.6 ENCLOSURE, PREFERENCLOSURE, RESISTANCEPERCUT & DIAGMINEDGELENGTH int numEnclosure() const; int hasEnclosureRule(int index) const; char* enclosureRule(int index) ; double enclosureOverhang1(int index) const; double enclosureOverhang2(int index) const; int hasEnclosureWidth(int index) const; double enclosureMinWidth(int index) const; int hasEnclosureExceptExtraCut(int index) const; // 5.7 double enclosureExceptExtraCut(int index) const; // 5.7 int hasEnclosureMinLength(int index) const; // 5.7 double enclosureMinLength(int index) const; // 5.7 int numPreferEnclosure() const; int hasPreferEnclosureRule(int index) const; char* preferEnclosureRule(int index) ; double preferEnclosureOverhang1(int index) const; double preferEnclosureOverhang2(int index) const; int hasPreferEnclosureWidth(int index) const; double preferEnclosureMinWidth(int index) const; int hasResistancePerCut() const; double resistancePerCut() const; int hasDiagMinEdgeLength() const; double diagMinEdgeLength() const; int numMinSize() const; double minSizeWidth(int index) const; double minSizeLength(int index) const; // 5.7 int hasMaxFloatingArea() const; double maxFloatingArea() const; int hasArraySpacing() const; int hasLongArray() const; int hasViaWidth() const; double viaWidth() const; double cutSpacing() const; int numArrayCuts() const; int arrayCuts(int index) const; double arraySpacing(int index) const; int hasSpacingTableOrtho() const; // SPACINGTABLE ORTHOGONAL FOR LAYER CUT lefiOrthogonal *orthogonal() const; void parse65nmRules(); // 5.7 void parseLEF58Layer(); // 5.8 int need58PropsProcessing() const; // 5.8 // Debug print void print(FILE* f) const; private: void parseSpacing(int index); void parseMaxFloating(int index); void parseArraySpacing(int index); void parseMinstep(int index); void parseAntennaCumRouting(int index); void parseAntennaGatePlus(int index); void parseAntennaAreaMinus(int index); void parseAntennaAreaDiff(int index); void parseLayerType(int index); // 5.8 void parseLayerEnclosure(int index); // 5.8 void parseLayerWidthTable(int indxe); // 5.8 protected: char* name_; int nameSize_; char* type_; int typeSize_; char* layerType_; // 5.8 - POLYROUTING, MIMCAP, TSV, PASSIVATION, NWELL int hasPitch_; int hasMask_; // 5.8 native int hasOffset_; int hasWidth_; int hasArea_; int hasSpacing_; int hasDiagPitch_; // 5.6 int hasDiagWidth_; // 5.6 int hasDiagSpacing_; // 5.6 int* hasSpacingName_; // 5.5 int* hasSpacingLayerStack_; // 5.7 int* hasSpacingAdjacent_; // 5.5 int* hasSpacingRange_; // pcr 409334 int* hasSpacingUseLengthThreshold_; // pcr 282799, due to mult. spacing allow int* hasSpacingLengthThreshold_; // pcr 409334 int* hasSpacingCenterToCenter_; // 5.6 int* hasSpacingParallelOverlap_; // 5.7 int* hasSpacingCutArea_; // 5.7 int* hasSpacingEndOfLine_; // 5.7 int* hasSpacingParellelEdge_; // 5.7 int* hasSpacingTwoEdges_; // 5.7 int* hasSpacingAdjacentExcept_; // 5.7 int* hasSpacingSamenet_; // 5.7 int* hasSpacingSamenetPGonly_; // 5.7 int hasArraySpacing_; // 5.7 int hasDirection_; int hasResistance_; int hasCapacitance_; int hasHeight_; int hasWireExtension_; int hasThickness_; int hasShrinkage_; int hasCapMultiplier_; int hasEdgeCap_; int hasAntennaArea_; int hasAntennaLength_; int hasCurrentDensityPoint_; double currentDensity_; double pitchX_; // 5.6 double pitchY_; // 5.6 double offsetX_; // 5.6 double offsetY_; // 5.6 double diagPitchX_; // 5.6 double diagPitchY_; // 5.6 double diagWidth_; // 5.6 double diagSpacing_; // 5.6 double width_; double area_; double wireExtension_; int numSpacings_; int spacingsAllocated_; int maskNumber_; // 5.8 double* spacing_; // for Cut & routing Layer, spacing is multiple char** spacingName_; int* spacingAdjacentCuts_; // 5.5 double* spacingAdjacentWithin_; // 5.5 double* spacingCutArea_; // 5.7 double* rangeMin_; // pcr 282799 & 408930, due to mult spacing allow double* rangeMax_; // pcr 282799 & 408930, due to mult spacing allow double* rangeInfluence_; // pcr 282799 & 408930, due to mult spacing allow double* rangeInfluenceRangeMin_; // pcr 388183 & 408930 double* rangeInfluenceRangeMax_; // pcr 388183 & 408930 double* rangeRangeMin_; // pcr 408930 double* rangeRangeMax_; // pcr 408930 double* lengthThreshold_; // pcr 408930 double* lengthThresholdRangeMin_; // pcr 408930 double* lengthThresholdRangeMax_; // pcr 408930 // 5.5 int numMinimumcut_; int minimumcutAllocated_; int* minimumcut_; // pcr 409334 double* minimumcutWidth_; // pcr 409334 int* hasMinimumcutWithin_; // 5.7 double* minimumcutWithin_; // 5.7 int* hasMinimumcutConnection_; char** minimumcutConnection_; int* hasMinimumcutNumCuts_; double* minimumcutLength_; double* minimumcutDistance_; double maxwidth_; // 5.5 double minwidth_; // 5.5 int numMinenclosedarea_; // 5.5 int minenclosedareaAllocated_; // 5.5 double* minenclosedarea_; // 5.5 double* minenclosedareaWidth_; // 5.5 double protrusionWidth1_; // 5.5 double protrusionLength_; // 5.5 double protrusionWidth2_; // 5.5 int numMinstep_; // 5.6 int numMinstepAlloc_; // 5.6 double* minstep_; // 5.6, switch to multiple char** minstepType_; // INSIDECORNER|OUTSIDECORNER|STEP double* minstepLengthsum_; int* minstepMaxEdges_; // 5.7 double* minstepMinAdjLength_; // 5.7 double* minstepMinBetLength_; // 5.7 int* minstepXSameCorners_; // 5.7 char* direction_; double resistance_; double capacitance_; double height_; double thickness_; double shrinkage_; double capMultiplier_; double edgeCap_; double antennaArea_; double antennaLength_; int numCurrentPoints_; int currentPointsAllocated_; double* currentWidths_; double* current_; int numCapacitancePoints_; int capacitancePointsAllocated_; double* capacitanceWidths_; double* capacitances_; int numResistancePoints_; int resistancePointsAllocated_; double* resistanceWidths_; double* resistances_; int numProps_; int propsAllocated_; char** names_; char** values_; double* dvalues_; char* types_; // I: integer, R: real, S:string // Q: quotedstring int numAccurrents_; // number of ACCURRENTDENSITY int accurrentAllocated_; lefiLayerDensity** accurrents_; int numDccurrents_; // number of DCCURRENTDENSITY int dccurrentAllocated_; lefiLayerDensity** dccurrents_; int numNums_; int numAllocated_; double* nums_; // 3/23/2000 - Wanda da Rosa. The following is for 5.4 ANTENNA. // Either 5.4 or 5.3 are allowed, not both int hasAntennaAreaRatio_; int hasAntennaDiffAreaRatio_; int hasAntennaDiffAreaRatioPWL_; int hasAntennaCumAreaRatio_; int hasAntennaCumDiffAreaRatio_; int hasAntennaCumDiffAreaRatioPWL_; int hasAntennaAreaFactor_; int hasAntennaAreaFactorDUO_; int hasAntennaSideAreaRatio_; int hasAntennaDiffSideAreaRatio_; int hasAntennaDiffSideAreaRatioPWL_; int hasAntennaCumSideAreaRatio_; int hasAntennaCumDiffSideAreaRatio_; int hasAntennaCumDiffSideAreaRatioPWL_; int hasAntennaSideAreaFactor_; int hasAntennaSideAreaFactorDUO_; // 5.5 AntennaModel lefiAntennaModel* currentAntennaModel_; int numAntennaModel_; int antennaModelAllocated_; lefiAntennaModel** antennaModel_; // 8/29/2001 - Wanda da Rosa. The following is for 5.4 enhancements. int hasSlotWireWidth_; int hasSlotWireLength_; int hasSlotWidth_; int hasSlotLength_; int hasMaxAdjacentSlotSpacing_; int hasMaxCoaxialSlotSpacing_; int hasMaxEdgeSlotSpacing_; int hasSplitWireWidth_; int hasMinimumDensity_; int hasMaximumDensity_; int hasDensityCheckWindow_; int hasDensityCheckStep_; int hasFillActiveSpacing_; int hasTwoWidthPRL_; double slotWireWidth_; double slotWireLength_; double slotWidth_; double slotLength_; double maxAdjacentSlotSpacing_; double maxCoaxialSlotSpacing_; double maxEdgeSlotSpacing_; double splitWireWidth_; double minimumDensity_; double maximumDensity_; double densityCheckWindowLength_; double densityCheckWindowWidth_; double densityCheckStep_; double fillActiveSpacing_; // 5.5 SPACINGTABLE int numSpacingTable_; int spacingTableAllocated_; lefiSpacingTable** spacingTable_; // 5.6 int numEnclosure_; int enclosureAllocated_; char** enclosureRules_; double* overhang1_; double* overhang2_; double* encminWidth_; double* cutWithin_; double* minLength_; int numPreferEnclosure_; int preferEnclosureAllocated_; char** preferEnclosureRules_; double* preferOverhang1_; double* preferOverhang2_; double* preferMinWidth_; double resPerCut_; double diagMinEdgeLength_; int numMinSize_; double* minSizeWidth_; double* minSizeLength_; // 5.7 double* eolWidth_; double* eolWithin_; double* parSpace_; double* parWithin_; double maxArea_; int hasLongArray_; double viaWidth_; double cutSpacing_; int numArrayCuts_; int arrayCutsAllocated_; int* arrayCuts_; double* arraySpacings_; int hasSpacingTableOrtho_; lefiOrthogonal* spacingTableOrtho_; double* notchLength_; double* endOfNotchWidth_; double* minNotchSpacing_; double* eonotchLength_; int lef58WidthTableOrthoValues_; int lef58WidthTableWrongDirValues_; double* lef58WidthTableOrtho_; double* lef58WidthTableWrongDir_; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiMacro.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2017, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiMacro_h #define lefiMacro_h #include #include "lefiKRDefs.hpp" #include "lefiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class lefiObstruction { public: lefiObstruction(); void Init(); void Destroy(); ~lefiObstruction(); void clear(); void setGeometries(lefiGeometries* g); lefiGeometries* geometries() const; void print(FILE* f) const; protected: lefiGeometries* geometries_; }; // 5.5 class lefiPinAntennaModel { public: lefiPinAntennaModel(); ~lefiPinAntennaModel(); void Init(); void clear(); void Destroy(); void setAntennaModel(int oxide); void addAntennaGateArea(double value, const char* layer); void addAntennaMaxAreaCar(double value, const char* layer); void addAntennaMaxSideAreaCar(double value, const char* layer); void addAntennaMaxCutCar(double value, const char* layer); void setAntennaReturnFlag(int flag); int hasAntennaGateArea() const; int hasAntennaMaxAreaCar() const; int hasAntennaMaxSideAreaCar() const; int hasAntennaMaxCutCar() const; char* antennaOxide() const; int numAntennaGateArea() const; double antennaGateArea(int index) const; const char* antennaGateAreaLayer(int index) const; int numAntennaMaxAreaCar() const; double antennaMaxAreaCar(int index) const; const char* antennaMaxAreaCarLayer(int index) const; int numAntennaMaxSideAreaCar() const; double antennaMaxSideAreaCar(int index) const; const char* antennaMaxSideAreaCarLayer(int index) const; int numAntennaMaxCutCar() const; double antennaMaxCutCar(int index) const; const char* antennaMaxCutCarLayer(int index) const; int hasReturn() const; protected: char* oxide_; int hasReturn_; int numAntennaGateArea_; int antennaGateAreaAllocated_; double* antennaGateArea_; char** antennaGateAreaLayer_; int numAntennaMaxAreaCar_; int antennaMaxAreaCarAllocated_; double* antennaMaxAreaCar_; char** antennaMaxAreaCarLayer_; int numAntennaMaxSideAreaCar_; int antennaMaxSideAreaCarAllocated_; double* antennaMaxSideAreaCar_; char** antennaMaxSideAreaCarLayer_; int numAntennaMaxCutCar_; int antennaMaxCutCarAllocated_; double* antennaMaxCutCar_; char** antennaMaxCutCarLayer_; }; class lefiPin { public: lefiPin(); void Init(); void Destroy(); ~lefiPin(); void clear(); void bump(char** array, int len, int* size); void setName(const char* name); void addPort(lefiGeometries* g); void addForeign(const char* name, int hasPnt, double x, double y, int orient); void setLEQ(const char* name); void setDirection(const char* name); void setUse(const char* name); void setShape(const char* name); void setMustjoin(const char* name); void setOutMargin(double high, double low); void setOutResistance(double high, double low); void setInMargin(double high, double low); void setPower(double power); void setLeakage(double current); void setMaxload(double capacitance); void setMaxdelay(double delayTime); void setCapacitance(double capacitance); void setResistance(double resistance); void setPulldownres(double resistance); void setTieoffr(double resistance); void setVHI(double voltage); void setVLO(double voltage); void setRiseVoltage(double voltage); void setFallVoltage(double voltage); void setRiseThresh(double capacitance); void setFallThresh(double capacitance); void setRiseSatcur(double current); void setFallSatcur(double current); void setCurrentSource(const char* name); void setTables(const char* highName, const char* lowName); void setProperty(const char* name, const char* value, const char type); void setNumProperty(const char* name, double d, const char* value, const char type); void addAntennaModel(int oxide); // 5.5 void addAntennaSize(double value, const char* layer); void addAntennaMetalArea(double value, const char* layer); void addAntennaMetalLength(double value, const char* layer); void addAntennaPartialMetalArea(double value, const char* layer); void addAntennaPartialMetalSideArea(double value, const char* layer); void addAntennaGateArea(double value, const char* layer); void addAntennaDiffArea(double value, const char* layer); void addAntennaMaxAreaCar(double value, const char* layer); void addAntennaMaxSideAreaCar(double value, const char* layer); void addAntennaPartialCutArea(double value, const char* layer); void addAntennaMaxCutCar(double value, const char* layer); void setRiseSlewLimit(double value); void setFallSlewLimit(double value); void setTaperRule(const char* name); void setNetExpr(const char* name); // 5.6 void setSupplySensitivity(const char* pinName); // 5.6 void setGroundSensitivity(const char* pinName); // 5.6 void bumpProps(); int hasForeign() const; int hasForeignOrient(int index = 0) const; int hasForeignPoint(int index = 0) const; int hasLEQ() const; int hasDirection() const; int hasUse() const; int hasShape() const; int hasMustjoin() const; int hasOutMargin() const; int hasOutResistance() const; int hasInMargin() const; int hasPower() const; int hasLeakage() const; int hasMaxload() const; int hasMaxdelay() const; int hasCapacitance() const; int hasResistance() const; int hasPulldownres() const; int hasTieoffr() const; int hasVHI() const; int hasVLO() const; int hasRiseVoltage() const; int hasFallVoltage() const; int hasRiseThresh() const; int hasFallThresh() const; int hasRiseSatcur() const; int hasFallSatcur() const; int hasCurrentSource() const; int hasTables() const; int hasAntennaSize() const; int hasAntennaMetalArea() const; int hasAntennaMetalLength() const; int hasAntennaPartialMetalArea() const; int hasAntennaPartialMetalSideArea() const; int hasAntennaPartialCutArea() const; int hasAntennaDiffArea() const; int hasAntennaModel() const; // 5.5 int hasTaperRule() const; int hasRiseSlewLimit() const; int hasFallSlewLimit() const; int hasNetExpr() const; // 5.6 int hasSupplySensitivity() const; // 5.6 int hasGroundSensitivity() const; // 5.6 const char* name() const; int numPorts() const; lefiGeometries* port(int index) const; int numForeigns() const; const char* foreignName(int index = 0) const; const char* taperRule() const; int foreignOrient(int index = 0) const; const char* foreignOrientStr(int index = 0) const; double foreignX(int index = 0) const; double foreignY(int index = 0) const; const char* LEQ() const; const char* direction() const; const char* use() const; const char* shape() const; const char* mustjoin() const; double outMarginHigh() const; double outMarginLow() const; double outResistanceHigh() const; double outResistanceLow() const; double inMarginHigh() const; double inMarginLow() const; double power() const; double leakage() const; double maxload() const; double maxdelay() const; double capacitance() const; double resistance() const; double pulldownres() const; double tieoffr() const; double VHI() const; double VLO() const; double riseVoltage() const; double fallVoltage() const; double riseThresh() const; double fallThresh() const; double riseSatcur() const; double fallSatcur() const; double riseSlewLimit() const; double fallSlewLimit() const; const char* currentSource() const; const char* tableHighName() const; const char* tableLowName() const; int numAntennaSize() const; double antennaSize(int index) const; const char* antennaSizeLayer(int index) const; int numAntennaMetalArea() const; double antennaMetalArea(int index) const; const char* antennaMetalAreaLayer(int index) const; int numAntennaMetalLength() const; double antennaMetalLength(int index) const; const char* antennaMetalLengthLayer(int index) const; int numAntennaPartialMetalArea() const; double antennaPartialMetalArea(int index) const; const char* antennaPartialMetalAreaLayer(int index) const; int numAntennaPartialMetalSideArea() const; double antennaPartialMetalSideArea(int index) const; const char* antennaPartialMetalSideAreaLayer(int index) const; int numAntennaPartialCutArea() const; double antennaPartialCutArea(int index) const; const char* antennaPartialCutAreaLayer(int index) const; int numAntennaDiffArea() const; double antennaDiffArea(int index) const; const char* antennaDiffAreaLayer(int index) const; // 5.6 const char* netExpr() const; const char* supplySensitivity() const; const char* groundSensitivity() const; // 5.5 int numAntennaModel() const; lefiPinAntennaModel* antennaModel(int index) const; int numProperties() const; const char* propName(int index) const; const char* propValue(int index) const; double propNum(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; void print(FILE* f) const ; protected: int nameSize_; char* name_; char hasLEQ_; char hasDirection_; char hasUse_; char hasShape_; char hasMustjoin_; char hasOutMargin_; char hasOutResistance_; char hasInMargin_; char hasPower_; char hasLeakage_; char hasMaxload_; char hasMaxdelay_; char hasCapacitance_; char hasResistance_; char hasPulldownres_; char hasTieoffr_; char hasVHI_; char hasVLO_; char hasRiseVoltage_; char hasFallVoltage_; char hasRiseThresh_; char hasFallThresh_; char hasRiseSatcur_; char hasFallSatcur_; char hasCurrentSource_; char hasTables_; char hasAntennasize_; char hasRiseSlewLimit_; char hasFallSlewLimit_; int numForeigns_; int foreignAllocated_; int* hasForeignOrient_; int* hasForeignPoint_; int* foreignOrient_; double* foreignX_; double* foreignY_; char** foreign_; int LEQSize_; char* LEQ_; int mustjoinSize_; char* mustjoin_; double outMarginH_; double outMarginL_; double outResistanceH_; double outResistanceL_; double inMarginH_; double inMarginL_; double power_; double leakage_; double maxload_; double maxdelay_; double capacitance_; double resistance_; double pulldownres_; double tieoffr_; double VHI_; double VLO_; double riseVoltage_; double fallVoltage_; double riseThresh_; double fallThresh_; double riseSatcur_; double fallSatcur_; int lowTableSize_; char* lowTable_; int highTableSize_; char* highTable_; double riseSlewLimit_; double fallSlewLimit_; // 5.5 AntennaModel int numAntennaModel_; int antennaModelAllocated_; int curAntennaModelIndex_; // save the current index of the antenna lefiPinAntennaModel** antennaModel_; int numAntennaSize_; int antennaSizeAllocated_; double* antennaSize_; char** antennaSizeLayer_; int numAntennaMetalArea_; int antennaMetalAreaAllocated_; double* antennaMetalArea_; char** antennaMetalAreaLayer_; int numAntennaMetalLength_; int antennaMetalLengthAllocated_; double* antennaMetalLength_; char** antennaMetalLengthLayer_; int numAntennaPartialMetalArea_; int antennaPartialMetalAreaAllocated_; double* antennaPartialMetalArea_; char** antennaPartialMetalAreaLayer_; int numAntennaPartialMetalSideArea_; int antennaPartialMetalSideAreaAllocated_; double* antennaPartialMetalSideArea_; char** antennaPartialMetalSideAreaLayer_; int numAntennaPartialCutArea_; int antennaPartialCutAreaAllocated_; double* antennaPartialCutArea_; char** antennaPartialCutAreaLayer_; int numAntennaDiffArea_; int antennaDiffAreaAllocated_; double* antennaDiffArea_; char** antennaDiffAreaLayer_; char* taperRule_; char* netEpxr_; char* ssPinName_; char* gsPinName_; char direction_[32]; char use_[12]; char shape_[12]; char currentSource_[12]; int numProperties_; int propertiesAllocated_; char** propNames_; char** propValues_; double* propNums_; char* propTypes_; int numPorts_; int portsAllocated_; lefiGeometries** ports_; }; // 5.6 class lefiDensity { public: lefiDensity(); void Init(); void Destroy(); ~lefiDensity(); void clear(); void addLayer(const char* name); void addRect(double x1, double y1, double x2, double y2, double value); int numLayer() const; char* layerName(int index) const; int numRects(int index) const; lefiGeomRect getRect(int index, int rectIndex) const; double densityValue(int index, int rectIndex) const; void print(FILE* f) const; protected: int numLayers_; int layersAllocated_; char** layerName_; int* numRects_; int* rectsAllocated_; struct lefiGeomRect** rects_; double** densityValue_; }; class lefiMacro { public: lefiMacro(); void Init(); void Destroy(); ~lefiMacro(); void clear(); void bump(char** array, int len, int* size); void setName(const char* name); void setGenerator(const char* name); void setGenerate(const char* name1, const char* name2); void setPower(double d); void setOrigin(double x, double y); void setClass(const char* name); void setSource(const char* name); void setEEQ(const char* name); void setLEQ(const char* name); void setClockType(const char* name); void setProperty(const char* name, const char* value, const char type); void setNumProperty(const char* name, double d, const char* value, const char type); void bumpProps(); // orient=-1 means no orient was specified. void addForeign(const char* name, int hasPnt, double x, double y, int orient); void setXSymmetry(); void setYSymmetry(); void set90Symmetry(); void setSiteName(const char* name); void setSitePattern(lefiSitePattern* p); void setSize(double x, double y); void setBuffer(); void setInverter(); void setFixedMask(int isFixedMask = 0); int hasClass() const; int hasGenerator() const; int hasGenerate() const; int hasPower() const; int hasOrigin() const; int hasEEQ() const; int hasLEQ() const; int hasSource() const; int hasXSymmetry() const; int hasYSymmetry() const; int has90Symmetry() const; int hasSiteName() const; int hasSitePattern() const; int hasSize() const; int hasForeign() const; int hasForeignOrigin(int index = 0) const; int hasForeignOrient(int index = 0) const; int hasForeignPoint(int index = 0) const; int hasClockType() const; int isBuffer() const; int isInverter() const; int isFixedMask() const; int numSitePattern() const; int numProperties() const; const char* propName(int index) const; const char* propValue(int index) const; double propNum(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; const char* name() const; const char* macroClass() const; const char* generator() const; const char* EEQ() const; const char* LEQ() const; const char* source() const; const char* clockType() const; double originX() const; double originY() const; double power() const; void generate(char** name1, char** name2) const; lefiSitePattern* sitePattern(int index) const; const char* siteName() const; double sizeX() const; double sizeY() const; int numForeigns() const; int foreignOrient(int index = 0) const; const char* foreignOrientStr(int index = 0) const; double foreignX(int index = 0) const; double foreignY(int index = 0) const; const char* foreignName(int index = 0) const; // Debug print void print(FILE* f) const; protected: int nameSize_; char* name_; char macroClass_[32]; char source_[12]; int generatorSize_; char* generator_; char hasClass_; char hasGenerator_; char hasGenerate_; char hasPower_; char hasOrigin_; char hasSource_; char hasEEQ_; char hasLEQ_; char hasSymmetry_; // X=1 Y=2 R90=4 (can be combined) char hasSiteName_; char hasSize_; char hasClockType_; char isBuffer_; char isInverter_; char* EEQ_; int EEQSize_; char* LEQ_; int LEQSize_; char* gen1_; int gen1Size_; char* gen2_; int gen2Size_; double power_; double originX_; double originY_; double sizeX_; double sizeY_; int numSites_; int sitesAllocated_; lefiSitePattern** pattern_; int numForeigns_; int foreignAllocated_; int* hasForeignOrigin_; int* hasForeignPoint_; int* foreignOrient_; double* foreignX_; double* foreignY_; char** foreign_; int siteNameSize_; char* siteName_; char* clockType_; int clockTypeSize_; int numProperties_; int propertiesAllocated_; char** propNames_; char** propValues_; double* propNums_; char* propTypes_; int isFixedMask_; }; class lefiTiming { public: lefiTiming(); void Init(); void Destroy(); ~lefiTiming(); void addRiseFall(const char* risefall, double one, double two); void addRiseFallVariable(double one, double two); void addRiseFallSlew(double one, double two, double three, double four); void addRiseFallSlew2(double one, double two, double three); void setRiseRS(double one, double two); void setFallRS(double one, double two); void setRiseCS(double one, double two); void setFallCS(double one, double two); void setRiseAtt1(double one, double two); void setFallAtt1(double one, double two); void setRiseTo(double one, double two); void setFallTo(double one, double two); void addUnateness(const char* typ); void setStable(double one, double two, const char* typ); void addTableEntry(double one, double two, double three); void addTableAxisNumber(double one); void addFromPin(const char* name); void addToPin(const char* name); void addDelay(const char* risefall, const char* unateness, double one, double two, double three); void addTransition(const char* risefall, const char* unateness, double one, double two, double three); // addSDF2Pins & addSDF1Pin are for 5.1 void addSDF2Pins(const char* trigType, const char* fromTrig, const char* toTrig, double one, double two, double three); void addSDF1Pin(const char* trigType, double one, double two, double three); void setSDFcondStart(const char* condStart); void setSDFcondEnd(const char* condEnd); void setSDFcond(const char* cond); int hasData(); void clear(); int numFromPins(); const char* fromPin(int index); int numToPins(); const char* toPin(int index); int hasTransition(); int hasDelay(); int hasRiseSlew(); int hasRiseSlew2(); int hasFallSlew(); int hasFallSlew2(); int hasRiseIntrinsic(); int hasFallIntrinsic(); int numOfAxisNumbers(); double* axisNumbers(); int numOfTableEntries(); void tableEntry(int num, double* one, double* two, double* three); const char* delayRiseOrFall(); const char* delayUnateness(); double delayTableOne(); double delayTableTwo(); double delayTableThree(); const char* transitionRiseOrFall(); const char* transitionUnateness(); double transitionTableOne(); double transitionTableTwo(); double transitionTableThree(); double fallIntrinsicOne(); double fallIntrinsicTwo(); double fallIntrinsicThree(); double fallIntrinsicFour(); double riseIntrinsicOne(); double riseIntrinsicTwo(); double riseIntrinsicThree(); double riseIntrinsicFour(); double fallSlewOne(); double fallSlewTwo(); double fallSlewThree(); double fallSlewFour(); double fallSlewFive(); double fallSlewSix(); double fallSlewSeven(); double riseSlewOne(); double riseSlewTwo(); double riseSlewThree(); double riseSlewFour(); double riseSlewFive(); double riseSlewSix(); double riseSlewSeven(); int hasRiseRS(); double riseRSOne(); double riseRSTwo(); int hasRiseCS(); double riseCSOne(); double riseCSTwo(); int hasFallRS(); double fallRSOne(); double fallRSTwo(); int hasFallCS(); double fallCSOne(); double fallCSTwo(); int hasUnateness(); const char* unateness(); int hasRiseAtt1(); double riseAtt1One(); double riseAtt1Two(); int hasFallAtt1(); double fallAtt1One(); double fallAtt1Two(); int hasFallTo(); double fallToOne(); double fallToTwo(); int hasRiseTo(); double riseToOne(); double riseToTwo(); int hasStableTiming(); double stableSetup(); double stableHold(); const char* stableRiseFall(); // The following are for 5.1 int hasSDFonePinTrigger(); int hasSDFtwoPinTrigger(); int hasSDFcondStart(); int hasSDFcondEnd(); int hasSDFcond(); const char* SDFonePinTriggerType(); const char* SDFtwoPinTriggerType(); const char* SDFfromTrigger(); const char* SDFtoTrigger(); double SDFtriggerOne(); double SDFtriggerTwo(); double SDFtriggerThree(); const char* SDFcondStart(); const char* SDFcondEnd(); const char* SDFcond(); protected: int numFrom_; char** from_; int fromAllocated_; int numTo_; char** to_; int toAllocated_; int hasTransition_; int hasDelay_; int hasRiseSlew_; int hasRiseSlew2_; int hasFallSlew_; int hasFallSlew2_; int hasRiseIntrinsic_; int hasFallIntrinsic_; int hasRiseRS_; int hasRiseCS_; int hasFallRS_; int hasFallCS_; int hasUnateness_; int hasFallAtt1_; int hasRiseAtt1_; int hasFallTo_; int hasRiseTo_; int hasStableTiming_; int hasSDFonePinTrigger_; int hasSDFtwoPinTrigger_; int hasSDFcondStart_; int hasSDFcondEnd_; int hasSDFcond_; int nowRise_; int numOfAxisNumbers_; double* axisNumbers_; int axisNumbersAllocated_; int numOfTableEntries_; int tableEntriesAllocated_; double* table_; // three numbers per entry char* delayRiseOrFall_; char* delayUnateness_; double delayTableOne_; double delayTableTwo_; double delayTableThree_; char* transitionRiseOrFall_; char* transitionUnateness_; double transitionTableOne_; double transitionTableTwo_; double transitionTableThree_; double riseIntrinsicOne_; double riseIntrinsicTwo_; double riseIntrinsicThree_; double riseIntrinsicFour_; double fallIntrinsicOne_; double fallIntrinsicTwo_; double fallIntrinsicThree_; double fallIntrinsicFour_; double riseSlewOne_; double riseSlewTwo_; double riseSlewThree_; double riseSlewFour_; double riseSlewFive_; double riseSlewSix_; double riseSlewSeven_; double fallSlewOne_; double fallSlewTwo_; double fallSlewThree_; double fallSlewFour_; double fallSlewFive_; double fallSlewSix_; double fallSlewSeven_; double riseRSOne_; double riseRSTwo_; double riseCSOne_; double riseCSTwo_; double fallRSOne_; double fallRSTwo_; double fallCSOne_; double fallCSTwo_; char* unateness_; double riseAtt1One_; double riseAtt1Two_; double fallAtt1One_; double fallAtt1Two_; double fallToOne_; double fallToTwo_; double riseToOne_; double riseToTwo_; double stableSetup_; double stableHold_; char* stableRiseFall_; char* SDFtriggerType_; char* SDFfromTrigger_; char* SDFtoTrigger_; double SDFtriggerTableOne_; double SDFtriggerTableTwo_; double SDFtriggerTableThree_; char* SDFcondStart_; char* SDFcondEnd_; char* SDFcond_; }; // 5.8 class lefiMacroSite { public: lefiMacroSite(const char *name, const lefiSitePattern* pattern); const char *siteName() const; const lefiSitePattern *sitePattern() const; protected: const char *siteName_; const lefiSitePattern *sitePattern_; }; class lefiMacroForeign { public: lefiMacroForeign(const char *name, int hasPts, double x, double y, int hasOrient, int orient); const char *cellName() const; int cellHasPts() const; double px() const; double py() const; int cellHasOrient() const; int cellOrient() const; protected: const char *cellName_; int cellHasPts_; double px_; double py_; int cellHasOrient_; int cellOrient_; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiMisc.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2014, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiMisc_h #define lefiMisc_h #include #include "lefiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE // The different types of items in a geometry list. struct lefiGeomRect { double xl; double yl; double xh; double yh; int colorMask; }; struct lefiGeomRectIter { double xl; double yl; double xh; double yh; double xStart; double yStart; double xStep; double yStep; int colorMask; }; struct lefiGeomPath { int numPoints; double* x; double* y; int colorMask; }; struct lefiGeomPathIter { int numPoints; double* x; double* y; double xStart; double yStart; double xStep; double yStep; int colorMask; }; struct lefiGeomPolygon { int numPoints; double* x; double* y; int colorMask; }; struct lefiGeomPolygonIter { int numPoints; double* x; double* y; double xStart; double yStart; double xStep; double yStep; int colorMask; }; enum lefiGeomEnum { lefiGeomUnknown = 0, lefiGeomLayerE, lefiGeomLayerExceptPgNetE, lefiGeomLayerMinSpacingE, lefiGeomLayerRuleWidthE, lefiGeomWidthE, lefiGeomPathE, lefiGeomPathIterE, lefiGeomRectE, lefiGeomRectIterE, lefiGeomPolygonE, lefiGeomPolygonIterE, lefiGeomViaE, lefiGeomViaIterE, lefiGeomClassE, lefiGeomEnd }; struct lefiGeomVia { char* name; double x; double y; int topMaskNum; int cutMaskNum; int bottomMaskNum; }; struct lefiGeomViaIter { char* name; double x; double y; double xStart; double yStart; double xStep; double yStep; int topMaskNum; int cutMaskNum; int bottomMaskNum; }; class lefiGeometries { public: lefiGeometries(); void Init(); void Destroy(); ~lefiGeometries(); void clear(); void clearPolyItems(); void add(void* v, lefiGeomEnum e); void addLayer(const char* name); void addLayerExceptPgNet(); // 5.7 void addLayerMinSpacing(double spacing); void addLayerRuleWidth(double width); void addClass(const char* name); void addWidth(double w); void addPath(int colorMask); void addPathIter(int colorMask); /* pcr 481783 & 560504 */ void addRect(int colorMask, double xl, double yl, double xh, double yh); void addRectIter(int colorMask, double xl, double yl, double xh, double yh); void addPolygon(int colorMask = 0); void addPolygonIter(int colorMask); void addVia(int viaMasks, double x, double y, const char* name); void addViaIter(int viaMasks, double x, double y, const char* name); void addStepPattern(double xStart, double yStart, double xStep, double yStep); void startList(double x, double y); void addToList(double x, double y); int numItems() const; lefiGeomEnum itemType(int index) const; lefiGeomRect* getRect(int index) const; lefiGeomRectIter* getRectIter(int index) const; lefiGeomPath* getPath(int index) const; lefiGeomPathIter* getPathIter(int index) const; int hasLayerExceptPgNet(int index) const ; // 5.7 char* getLayer(int index) const; double getLayerMinSpacing(int index) const; double getLayerRuleWidth(int index) const; double getWidth(int index) const; lefiGeomPolygon* getPolygon(int index) const; lefiGeomPolygonIter* getPolygonIter(int index) const; char* getClass(int index) const; lefiGeomVia* getVia(int index) const; lefiGeomViaIter* getViaIter(int index) const; void print(FILE* f) const; protected: int numItems_; int itemsAllocated_; lefiGeomEnum* itemType_; void** items_; int numPoints_; int pointsAllocated_; double* x_; double* y_; double xStart_; double yStart_; double xStep_; double yStep_; }; class lefiSpacing { public: lefiSpacing(); void Init(); void Destroy(); ~lefiSpacing(); lefiSpacing* clone(); void set(const char* name1, const char* name2, double num, int hasStack); int hasStack() const; const char* name1() const; const char* name2() const; double distance() const; // Debug print void print(FILE* f) const; protected: int name1Size_; int name2Size_; char* name1_; char* name2_; double distance_; int hasStack_; }; class lefiIRDrop { public: lefiIRDrop(); void Init(); void Destroy(); ~lefiIRDrop(); void clear(); void setTableName(const char* name); void setValues(double name1, double name2); const char* name() const; double value1(int index) const; double value2(int index) const; int numValues() const; // Debug print void print(FILE* f) const; protected: int nameSize_; int value1Size_; int value2Size_; int numValues_; int valuesAllocated_; char* name_; double* value1_; double* value2_; }; class lefiMinFeature { public: lefiMinFeature(); void Init(); void Destroy(); ~lefiMinFeature(); void set(double one, double two); double one() const; double two() const; // Debug print void print(FILE* f) const; protected: double one_; double two_; }; class lefiSite { public: lefiSite(); void Init(); void Destroy(); ~lefiSite(); void setName(const char* name); void setClass(const char* cls); void setSize(double x, double y); void setXSymmetry(); void setYSymmetry(); void set90Symmetry(); void addRowPattern(const char* name, int orient); const char* name() const; int hasClass() const; const char* siteClass() const; double sizeX() const; double sizeY() const; int hasSize() const; int hasXSymmetry() const; int hasYSymmetry() const; int has90Symmetry() const; int hasRowPattern() const; // 5.6 int numSites() const; // 5.6 char* siteName(int index) const; // 5.6 int siteOrient(int index) const; // 5.6 char* siteOrientStr(int index) const; // 5.6 // Debug print void print(FILE* f) const; protected: int nameSize_; char* name_; int hasClass_; char siteClass_[8]; double sizeX_; double sizeY_; int hasSize_; int symmetry_; // bit 0-x bit 1-y bit 2-90 int numRowPattern_; // 5.6 ROWPATTERN int rowPatternAllocated_; char** siteNames_; int* siteOrients_; }; class lefiSitePattern { public: lefiSitePattern(); void Init(); void Destroy(); ~lefiSitePattern(); void set(const char* name, double x, double y, int orient, double xStart, double yStart, double xStep, double yStep); const char* name() const; int orient() const; const char* orientStr() const; double x() const; double y() const; int hasStepPattern() const; // 5.6 double xStart() const; double yStart() const; double xStep() const; double yStep() const; // Debug print void print(FILE* f) const; protected: int nameSize_; char* name_; int orient_; double x_; double y_; double xStart_; double yStart_; double xStep_; double yStep_; }; class lefiTrackPattern { public: lefiTrackPattern(); void Init(); void Destroy(); ~lefiTrackPattern(); void clear(); void set(const char* name, double start, int numTracks, double space); void addLayer(const char* name); const char* name() const; double start() const; int numTracks() const; double space() const; int numLayers() const; const char* layerName(int index) const; // Debug print void print(FILE* f) const; protected: int nameSize_; char* name_; double start_; int numTracks_; double space_; int numLayers_; int layerAllocated_; char** layerNames_; }; class lefiGcellPattern { public: lefiGcellPattern(); void Init(); void Destroy(); ~lefiGcellPattern(); void set(const char* name, double start, int numCRs, double space); const char* name() const; double start() const; int numCRs() const; double space() const; // Debug print void print(FILE* f) const; protected: int nameSize_; char* name_; double start_; int numCRs_; double space_; }; class lefiUseMinSpacing { public: lefiUseMinSpacing(); void Init(); void Destroy(); ~lefiUseMinSpacing(); void set(const char* name, int value); const char* name() const; int value() const; // Debug print void print(FILE* f) const; protected: char* name_; int value_; }; // 5.5 for Maximum Stacked-via rule class lefiMaxStackVia { public: lefiMaxStackVia(); void Init(); void Destroy(); ~lefiMaxStackVia(); void clear(); void setMaxStackVia(int value); void setMaxStackViaRange(const char* bottomLayer, const char* topLayer); int maxStackVia() const; int hasMaxStackViaRange() const; const char* maxStackViaBottomLayer() const; const char* maxStackViaTopLayer() const; // Debug print void print(FILE* f) const; protected: int value_; int hasRange_; char* bottomLayer_; char* topLayer_; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiNonDefault.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiNonDefault_h #define lefiNonDefault_h #include #include "lefiKRDefs.hpp" #include "lefiVia.hpp" #include "lefiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class lefiNonDefault { public: lefiNonDefault(); void Init(); void Destroy(); ~lefiNonDefault(); void setName(const char* name); void addLayer(const char* name); void addWidth(double num); void addWireExtension(double num); void addSpacing(double num); void addSpacingRule(lefiSpacing* s); void addResistance(double num); void addCapacitance(double num); void addEdgeCap(double num); void addViaRule(lefiVia* v); void addDiagWidth(double num); // 5.6 void end(); void clear(); void addProp(const char* name, const char* value, const char type); void addNumProp(const char* name, const double d, const char* value, const char type); void setHardspacing(); // 5.6 void addUseVia(const char* name); // 5.6 void addUseViaRule(const char* name); // 5.6 void addMinCuts(const char* name, int numCuts); // 5.6 const char* name() const; int hasHardspacing() const; // 5.6 int numProps() const; const char* propName(int index) const; const char* propValue(int index) const; double propNumber(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; // A non default rule can have one or more layers. // The layer information is kept in an array. int numLayers() const ; const char* layerName(int index) const ; int hasLayerWidth(int index) const; double layerWidth(int index) const ; int hasLayerSpacing(int index) const ; double layerSpacing(int index) const ; int hasLayerWireExtension(int index) const ; double layerWireExtension(int index) const ; int hasLayerResistance(int index) const; // obsolete in 5.6 double layerResistance(int index) const; // obsolete in 5.6 int hasLayerCapacitance(int index) const; // obsolete in 5.6 double layerCapacitance(int index) const; // obsolete in 5.6 int hasLayerEdgeCap(int index) const; // obsolete in 5.6 double layerEdgeCap(int index) const; // obsolete in 5.6 int hasLayerDiagWidth(int index) const; // 5.6 double layerDiagWidth(int index) const; // 5.6 // A non default rule can have one or more vias. // These routines return the via info. int numVias() const ; lefiVia* viaRule(int index) const ; // A non default rule can have one or more spacing rules. // These routines return the that info. int numSpacingRules() const ; lefiSpacing* spacingRule(int index) const ; int numUseVia() const; // 5.6 const char* viaName(int index) const; // 5.6 int numUseViaRule() const; // 5.6 const char* viaRuleName(int index) const; // 5.6 int numMinCuts() const; // 5.6 const char* cutLayerName(int index) const; // 5.6 int numCuts(int index) const; // 5.6 // Debug print void print(FILE* f); protected: int nameSize_; char* name_; // Layer information int numLayers_; int layersAllocated_; char** layerName_; double* width_; double* spacing_; double* wireExtension_; char* hasWidth_; char* hasSpacing_; char* hasWireExtension_; // 5.4 double* resistance_; double* capacitance_; double* edgeCap_; char* hasResistance_; char* hasCapacitance_; char* hasEdgeCap_; double* diagWidth_; // 5.6 char* hasDiagWidth_; // 5.6 int numVias_; int allocatedVias_; lefiVia** viaRules_; int numSpacing_; int allocatedSpacing_; lefiSpacing** spacingRules_; int hardSpacing_; // 5.6 int numUseVias_; // 5.6 int allocatedUseVias_; // 5.6 char** useViaName_; // 5.6 int numUseViaRules_; // 5.6 int allocatedUseViaRules_; // 5.6 char** useViaRuleName_; // 5.6 int numMinCuts_; // 5.6 int allocatedMinCuts_; // 5.6 char** cutLayerName_; // 5.6 int* numCuts_; // 5.6 int numProps_; int propsAllocated_; char** names_; char** values_; double* dvalues_; char* types_; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiProp.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiProp_h #define lefiProp_h #include "lefiKRDefs.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE // Struct holds the data for one property. class lefiProp { public: lefiProp(); void Init(); void Destroy(); ~lefiProp(); void setPropType(const char* typ, const char* string); void setRange(double left, double right); void setNumber(double num); void setPropInteger(); void setPropReal(); void setPropString(); void setPropQString(const char* string); void setPropNameMapString(const char* string); void clear(); const char* string() const; const char* propType() const; const char* propName() const; char dataType() const; // either I:integer R:real S:string Q:quotedstring // N:property name is not defined in the property definition section int hasNumber() const; int hasRange() const; int hasString() const; int hasNameMapString() const; double number() const; double left() const; double right() const; void bumpSize(int size); void bumpName(int size); void print(FILE* f) const; protected: char* propType_; // "design" "net" "macro" ... char* propName_; // name. int nameSize_; // allocated size of name. char hasRange_; // either 0:NO or 1:YES. char hasNumber_; // either 0:NO or 1:YES. char hasNameMapString_; char dataType_; // either I:integer R:real S:string Q:quotedstring. // N:property name is not defined. char* stringData_; // if it is a string the data is here. int stringLength_; // allocated size of stringData. double left_; double right_; // if it has a range the numbers are here. double d_; // if it is a real or int the number is here. }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiPropType.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiPropType_h #define lefiPropType_h #include "lefiKRDefs.hpp" #include BEGIN_LEFDEF_PARSER_NAMESPACE // Struct holds the data type for one property, if the property is // either REAL or INTEGER. class lefiPropType { public: lefiPropType(); void Init(); void Destroy(); ~lefiPropType(); void setPropType(const char* name, const char type); void Clear(); const char propType(char* name) const; void bumpProps(); protected: int numProperties_; int propertiesAllocated_; char** propNames_; // name. char* propTypes_; // 'R' == "REAL", 'I' == "INTEGER" }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiUnits.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiUnits_h #define lefiUnits_h #include #include "lefiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class lefiUnits { public: lefiUnits(); void Init(); void Destroy(); ~lefiUnits(); void setDatabase(const char* name, double num); void clear(); void setTime(double num); void setCapacitance(double num); void setResistance(double num); void setPower(double num); void setCurrent(double num); void setVoltage(double num); void setFrequency(double num); int hasDatabase() const; int hasCapacitance()const; int hasResistance() const; int hasTime() const; int hasPower() const; int hasCurrent() const; int hasVoltage() const; int hasFrequency() const; const char* databaseName() const; double databaseNumber() const; double capacitance() const; double resistance() const; double time() const; double power() const; double current() const; double voltage() const; double frequency() const; // Debug print void print(FILE* f) const ; protected: int hasDatabase_; int hasCapacitance_; int hasResistance_; int hasTime_; int hasPower_; int hasCurrent_; int hasVoltage_; int hasFrequency_; char* databaseName_; double databaseNumber_; double capacitance_; double resistance_; double power_; double time_; double current_; double voltage_; double frequency_; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiUser.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** // User header file for the LEF Interface. This includes // all of the header files which are relevant to both the // reader and the writer. // // lefrReader.h and lefwWriter.h include this file, so that // an application only needs to include either lefrReader.h(pp) // or lefwWriter.h(pp). // #ifndef LEFI_USER_H #define LEFI_USER_H #include "lefiDebug.hpp" #include "lefiUnits.hpp" #include "lefiLayer.hpp" #include "lefiVia.hpp" #include "lefiViaRule.hpp" #include "lefiMisc.hpp" #include "lefiNonDefault.hpp" #include "lefiMacro.hpp" #include "lefiArray.hpp" #include "lefiCrossTalk.hpp" #include "lefiProp.hpp" #include "lefiPropType.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE // NEW CALLBACK add the reference here END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiUtil.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiUtil_h #define lefiUtil_h #include "lefiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE // Structure to return Macro data to FE struct lefiPoints { double x; double y; }; typedef struct lefiPoints lefiNum; //int lefiValidTime(); extern int lefiValidUser(); extern char* lefiUser(); extern char* lefiOrientStr(int orient); extern double convert_name2num(const char *versionName); extern bool validateMaskNumber(int num); END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiVia.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiVia_h #define lefiVia_h #include #include "lefiKRDefs.hpp" #include "lefiMisc.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class lefiViaLayer { public: lefiViaLayer(); void Init(); void Destroy(); ~lefiViaLayer(); void setName(const char* name); void addRect(int mask, double xl, double yl, double xh, double yh); void addPoly(int mask, lefiGeometries* geom); lefiViaLayer* clone(); int numRects(); char* name(); double xl(int index); double yl(int index); double xh(int index); double yh(int index); int rectColorMask(int index); int polyColorMask(int index); int numPolygons(); // 5.6 lefiGeomPolygon* getPolygon(int index) const; // 5.6 protected: char* name_; int* rectColorMask_; int* polyColorMask_; int numRects_; int rectsAllocated_; double* xl_; double* yl_; double* xh_; double* yh_; int numPolys_; int polysAllocated_; lefiGeomPolygon** polygons_; }; class lefiVia { public: lefiVia(); void Init(); void Destroy(); ~lefiVia(); void clear(); // setName calls clear to init // deflt=0 no default specified // deflt=1 default specified in lef file void setName(const char* name, int viaType); void setResistance(double num); void addProp(const char* name, const char* value, const char type); void addNumProp(const char* name, double d, const char* value, const char type); // orient=-1 means no orient was specified. void setForeign(const char* name, int hasPnt, double x, double y, int orient); void setTopOfStack(); void addLayer(const char* name); void addRectToLayer(int mask, double xl, double yl, double xh, double yh); void addPolyToLayer(int mask, lefiGeometries* geom); void bumpProps(); void setViaRule(const char* viaRuleName, double xSize, double ySize, const char* botLayer, const char* cutLayer, const char* topLayer, double xCut, double yCut, double xBotEnc, double yBotEnc, double xTopEnc, double yTopEnc); // 5.6 void setRowCol(int numRows, int numCols); // 5.6 void setOrigin(double xOffset, double yOffset); // 5.6 void setOffset(double xBot, double yBot, double xTop, double yTop); // 5.6 void setPattern(const char* cutPattern); // 5.6 // make a new one lefiVia* clone(); int hasDefault() const ; int hasGenerated() const ; // 5.6, this no longer in 5.6, should be removed int hasForeign() const ; int hasForeignPnt() const ; int hasForeignOrient() const ; int hasProperties() const ; int hasResistance() const ; int hasTopOfStack() const ; int numLayers() const; char* layerName(int layerNum) const; int numRects(int layerNum) const; double xl(int layerNum, int rectNum) const; double yl(int layerNum, int rectNum) const; double xh(int layerNum, int rectNum) const; double yh(int layerNum, int rectNum) const; int rectColorMask(int layerNum, int rectNum) const; int polyColorMask(int layerNum, int polyNum) const; int numPolygons(int layerNum) const; // 5.6 lefiGeomPolygon getPolygon(int layerNum, int polyNum) const; // 5.6 char* name() const ; double resistance() const ; // Given an index from 0 to numProperties()-1 return // information about that property. int numProperties() const ; char* propName(int index) const; char* propValue(int index) const; double propNumber(int index) const; char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; char* foreign() const; double foreignX() const; double foreignY() const; int foreignOrient() const; char* foreignOrientStr() const; // 5.6 VIARULE inside a VIA int hasViaRule() const; const char* viaRuleName() const; double xCutSize() const; double yCutSize() const; const char* botMetalLayer() const; const char* cutLayer() const; const char* topMetalLayer() const; double xCutSpacing() const; double yCutSpacing() const; double xBotEnc() const; double yBotEnc() const; double xTopEnc() const; double yTopEnc() const; int hasRowCol() const; int numCutRows() const; int numCutCols() const; int hasOrigin() const; double xOffset() const; double yOffset() const; int hasOffset() const; double xBotOffset() const; double yBotOffset() const; double xTopOffset() const; double yTopOffset() const; int hasCutPattern() const; const char* cutPattern() const; // Debug print void print(FILE* f) const; protected: char* name_; int nameSize_; int hasDefault_; int hasGenerated_; int hasResistance_; int hasForeignPnt_; int hasTopOfStack_; int numProps_; int propsAllocated_; char** propName_; // The prop value is stored in the propValue_ or the propDValue_. // If it is a string it is in propValue_. If it is a number, // then propValue_ is NULL and it is stored in propDValue_; char** propValue_; double* propDValue_; char* propType_; int numLayers_; int layersAllocated_; lefiViaLayer** layers_; double resistance_; char* foreign_; double foreignX_; double foreignY_; int foreignOrient_; char* viaRuleName_; // 5.6 double xSize_; // 5.6 double ySize_; // 5.6 char* botLayer_; // 5.6 char* cutLayer_; // 5.6 char* topLayer_; // 5.6 double xSpacing_; // 5.6 double ySpacing_; // 5.6 double xBotEnc_; // 5.6 double yBotEnc_; // 5.6 double xTopEnc_; // 5.6 double yTopEnc_; // 5.6 int numRows_; // 5.6 int numCols_; // 5.6 double xOffset_; // 5.6 double yOffset_; // 5.6 double xBotOs_; // 5.6 double yBotOs_; // 5.6 double xTopOs_; // 5.6 double yTopOs_; // 5.6 char* cutPattern_; // 5.6 }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefiViaRule.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefiViaRule_h #define lefiViaRule_h #include #include "lefiKRDefs.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class lefiViaRuleLayer { public: lefiViaRuleLayer(); void Init(); void Destroy(); ~lefiViaRuleLayer(); void clearLayerOverhang(); void setName(const char* name); void setHorizontal(); void setVertical(); void setEnclosure(double overhang1, double overhang2); // 5.5 void setWidth(double minW, double maxW); void setOverhang(double d); void setOverhangToEnclosure(double d); // 5.6 void setMetalOverhang(double d); void setResistance(double d); void setSpacing(double x, double y); void setRect(double xl, double yl, double xh, double yh); int hasDirection() const ; int hasEnclosure() const ; // 5.5 int hasWidth() const ; int hasResistance() const ; int hasOverhang() const ; int hasMetalOverhang() const ; int hasSpacing() const ; int hasRect() const ; char* name() const ; int isHorizontal() const ; int isVertical() const ; double enclosureOverhang1() const; // 5.5 double enclosureOverhang2() const; // 5.5 double widthMin() const ; double widthMax() const ; double overhang() const ; double metalOverhang() const ; double resistance() const ; double spacingStepX() const ; double spacingStepY() const ; double xl() const ; double yl() const ; double xh() const ; double yh() const ; // Debug print void print(FILE* f) const; protected: char* name_; char direction_; double overhang1_; // 5.5 double overhang2_; // 5.5 int hasWidth_; int hasResistance_; int hasOverhang_; int hasMetalOverhang_; int hasSpacing_; int hasRect_; double widthMin_; double widthMax_; double overhang_; double metalOverhang_; double resistance_; double spacingStepX_; double spacingStepY_; double xl_, yl_, xh_, yh_; }; class lefiViaRule { public: lefiViaRule(); void Init(); void clear(); void clearLayerOverhang(); void Destroy(); ~lefiViaRule(); void setGenerate(); void setDefault(); // This should clear out all the old stuff. void setName(const char* name); // Add one of possibly many via names void addViaName(const char* name); // These routines set a part of the active layer. void setRect(double xl, double yl, double xh, double yh); void setSpacing(double x, double y); void setWidth(double x, double y); void setResistance(double d); void setOverhang(double d); void setOverhangToEnclosure(double d); // 5.6 void setMetalOverhang(double d); void setVertical(); void setHorizontal(); void setEnclosure(double overhang1, double overhang2); void addProp(const char* name, const char* value, const char type); void addNumProp(const char* name, const double d, const char* value, const char type); // This routine sets and creates the active layer. void setLayer(const char* name); int hasGenerate() const ; int hasDefault() const ; char* name() const ; // There are 2 or 3 layers in a rule. // numLayers() tells how many. // If a third layer exists then it is the cut layer. int numLayers() const ; lefiViaRuleLayer* layer(int index) const; int numVias() const ; char* viaName(int index) const ; int numProps() const; const char* propName(int index) const; const char* propValue(int index) const; double propNumber(int index) const; const char propType(int index) const; int propIsNumber(int index) const; int propIsString(int index) const; // Debug print void print(FILE* f) const; protected: char* name_; int nameSize_; int hasGenerate_; int hasDefault_; int numLayers_; lefiViaRuleLayer layers_[3]; int numVias_; int viasAllocated_; char** vias_; int numProps_; int propsAllocated_; char** names_; char** values_; double* dvalues_; char* types_; }; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefrCallBacks.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2017, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefrCallbacks_h #define lefrCallbacks_h #include "lefiKRDefs.hpp" #include "lefrReader.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE class lefrCallbacks { public: lefrCallbacks(); static void reset(); // List of call back routines // These are filled in by the user. See the // "set" routines at the end of the file lefrDoubleCbkFnType AntennaInoutCbk; lefrDoubleCbkFnType AntennaInputCbk; lefrDoubleCbkFnType AntennaOutputCbk; lefrStringCbkFnType ArrayBeginCbk; lefrArrayCbkFnType ArrayCbk; lefrStringCbkFnType ArrayEndCbk; lefrStringCbkFnType BusBitCharsCbk; lefrIntegerCbkFnType CaseSensitiveCbk; lefrStringCbkFnType ClearanceMeasureCbk; lefrCorrectionTableCbkFnType CorrectionTableCbk; lefrDensityCbkFnType DensityCbk; lefrDoubleCbkFnType DielectricCbk; lefrStringCbkFnType DividerCharCbk; lefrDoubleCbkFnType EdgeRateScaleFactorCbk; lefrDoubleCbkFnType EdgeRateThreshold1Cbk; lefrDoubleCbkFnType EdgeRateThreshold2Cbk; lefrStringCbkFnType ExtensionCbk; lefrIntegerCbkFnType FixedMaskCbk; lefrVoidCbkFnType IRDropBeginCbk; lefrIRDropCbkFnType IRDropCbk; lefrVoidCbkFnType IRDropEndCbk; lefrDoubleCbkFnType InoutAntennaCbk; lefrDoubleCbkFnType InputAntennaCbk; lefrLayerCbkFnType LayerCbk; lefrVoidCbkFnType LibraryEndCbk; lefrStringCbkFnType MacroBeginCbk; lefrMacroCbkFnType MacroCbk; lefrStringCbkFnType MacroClassTypeCbk; lefrStringCbkFnType MacroEndCbk; lefrIntegerCbkFnType MacroFixedMaskCbk; lefrMacroNumCbkFnType MacroOriginCbk; lefrMacroSiteCbkFnType MacroSiteCbk; lefrMacroForeignCbkFnType MacroForeignCbk; lefrMacroNumCbkFnType MacroSizeCbk; lefrDoubleCbkFnType ManufacturingCbk; lefrMaxStackViaCbkFnType MaxStackViaCbk; lefrMinFeatureCbkFnType MinFeatureCbk; lefrStringCbkFnType NoWireExtensionCbk; lefrNoiseMarginCbkFnType NoiseMarginCbk; lefrNoiseTableCbkFnType NoiseTableCbk; lefrNonDefaultCbkFnType NonDefaultCbk; lefrObstructionCbkFnType ObstructionCbk; lefrDoubleCbkFnType OutputAntennaCbk; lefrPinCbkFnType PinCbk; lefrVoidCbkFnType PropBeginCbk; lefrPropCbkFnType PropCbk; lefrVoidCbkFnType PropEndCbk; lefrSiteCbkFnType SiteCbk; lefrVoidCbkFnType SpacingBeginCbk; lefrSpacingCbkFnType SpacingCbk; lefrVoidCbkFnType SpacingEndCbk; lefrTimingCbkFnType TimingCbk; lefrUnitsCbkFnType UnitsCbk; lefrUseMinSpacingCbkFnType UseMinSpacingCbk; lefrDoubleCbkFnType VersionCbk; lefrStringCbkFnType VersionStrCbk; lefrViaCbkFnType ViaCbk; lefrViaRuleCbkFnType ViaRuleCbk; }; extern lefrCallbacks *lefCallbacks; END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefrData.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2014, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: arakhman $ // $Revision: #11 $ // $Date: 2013/04/23 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefrData_h #define lefrData_h #include #include #include #include #include "lefiDefs.hpp" #include "lefiUser.hpp" #include "lefiLayer.hpp" #include "lefiArray.hpp" #include "lefiUtil.hpp" #include "lefiMacro.hpp" #include "lefiPropType.hpp" #include "lefiCrossTalk.hpp" #include "lefiProp.hpp" #include "lefiNonDefault.hpp" #include "lefiVia.hpp" #include "lefiViaRule.hpp" #include "lefiUnits.hpp" #include "lefrReader.hpp" #define CURRENT_VERSION 5.8 #define RING_SIZE 10 #define IN_BUF_SIZE 16384 #define TOKEN_SIZE 4096 BEGIN_LEFDEF_PARSER_NAMESPACE struct lefCompareStrings { bool operator()(const std::string &lhs, const std::string &rhs) const { return std::strcmp(lhs.c_str(), rhs.c_str()) < 0; } }; typedef std::map lefAliasMap; typedef std::map lefStringMap; typedef std::map lefIntMap; typedef std::map lefDoubleMap; class lefrData { public: lefrData(); ~lefrData(); static void reset(); void initRead(); void doubleBuffer(); FILE* lefrFile; FILE* lefrLog; char lefPropDefType; char* arrayName; char* last; char* layerName; char* lefch; char* lefrFileName; char* macroName; char* ndName; char* next; char* nonDefaultRuleName; char* outMsg; char* pinName; char* shiftBuf; char* siteName; char* viaName; char* viaRuleName; double layerCutSpacing; double lef_save_x; double lef_save_y; // for interpreting (*) notation of LEF/DEF double leflVal; double lefrVal; double versionNum; int antennaInoutWarnings; int antennaInputWarnings; int antennaOutputWarnings; int arrayCutsVal; int arrayCutsWar; int arrayWarnings; int caseSensitiveWarnings; int correctionTableWarnings; int dielectricWarnings; int doneLib; // keep track if the library is done parsing int edgeRateScaleFactorWarnings; int edgeRateThreshold1Warnings; int edgeRateThreshold2Warnings; int encrypted; int first; int first_buffer; int ge56almostDone; // have reached the EXTENSION SECTION int ge56done; // a 5.6 and it has END LIBRARY statement int hasBusBit; int hasDirection; int hasDivChar; int hasFixedMask; int hasGeoLayer; int hasInfluence; int hasLayerMincut; int hasManufactur; int hasMask; int hasMinfeature; int hasNameCase; int hasOpenedLogFile; int hasPRP; int hasParallel; int hasPitch; int hasSamenet; int hasSite; int hasSiteClass; int hasSiteSize; int hasSpCenter; int hasSpLayer; int hasSpParallel; int hasSpSamenet; int hasTwoWidths; int hasType; int hasVer; int hasViaRule_layer; int hasWidth; int hasFatalError; // don't report errors after the file end. int iRDropWarnings; int ignoreVersion; // ignore checking version number int inDefine; int inoutAntennaWarnings; int inputAntennaWarnings; int input_level; int isGenerate; int layerCut; int layerDir; int layerMastOver; int layerRout; int layerWarnings; int lefDefIf; int lefDumbMode; int lefErrMsgPrinted; int lefFixedMask; //All the LEF MACRO PIN MASK assignments can be int lefInfoMsgPrinted; int lefInvalidChar; int lefNdRule; int lefNewIsKeyword; int lefNlToken; int lefNoNum; int lefRetVal; int lefWRetVal; int lefWarnMsgPrinted; int lef_errors; int lef_nlines; int lef_ntokens; int lef_warnings; int lefrDoGcell; int lefrDoGeometries; int lefrDoSite; int lefrDoTrack; int lefrHasLayer; // 5.5 this & lefrHasMaxVS is to keep track that int lefrHasMaxVS; // MAXVIASTACK has to be after all layers int lefrHasSpacing; // keep track of spacing in a layer int lefrHasSpacingTbl; // keep track of spacing table in a layer int macroWarnings; int maxStackViaWarnings; int minFeatureWarnings; int msgCnt; int namesCaseSensitive; // always true in 5.6 int ndLayer; int ndLayerSpace; int ndLayerWidth; int ndRule; int needGeometry; int noWireExtensionWarnings; int noiseMarginWarnings; int noiseTableWarnings; int nonDefaultWarnings; int numVia; int obsDef; int origDef; int outputAntennaWarnings; int pinDef; int pinWarnings; int prtNewLine; // sometimes need to print a new line int prtSemiColon; // sometimes ; is not printed yet int ringPlace; int shiftBufLength; int siteDef; int siteWarnings; int sizeDef; int spParallelLength; int spaceMissing; int spacingWarnings; int symDef; int timingWarnings; int unitsWarnings; int use5_3; int use5_4; int useLenThr; int useMinSpacingWarnings; int viaLayer; int viaRuleHasDir; int viaRuleHasEnc; int viaRuleLayer; int viaRuleWarnings; int viaWarnings; lefiAntennaEnum antennaType; lefiAntennaPWL* lefrAntennaPWLPtr; lefiArray lefrArray; lefiCorrectionTable lefrCorrectionTable; lefiDensity lefrDensity; lefiGcellPattern* lefrGcellPatternPtr; lefiGeometries* lefrGeometriesPtr; lefiIRDrop lefrIRDrop; lefiLayer lefrLayer; lefiMacro lefrMacro; lefiMaxStackVia lefrMaxStackVia; // 5.5 lefiMinFeature lefrMinFeature; lefiNoiseMargin lefrNoiseMargin; lefiNoiseTable lefrNoiseTable; lefiNonDefault lefrNonDefault; lefiNonDefault* nd; // PCR 909010 - For VIA in the nondefaultrule lefiNum macroNum; lefiObstruction lefrObstruction; lefiPin lefrPin; lefiProp lefrProp; lefiSite lefrSite; lefiSitePattern* lefrSitePatternPtr; lefiSpacing lefrSpacing; lefiTiming lefrTiming; lefiTrackPattern* lefrTrackPatternPtr; lefiUnits lefrUnits; lefiUseMinSpacing lefrUseMinSpacing; lefiVia lefrVia; lefiViaRule lefrViaRule; lefStringMap alias_set; lefDoubleMap define_set; lefIntMap defineb_set; lefStringMap defines_set; int tokenSize; //ARRAYS // Ring buffer storage char *ring[RING_SIZE]; int ringSizes[RING_SIZE]; char lefDebug[100]; char *current_token; char *pv_token; char *uc_token; char current_buffer[IN_BUF_SIZE]; const char *current_stack[20]; // the stack itself char lefrErrMsg[1024]; char temp_name[258]; std::vector Hist_text; // to hold the msg limit, 0 - num of limit // 1 - num of message printed, 4701 = 4700 + 1, message starts on 1 // 2 - warning printed int msgLimit[2][MAX_LEF_MSGS]; }; extern lefrData *lefData; END_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefrReader.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2017, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef LEFRREADER_H #define LEFRREADER_H #include #include #include "lefiKRDefs.hpp" #include "lefiDefs.hpp" #include "lefiUser.hpp" #include "lefiUtil.hpp" #define MAX_LEF_MSGS 4701 BEGIN_LEFDEF_PARSER_NAMESPACE // The reader initialization. Must be called before lefrRead(). extern int lefrInit (); extern int lefrInitSession (int startSession = 1); // obsolted extern int lefrReset (); // Clears parser configuration and return it in inial state. extern int lefrClear (); // obsoleted extern int lefrReleaseNResetMemory (); // Change the comment character in LEF. The normal character is // '#'. You can change it to anything you want, but be careful. extern void lefrSetCommentChar (char c); // Allow the parser to upshift all names if the LEF // file is case insensitive. The default is no shift, so the user // must do case insensitive matching. extern void lefrSetShiftCase (); // Allow the user to change the casesensitivity anytime during // parsing. // caseSen = 0, will turn off the casesensitivity // caseSen != 0, will turn on the casesensitivity extern void lefrSetCaseSensitivity (int caseSense); // The reader request the file name they are parsing extern const char * lefrFName (); // The main reader function. // The file should already be opened. This requirement allows // the reader to be used with stdin or a pipe. The file name // is only used for error messages. The includeSearchPath is // a colon-delimited list of directories in which to find // include files. extern int lefrRead (FILE *file, const char *fileName, lefiUserData userData); // Set all of the callbacks that have not yet been set to a function // that will add up how many times a given lef data type was ignored // (ie no callback was done). The statistics can later be printed out. extern void lefrSetRegisterUnusedCallbacks (); extern void lefrPrintUnusedCallbacks (FILE* f); // Set/get the client-provided user data. lefi doesn't look at // this data at all, it simply passes the opaque lefiUserData pointer // back to the application with each callback. The client can // change the data at any time, and it will take effect on the // next callback. The lefi reader and writer maintain separate // user data pointers. extern void lefrSetUserData (lefiUserData); extern lefiUserData lefrGetUserData (); // An enum describing all of the types of reader callbacks. typedef enum { lefrUnspecifiedCbkType = 0, lefrVersionCbkType, lefrVersionStrCbkType, lefrDividerCharCbkType, lefrBusBitCharsCbkType, lefrUnitsCbkType, lefrCaseSensitiveCbkType, lefrNoWireExtensionCbkType, lefrPropBeginCbkType, lefrPropCbkType, lefrPropEndCbkType, lefrLayerCbkType, lefrViaCbkType, lefrViaRuleCbkType, lefrSpacingCbkType, lefrIRDropCbkType, lefrDielectricCbkType, lefrMinFeatureCbkType, lefrNonDefaultCbkType, lefrSiteCbkType, lefrMacroBeginCbkType, lefrPinCbkType, lefrMacroCbkType, lefrObstructionCbkType, lefrArrayCbkType, // NEW CALLBACKS - each callback has its own type. For each callback // that you add, you must add an item to this enum. lefrSpacingBeginCbkType, lefrSpacingEndCbkType, lefrArrayBeginCbkType, lefrArrayEndCbkType, lefrIRDropBeginCbkType, lefrIRDropEndCbkType, lefrNoiseMarginCbkType, lefrEdgeRateThreshold1CbkType, lefrEdgeRateThreshold2CbkType, lefrEdgeRateScaleFactorCbkType, lefrNoiseTableCbkType, lefrCorrectionTableCbkType, lefrInputAntennaCbkType, lefrOutputAntennaCbkType, lefrInoutAntennaCbkType, lefrAntennaInputCbkType, lefrAntennaInoutCbkType, lefrAntennaOutputCbkType, lefrManufacturingCbkType, lefrUseMinSpacingCbkType, lefrClearanceMeasureCbkType, lefrTimingCbkType, lefrMacroClassTypeCbkType, lefrMacroOriginCbkType, lefrMacroSizeCbkType, lefrMacroFixedMaskCbkType, lefrMacroEndCbkType, lefrMaxStackViaCbkType, lefrExtensionCbkType, lefrDensityCbkType, lefrFixedMaskCbkType, lefrMacroSiteCbkType, lefrMacroForeignCbkType, lefrLibraryEndCbkType } lefrCallbackType_e; // Declarations of function signatures for each type of callback. // These declarations are type-safe when compiling with ANSI C // or C++; you will only be able to register a function pointer // with the correct signature for a given type of callback. // // Each callback function is expected to return 0 if successful. // A non-zero return code will cause the reader to abort. // // The lefrDesignStart and lefrDesignEnd callback is only called once. // Other callbacks may be called multiple times, each time with a different // set of data. // // For each callback, the Def API will make the callback to the // function supplied by the client, which should either make a copy // of the Def object, or store the data in the client's own data structures. // The Def API will delete or reuse each object after making the callback, // so the client should not keep a pointer to it. // // All callbacks pass the user data pointer provided in lefrRead() // or lefrSetUserData() back to the client; this can be used by the // client to obtain access to the rest of the client's data structures. // // The user data pointer is obtained using lefrGetUserData() immediately // prior to making each callback, so the client is free to change the // user data on the fly if necessary. // // Callbacks with the same signature are passed a callback type // parameter, which allows an application to write a single callback // function, register that function for multiple callbacks, then // switch based on the callback type to handle the appropriate type of // data. // A declaration of the signature of all callbacks that return nothing. typedef int (*lefrVoidCbkFnType) (lefrCallbackType_e, void* num, lefiUserData); // A declaration of the signature of all callbacks that return a string. typedef int (*lefrStringCbkFnType) (lefrCallbackType_e, const char *string, lefiUserData); // A declaration of the signature of all callbacks that return a integer. typedef int (*lefrIntegerCbkFnType) (lefrCallbackType_e, int number, lefiUserData); // A declaration of the signature of all callbacks that return a double. typedef int (*lefrDoubleCbkFnType) (lefrCallbackType_e, double number, lefiUserData); // A declaration of the signature of all callbacks that return a lefiUnits. typedef int (*lefrUnitsCbkFnType) (lefrCallbackType_e, lefiUnits* units, lefiUserData); // A declaration of the signature of all callbacks that return a lefiLayer. typedef int (*lefrLayerCbkFnType) (lefrCallbackType_e, lefiLayer* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiVia. typedef int (*lefrViaCbkFnType) (lefrCallbackType_e, lefiVia* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiViaRule. typedef int (*lefrViaRuleCbkFnType) (lefrCallbackType_e, lefiViaRule* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiSpacing. typedef int (*lefrSpacingCbkFnType) (lefrCallbackType_e, lefiSpacing* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiIRDrop. typedef int (*lefrIRDropCbkFnType) (lefrCallbackType_e, lefiIRDrop* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiMinFeature. typedef int (*lefrMinFeatureCbkFnType) (lefrCallbackType_e, lefiMinFeature* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiNonDefault. typedef int (*lefrNonDefaultCbkFnType) (lefrCallbackType_e, lefiNonDefault* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiSite. typedef int (*lefrSiteCbkFnType) (lefrCallbackType_e, lefiSite* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiMacro. typedef int (*lefrMacroCbkFnType) (lefrCallbackType_e, lefiMacro* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiPin. typedef int (*lefrPinCbkFnType) (lefrCallbackType_e, lefiPin* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiObstruction. typedef int (*lefrObstructionCbkFnType) (lefrCallbackType_e, lefiObstruction* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiArray. typedef int (*lefrArrayCbkFnType) (lefrCallbackType_e, lefiArray* l, lefiUserData); // A declaration of the signature of all callbacks that return a lefiProp. typedef int (*lefrPropCbkFnType) (lefrCallbackType_e, lefiProp* p, lefiUserData); // A declaration of the signature of all callbacks that return a lefiNoiseMargin. typedef int (*lefrNoiseMarginCbkFnType) (lefrCallbackType_e, struct lefiNoiseMargin* p, lefiUserData); // A declaration of the signature of all callbacks that return a lefiNoiseTable. typedef int (*lefrNoiseTableCbkFnType) (lefrCallbackType_e, lefiNoiseTable* p, lefiUserData); // A declaration of the signature of all callbacks that return a lefiCorrectionTable. typedef int (*lefrCorrectionTableCbkFnType) (lefrCallbackType_e, lefiCorrectionTable* p, lefiUserData); // A declaration of the signature of all callbacks that return a lefiTiming. typedef int (*lefrTimingCbkFnType) (lefrCallbackType_e, lefiTiming* p, lefiUserData); // A declaration of the signature of all callbacks that return a lefiUseMinSpacing. typedef int (*lefrUseMinSpacingCbkFnType) (lefrCallbackType_e, lefiUseMinSpacing* l, lefiUserData); // NEW CALLBACK - If your callback returns a pointer to a new class then // you must add a type function here. // A declaration of the signature of all callbacks that return a lefiMaxStackVia. typedef int (*lefrMaxStackViaCbkFnType) (lefrCallbackType_e, lefiMaxStackVia* l, lefiUserData); typedef int (*lefrMacroNumCbkFnType) (lefrCallbackType_e, lefiNum l, lefiUserData); typedef int (*lefrMacroSiteCbkFnType) (lefrCallbackType_e, const lefiMacroSite *site, lefiUserData); typedef int (*lefrMacroForeignCbkFnType) (lefrCallbackType_e, const lefiMacroForeign *foreign, lefiUserData); // 5.6 // A declaration of the signature of all callbacks that return a lefiDensity. typedef int (*lefrDensityCbkFnType) (lefrCallbackType_e, lefiDensity* l, lefiUserData); // Functions to call to register a callback function. extern void lefrSetUnitsCbk(lefrUnitsCbkFnType); extern void lefrSetVersionCbk(lefrDoubleCbkFnType); extern void lefrSetVersionStrCbk(lefrStringCbkFnType); extern void lefrSetDividerCharCbk(lefrStringCbkFnType); extern void lefrSetBusBitCharsCbk(lefrStringCbkFnType); extern void lefrSetNoWireExtensionCbk(lefrStringCbkFnType); extern void lefrSetCaseSensitiveCbk(lefrIntegerCbkFnType); extern void lefrSetPropBeginCbk(lefrVoidCbkFnType); extern void lefrSetPropCbk(lefrPropCbkFnType); extern void lefrSetPropEndCbk(lefrVoidCbkFnType); extern void lefrSetLayerCbk(lefrLayerCbkFnType); extern void lefrSetViaCbk(lefrViaCbkFnType); extern void lefrSetViaRuleCbk(lefrViaRuleCbkFnType); extern void lefrSetSpacingCbk(lefrSpacingCbkFnType); extern void lefrSetIRDropCbk(lefrIRDropCbkFnType); extern void lefrSetDielectricCbk(lefrDoubleCbkFnType); extern void lefrSetMinFeatureCbk(lefrMinFeatureCbkFnType); extern void lefrSetNonDefaultCbk(lefrNonDefaultCbkFnType); extern void lefrSetSiteCbk(lefrSiteCbkFnType); extern void lefrSetMacroBeginCbk(lefrStringCbkFnType); extern void lefrSetPinCbk(lefrPinCbkFnType); extern void lefrSetObstructionCbk(lefrObstructionCbkFnType); extern void lefrSetArrayCbk(lefrArrayCbkFnType); extern void lefrSetMacroCbk(lefrMacroCbkFnType); extern void lefrSetLibraryEndCbk(lefrVoidCbkFnType); // NEW CALLBACK - each callback must have a function to allow the user // to set it. Add the function here. extern void lefrSetTimingCbk(lefrTimingCbkFnType); extern void lefrSetSpacingBeginCbk(lefrVoidCbkFnType); extern void lefrSetSpacingEndCbk(lefrVoidCbkFnType); extern void lefrSetArrayBeginCbk(lefrStringCbkFnType); extern void lefrSetArrayEndCbk(lefrStringCbkFnType); extern void lefrSetIRDropBeginCbk(lefrVoidCbkFnType); extern void lefrSetIRDropEndCbk(lefrVoidCbkFnType); extern void lefrSetNoiseMarginCbk(lefrNoiseMarginCbkFnType); extern void lefrSetEdgeRateThreshold1Cbk(lefrDoubleCbkFnType); extern void lefrSetEdgeRateThreshold2Cbk(lefrDoubleCbkFnType); extern void lefrSetEdgeRateScaleFactorCbk(lefrDoubleCbkFnType); extern void lefrSetNoiseTableCbk(lefrNoiseTableCbkFnType); extern void lefrSetCorrectionTableCbk(lefrCorrectionTableCbkFnType); extern void lefrSetInputAntennaCbk(lefrDoubleCbkFnType); extern void lefrSetOutputAntennaCbk(lefrDoubleCbkFnType); extern void lefrSetInoutAntennaCbk(lefrDoubleCbkFnType); extern void lefrSetAntennaInputCbk(lefrDoubleCbkFnType); extern void lefrSetAntennaInoutCbk(lefrDoubleCbkFnType); extern void lefrSetAntennaOutputCbk(lefrDoubleCbkFnType); extern void lefrSetClearanceMeasureCbk(lefrStringCbkFnType); extern void lefrSetManufacturingCbk(lefrDoubleCbkFnType); extern void lefrSetUseMinSpacingCbk(lefrUseMinSpacingCbkFnType); extern void lefrSetMacroClassTypeCbk(lefrStringCbkFnType); extern void lefrSetMacroOriginCbk(lefrMacroNumCbkFnType); extern void lefrSetMacroSiteCbk(lefrMacroSiteCbkFnType); extern void lefrSetMacroForeignCbk(lefrMacroForeignCbkFnType); extern void lefrSetMacroSizeCbk(lefrMacroNumCbkFnType); extern void lefrSetMacroFixedMaskCbk(lefrIntegerCbkFnType); extern void lefrSetMacroEndCbk(lefrStringCbkFnType); extern void lefrSetMaxStackViaCbk(lefrMaxStackViaCbkFnType); extern void lefrSetExtensionCbk(lefrStringCbkFnType); extern void lefrSetDensityCbk(lefrDensityCbkFnType); extern void lefrSetFixedMaskCbk(lefrIntegerCbkFnType); // Set all of the callbacks that have not yet been set to the following // function. This is especially useful if you want to check to see // if you forgot anything. extern void lefrSetUnusedCallbacks (lefrVoidCbkFnType func); // Reset all the callback functions to nil extern void lefrUnsetCallbacks(); // Functions to call to unregister a callback function. extern void lefrUnsetAntennaInputCbk(); extern void lefrUnsetAntennaInoutCbk(); extern void lefrUnsetAntennaOutputCbk(); extern void lefrUnsetArrayBeginCbk(); extern void lefrUnsetArrayCbk(); extern void lefrUnsetArrayEndCbk(); extern void lefrUnsetBusBitCharsCbk(); extern void lefrUnsetCaseSensitiveCbk(); extern void lefrUnsetClearanceMeasureCbk(); extern void lefrUnsetCorrectionTableCbk(); extern void lefrUnsetDensityCbk(); extern void lefrUnsetDielectricCbk(); extern void lefrUnsetDividerCharCbk(); extern void lefrUnsetEdgeRateScaleFactorCbk(); extern void lefrUnsetEdgeRateThreshold1Cbk(); extern void lefrUnsetEdgeRateThreshold2Cbk(); extern void lefrUnsetExtensionCbk(); extern void lefrUnsetInoutAntennaCbk(); extern void lefrUnsetInputAntennaCbk(); extern void lefrUnsetIRDropBeginCbk(); extern void lefrUnsetIRDropCbk(); extern void lefrUnsetIRDropEndCbk(); extern void lefrUnsetLayerCbk(); extern void lefrUnsetLibraryEndCbk(); extern void lefrUnsetMacroBeginCbk(); extern void lefrUnsetMacroCbk(); extern void lefrUnsetMacroClassTypeCbk(); extern void lefrUnsetMacroEndCbk(); extern void lefrUnsetMacroOriginCbk(); extern void lefrUnsetMacroSiteCbk(); extern void lefrUnsetMacroForeignCbk(); extern void lefrUnsetMacroSizeCbk(); extern void lefrUnsetManufacturingCbk(); extern void lefrUnsetMaxStackViaCbk(); extern void lefrUnsetMinFeatureCbk(); extern void lefrUnsetNoiseMarginCbk(); extern void lefrUnsetNoiseTableCbk(); extern void lefrUnsetNonDefaultCbk(); extern void lefrUnsetNoWireExtensionCbk(); extern void lefrUnsetObstructionCbk(); extern void lefrUnsetOutputAntennaCbk(); extern void lefrUnsetPinCbk(); extern void lefrUnsetPropBeginCbk(); extern void lefrUnsetPropCbk(); extern void lefrUnsetPropEndCbk(); extern void lefrUnsetSiteCbk(); extern void lefrUnsetSpacingBeginCbk(); extern void lefrUnsetSpacingCbk(); extern void lefrUnsetSpacingEndCbk(); extern void lefrUnsetTimingCbk(); extern void lefrUnsetUseMinSpacingCbk(); extern void lefrUnsetUnitsCbk(); extern void lefrUnsetVersionCbk(); extern void lefrUnsetVersionStrCbk(); extern void lefrUnsetViaCbk(); extern void lefrUnsetViaRuleCbk(); // Return the current line number in the parser. extern int lefrLineNumber (); // Routine to set the message logging routine for errors typedef void (*LEFI_LOG_FUNCTION) (const char*); extern void lefrSetLogFunction(LEFI_LOG_FUNCTION); // Routine to set the message logging routine for warnings typedef void (*LEFI_WARNING_LOG_FUNCTION) (const char*); extern void lefrSetWarningLogFunction(LEFI_WARNING_LOG_FUNCTION); // Routine to set the user defined malloc routine typedef void* (*LEFI_MALLOC_FUNCTION) (int); extern void lefrSetMallocFunction(LEFI_MALLOC_FUNCTION); // Routine to set the user defined realloc routine typedef void* (*LEFI_REALLOC_FUNCTION) (void *, int); extern void lefrSetReallocFunction(LEFI_REALLOC_FUNCTION); // Routine to set the user defined free routine typedef void (*LEFI_FREE_FUNCTION) (void *); extern void lefrSetFreeFunction(LEFI_FREE_FUNCTION); // Routine to set the line number callback routine typedef void (*LEFI_LINE_NUMBER_FUNCTION) (int); extern void lefrSetLineNumberFunction( LEFI_LINE_NUMBER_FUNCTION); // Set the number of lines before calling the line function callback routine // Default is 10000 extern void lefrSetDeltaNumberLines (int); // PCR 551229 - Set the parser to be more relax // This api is specific for PKS. // When in relax mode, the parser will not require width, pitch, & direction // in routing layers. Also vias in nondefault rules extern void lefrSetRelaxMode (); extern void lefrUnsetRelaxMode (); // PCR 565274 - LEF/DEF API should have the API call to overwrite default // version extern void lefrSetVersionValue(const char* version); // Routine to set the read function typedef size_t (*LEFI_READ_FUNCTION) (FILE*, char*, size_t); extern void lefrSetReadFunction(LEFI_READ_FUNCTION); extern void lefrUnsetReadFunction(); // Routine to set the lefrWarning.log to open as append instead for write // New in 5.7 extern void lefrSetOpenLogFileAppend(); extern void lefrUnsetOpenLogFileAppend(); // Routine to disable string property value process, default it will process // the value string extern void lefrDisablePropStrProcess(); // Routine to set the max number of warnings for a perticular section extern void lefrSetAntennaInoutWarnings(int warn); extern void lefrSetAntennaInputWarnings(int warn); extern void lefrSetAntennaOutputWarnings(int warn); extern void lefrSetArrayWarnings(int warn); extern void lefrSetCaseSensitiveWarnings(int warn); extern void lefrSetCorrectionTableWarnings(int warn); extern void lefrSetDielectricWarnings(int warn); extern void lefrSetEdgeRateThreshold1Warnings(int warn); extern void lefrSetEdgeRateThreshold2Warnings(int warn); extern void lefrSetEdgeRateScaleFactorWarnings(int warn); extern void lefrSetInoutAntennaWarnings(int warn); extern void lefrSetInputAntennaWarnings(int warn); extern void lefrSetIRDropWarnings(int warn); extern void lefrSetLayerWarnings(int warn); extern void lefrSetMacroWarnings(int warn); extern void lefrSetMaxStackViaWarnings(int warn); extern void lefrSetMinFeatureWarnings(int warn); extern void lefrSetNoiseMarginWarnings(int warn); extern void lefrSetNoiseTableWarnings(int warn); extern void lefrSetNonDefaultWarnings(int warn); extern void lefrSetNoWireExtensionWarnings(int warn); extern void lefrSetOutputAntennaWarnings(int warn); extern void lefrSetPinWarnings(int warn); extern void lefrSetSiteWarnings(int warn); extern void lefrSetSpacingWarnings(int warn); extern void lefrSetTimingWarnings(int warn); extern void lefrSetUnitsWarnings(int warn); extern void lefrSetUseMinSpacingWarnings(int warn); extern void lefrSetViaRuleWarnings(int warn); extern void lefrSetViaWarnings(int warn); // Handling output messages extern void lefrDisableParserMsgs(int nMsg, int* msgs); extern void lefrEnableParserMsgs(int nMsg, int* msgs); extern void lefrEnableAllMsgs(); extern void lefrDisableAllMsgs(); extern void lefrSetTotalMsgLimit(int totNumMsgs); extern void lefrSetLimitPerMsg(int msgId, int numMsg); // Register lef58Type-layerType pair. extern void lefrRegisterLef58Type(const char *lef58Type, const char *layerType); // Return codes for the user callbacks. // The user should return one of these values. #define PARSE_OK 0 // continue parsing #define STOP_PARSE 1 // stop parsing with no error message #define PARSE_ERROR 2 // stop parsing, print an error message END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefrSettings.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2017, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: arakhman $ // $Revision: #11 $ // $Date: 2013/04/23 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef lefrSettings_h #define lefrSettings_h #include #include #include #include #include "lefrReader.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE struct lefCompareCStrings { bool operator()(const char* lhs, const char* rhs) const { return std::strcmp(lhs, rhs) < 0; } }; typedef std::map lefKeywordMap; typedef std::map MsgsDisableMap; typedef std::set StringSet; class lefrProps { public: lefiPropType lefrCompProp; lefiPropType lefrLayerProp; lefiPropType lefrLibProp; lefiPropType lefrMacroProp; lefiPropType lefrNondefProp; lefiPropType lefrPinProp; lefiPropType lefrViaProp; lefiPropType lefrViaRuleProp; }; class lefrSettings { public: lefrSettings(); void init_symbol_table(); static void reset(); void addLef58Type(const char *lef58Type, const char **layerType); std::string getLayerLef58Types(const char *type) const; void disableMsg(int msgId); void enableMsg(int msgId); void enableAllMsgs(); int suppresMsg(int msgId); static std::string getToken(const std::string &input, int &startIdx); lefKeywordMap Keyword_set; char CommentChar; double VersionNum; int DisPropStrProcess; int CaseSensitive; int CaseSensitiveSet; int DeltaNumberLines; int AntennaInoutWarnings; int AntennaInputWarnings; int AntennaOutputWarnings; int ArrayWarnings; int CaseSensitiveWarnings; int CorrectionTableWarnings; int DielectricWarnings; int EdgeRateScaleFactorWarnings; int EdgeRateThreshold1Warnings; int EdgeRateThreshold2Warnings; int IRDropWarnings; int InoutAntennaWarnings; int InputAntennaWarnings; LEFI_LINE_NUMBER_FUNCTION LineNumberFunction; int LayerWarnings; int MacroWarnings; int MaxStackViaWarnings; int MinFeatureWarnings; int NoWireExtensionWarnings; int NoiseMarginWarnings; int NoiseTableWarnings; int NonDefaultWarnings; int OutputAntennaWarnings; int PinWarnings; LEFI_READ_FUNCTION ReadFunction; int ReadEncrypted; int RegisterUnused; int RelaxMode; int ShiftCase; int SiteWarnings; int SpacingWarnings; int TimingWarnings; int UnitsWarnings; int UseMinSpacingWarnings; int ViaRuleWarnings; int ViaWarnings; int LogFileAppend; int TotalMsgLimit; lefiUserData UserData; StringSet Lef58TypePairs; LEFI_MALLOC_FUNCTION MallocFunction; LEFI_REALLOC_FUNCTION ReallocFunction; LEFI_FREE_FUNCTION FreeFunction; LEFI_LOG_FUNCTION ErrorLogFunction; LEFI_LOG_FUNCTION SetLogFunction; LEFI_WARNING_LOG_FUNCTION WarningLogFunction; int MsgLimit[MAX_LEF_MSGS]; MsgsDisableMap msgsDisableMap; int dAllMsgs; lefrProps lefProps; }; extern lefrSettings* lefSettings; END_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefwWriter.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef LEFW_WRITERCALLS_H #define LEFW_WRITERCALLS_H #include #include "lefiKRDefs.hpp" #include "lefiDefs.hpp" #include "lefiUser.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE // Return codes for writing functions: #define LEFW_OK 0 #define LEFW_UNINITIALIZED 1 #define LEFW_BAD_ORDER 2 #define LEFW_BAD_DATA 3 #define LEFW_ALREADY_DEFINED 4 #define LEFW_WRONG_VERSION 5 #define LEFW_MIX_VERSION_DATA 6 #define LEFW_OBSOLETE 7 // orient // 0 = N // 1 = W // 2 = S // 3 = E // 4 = FN // 5 = FW // 6 = FS // 7 = FE // The LEF writer initialization. Must be called first. // Either this routine or lefwInitCbk should be call only, // Can't call both routines. // This routine must be called only once. // Returns 0 if successful. extern int lefwInit(FILE* f); // The LEF writer initialization. Must be called first. // Either this routine or lefwInit should be call only, // Can't call both routines. // This routine must be called only once. // Returns 0 if successful. extern int lefwInitCbk(FILE* f); // This routine will set the writer to write out an encrypted // lef file. // This routine must be called only once and has to be called after // lefwInit or lefwInitCbk // Need to call lefwCloseEncrypt to do some cleaning if this routine // has called extern int lefwEncrypt(); // This routine needs to be called if lefwEncrypt has called. // It should be called before the fclose. // It does some house cleaning. extern int lefwCloseEncrypt(); // This routine will write a blank line extern int lefwNewLine(); // This routine is called after lefwInit. // This routine can be called only once. // Returns 0 if successful. extern int lefwVersion (int vers1, int vers2); // This routine is called after lefwInit. // This routine can be called only once. // Returns 0 if successful. // The caseSensitive can be ON or OFF. extern int lefwCaseSensitive (const char* caseSensitive); // This routine is called after lefwInit. // This routine can be called only once. // Returns 0 if successful. // The noWireExtensionAtPin can be ON or OFF. extern int lefwNoWireExtensionAtPin (const char* noWireExt); // This routine is called after lefwInit. // This routine can be called only once. // Returns 0 if successful. // already have one extern int lefwMinfeature (double minFeatureX, double minFeatureY); // This routine is called after lefwInit. // This routine can be called only once. // Returns 0 if successful. extern int lefwDielectric (double dielectric); // This routine is called after lefwInit. // This routine can be called only once. // Returns 0 if successful. extern int lefwBusBitChars (const char* busBitChars); // This routine is called after lefwInit. // This routine can be called only once. // Returns 0 if successful. extern int lefwDividerChar (const char* dividerChar); // This routine is called after lefwInit. // This routine can be called only once. // This is a 5.4 syntax. // Returns 0 if successful. extern int lefwManufacturingGrid (double grid); // This routine is called after lefwInit. // This routine can be called only once. // This is a 5.8 syntax. // Returns 0 if successful. extern int lefwFixedMask(); // This routine is called after lefwInit. // This routine can be called multiple times. // This is a 5.4 syntax. // Returns 0 if successful. extern int lefwUseMinSpacing (const char* type, const char* onOff); // This routine is called after lefwInit. // This routine can be called only once. // This is a 5.4 syntax. // Returns 0 if successful. extern int lefwClearanceMeasure (const char* type); // This routine is called after lefwInit. // This routine can be called only once. // This is a 5.4 syntax. // Returns 0 if successful. extern int lefwAntennaInputGateArea (double inputGateArea); // This routine is called after lefwInit. // This routine can be called only once. // This is a 5.4 syntax. // Returns 0 if successful. extern int lefwAntennaInOutDiffArea (double inOutDiffArea); // This routine is called after lefwInit. // This routine can be called only once. // This is a 5.4 syntax. // Returns 0 if successful. extern int lefwAntennaOutputDiffArea (double outputDiffArea); // This routine is called after lefwInit. // This routine can be called only once. // Returns 0 if successful. // This section of routines is optional. // The routine starts the units section. All of the units must follow. extern int lefwStartUnits(); // This routine is called once for each unit. The call must // be preceeded by a call to lefwStartUnits and must be // terminated by a call to lefwEndUnits. // Returns 0 if successful. extern int lefwUnits(double time, // optional(0) - TIME NANOSECONDS double capacitance, // optional(0) - CAPACITANCE PICOFARADS double resistance, // optional(0) - RESISTANCE OHMS double power, // optional(0) - POWER MILLIWATTS double current, // optional(0) - CURRENT MILLIAMPS double voltage, // optional(0) - VOLTAGE VOLTS double database); // optional(0) - DATABASE MICRONS // This routine is called once for each unit. It is separated from // lefwUnits due to backwards compatible for pre 5.3. // Returns 0 if successful. extern int lefwUnitsFrequency(double frequency); // This routine must be called after the lefwUnits call (if any). // The routine can be called only once. // Returns 0 if successful. extern int lefwEndUnits(); // This routine is called after lefwInit. // Either this routine or lefwStartLayerRouting must be called. // Multiple sections of lefwStartLayer can be called. // This routine can be called only once per section. // Returns 0 if successful. // The routine starts the layer section. All of the layers must follow. // The type can be either CUT for Cut Layer, MASTERSLICE or OVERLAP for // Masterslice or Overlay Layer. extern int lefwStartLayer(const char* layerName, const char* type); // CUT | MASTERSLICE | OVERLAP // This routine must be called after lefwStartLayer. // This section of routines is optional. // Returns 0 if successful. // This is a 5.8 syntax. extern int lefwLayerMask(int maskColor); // This routine must be called after lefwStartLayer. // This section of routines is optional. // Returns 0 if successful. // This is a 5.5 syntax. // This routine is called if the layer type is IMPLANT when // lefwStartLayer is called. extern int lefwLayerWidth(double minWidth); // The following APIs are for lefwrite 5.7 Layer, Spacing with type CUT // Due to adding new constructs, it is impossible to use the previous // APIs. // The following APIs are obsoleted in 5.7: // lefwLayer // lefwLayerStack // lefwLayerSpacingAdjacent // lefwLayerSpacingCenterToCenter // This routine must be called after lefwStartLayer. // This routine starts the Layer Type Cut Spacing // Returns 0 if successful. // The routing lefwLayerCutSpacingEnd has to call at the end of each spacing. // This is a 5.7 syntax. extern int lefwLayerCutSpacing(double spacing) ; // This routine must be called after lefwLayerSpacing // This routine is optional. // Returns 0 if successful. // This is a 5.7 syntax. extern int lefwLayerCutSpacingCenterToCenter(); // This routine must be called after lefwLayerSpacing // This routine is optional. // Returns 0 if successful. // This is a 5.7 syntax. extern int lefwLayerCutSpacingSameNet(); // This routine must be called after lefwLayerSpacing // This routine is optional. // Either this routine, lefwLayerCutSpacingAdjacent, // lefwLayerCutSpacingParallel or lefwLayerCutSpacingArea is called per Spacing. // Returns 0 if successful. // This is a 5.7 syntax. extern int lefwLayerCutSpacingLayer(const char* name2, int stack); // optional(0) // This routine must be called after lefwLayerSpacing // This routine is optional. // Either this routine, lefwLayerCutSpacingLayer, // lefwLayerCutSpacingParallel or lefwLayerCutSpacingArea is called per Spacing. // Returns 0 if successful. // This is a 5.7 syntax. extern int lefwLayerCutSpacingAdjacent(int viaCuts, // either 2, 3, or 4, opt double distance, int stack); // optional(0) // This routine must be called after lefwLayerSpacing // This routine is optional. // Either this routine, lefwLayerCutSpacingLayer, // lefwLayerCutSpacingAdjacent or lefwLayerCutSpacingArea is called per Spacing. // Returns 0 if successful. // This is a 5.7 syntax. extern int lefwLayerCutSpacingParallel(); // This routine must be called after lefwLayerSpacing // This routine is optional. // Either this routine, lefwLayerCutSpacingLayer, * lefwLayerCutSpacingAdjacent // or lefwLayerCutSpacingParallel is called per Spacing. // Returns 0 if successful. // This is a 5.7 syntax. extern int lefwLayerCutSpacingArea(double cutArea); // This routine must be called after lefwLayerSpacing // This routine marks the end of a Layer Type CUT Spacing // Returns 0 if successful. // This is a 5.7 syntax. extern int lefwLayerCutSpacingEnd(); // This routine must be called after lefwStartLayer. // This routine can be called only once. // This section of routines is optional. // This is a 5.7 syntax // Returns 0 if successful. // This routine is called if the layer type is CUT when // lefwStartLayer is called. extern int lefwLayerCutSpacingTableOrtho(int numSpacing, double* cutWithins, double* orthoSpacings); // This routine must be called after lefwStartLayer. // This routine can be called only once. // This section of routines is optional. // This is a 5.7 syntax // Returns 0 if successful. // This routine is called if the layer type is CUT when // lefwStartLayer is called. extern int lefwLayerArraySpacing(int longArray, // optional (0) double viaWidth, // optional (0) double cutSpacing, int numArrayCut, int* arrayCuts, double* arraySpacings); // This routine must be called after lefwStartLayer. // This routine can be called multiple times. // This section of routines is optional. // This is a 5.6 syntax. // Returns 0 if successful. // This routine is called if the layer type is CUT when // lefwStartLayer is called. extern int lefwLayerEnclosure(const char* location, //ABOVE|BELOW, optional "" double overhang1, double overhang2, double width); // optional (0) // This routine must be called after lefwStartLayer. // This routine can be called multiple times. // This routine is similar as lefwLayerEnclosure, but allow user to add // EXCEPTEXTRACUT option // This section of routines is optional. // This is a 5.7 syntax. // Returns 0 if successful. // This routine is called if the layer type is CUT when // lefwStartLayer is called. extern int lefwLayerEnclosureWidth( const char* location, //ABOVE|BELOW, optional "" double overhang1, double overhang2, double width, // optional (0) double cutWithin); // optional (0) // This routine must be called after lefwStartLayer. // This routine can be called multiple times. // This routine is to write out minLength inside ENCLOSURE instead of WIDTH // as in the routine lefwLayerEnclosure & lefwLayerEnclosureWidth. // This section of routines is optional. // This is a 5.7 syntax. // Returns 0 if successful. // This routine is called if the layer type is CUT when // lefwStartLayer is called. extern int lefwLayerEnclosureLength( const char* location, //ABOVE|BELOW, optional "" double overhang1, double overhang2, double minLength); // optional (0) // This routine must be called after lefwStartLayer. // This routine can be called multiple times. // This section of routines is optional. // This is a 5.6 syntax. // Returns 0 if successful. // This routine is called if the layer type is CUT when // lefwStartLayer is called. extern int lefwLayerPreferEnclosure( const char* location, //ABOVE|BELOW, optional "" double overhang1, double overhang2, double width); // optional (0) // This routine must be called after lefwStartLayer. // This routine can be called only once per Layer. // This section of routines is optional. // This is a 5.6 syntax. // Returns 0 if successful. // This routine is called if the layer type is CUT when // lefwStartLayer is called. extern int lefwLayerResistancePerCut(double resistance); // This routine must be called after the lefwStartLayer call (if any). // The routine can be called only once per section. // Returns 0 if successful. extern int lefwEndLayer(const char* layerName); // This routine is called after lefwInit. // Either this routine or lefwStartLayer must be called. // Multiple section of lefwStartLayer can be called. // The routine can be called only once per section. // Returns 0 if successful. // The routine starts the layer routing section. // All of the layers must follow. extern int lefwStartLayerRouting(const char* layerName); // This routine must be called only once after lefwStartLayerRouting. // This routine is required for LayerRouting. // Returns 0 if successful. extern int lefwLayerRouting(const char* direction, // HORIZONTAL | VERTICAL | // DIAG45 | DIAG135 double width); // This routine must be called only once after lefwStartLayerRouting. // Either this routine or lefwLayerRoutingPitchXYDistance can be called // but not both // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwLayerRoutingPitch(double pitch); // This routine must be called only once after lefwStartLayerRouting. // Either this routine or lefwLayerRoutingPitch can be called but not both // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwLayerRoutingPitchXYDistance(double xDistance, double yDistance); // This routine must be called only once after lefwStartLayerRouting. // Either this routine or lefwLayerRoutingDiagPitchXYDistance can be called // but not both // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwLayerRoutingDiagPitch(double distance); // This routine must be called only once after lefwStartLayerRouting. // Either this routine or lefwLayerRoutingDiagPitch can be called // but not both // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwLayerRoutingDiagPitchXYDistance(double diag45Distance, double diag135Distance); // This routine must be called only once after lefwStartLayerRouting. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwLayerRoutingDiagWidth(double diagWidth); // This routine must be called only once after lefwStartLayerRouting. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwLayerRoutingDiagSpacing(double diagSpacing); // This routine must be called only once after lefwStartLayerRouting. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwLayerRoutingDiagMinEdgeLength(double diagLength); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Either this routine or lefwLayerRoutingOffsetXYDistance can be called // but not both // Returns 0 if successful. extern int lefwLayerRoutingOffset(double offset); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Either this routine or lefwLayerRoutingOffset can be called but not both // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwLayerRoutingOffsetXYDistance(double xDistance, double yDistance); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingArea(double area); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingMinsize(int numRect, double* minWidth, double* minLength); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingMinimumcut(double numCuts, double minWidth); // This routine must be called only once after lefwStartLayerRouting. // This routine is similar as lefwLayerRoutingMinimumcut, but allow user // to specify value for WITHIN // This is a 5.7 syntax. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingMinimumcutWithin(double numCuts, double minWidth, double cutDistance); // This routine must be called only once after lefwLayerRoutingMinimumcut. // This routine is optional. // Direction can be either FROMABOVE or FROMBELOW // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwLayerRoutingMinimumcutConnections(const char* direction); // This routine must be called only once after lefwLayerRoutingMinimumcut. // This routine is optional. // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwLayerRoutingMinimumcutLengthWithin(double length, double distance); // This routine must be called multiple time after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingSpacing(double spacing); // Either this routine, lefwLayerRoutingSpacingLengthThreshold or // lefwLayerRoutingSpacingSameNet can be // called only once after lefwLayerRoutingSpacing. // This routine is optional. // Returns 0 if successful. extern int lefwLayerRoutingSpacingRange(double minWidth, double maxWidth); // Either this routine or lefwLayerRoutingSpacingRangeInfluence or // lefwLayerRoutingSpacingRangeRange can // be called once after llefwLayerRoutingSpacingRange. // This routine is valid only if either or both leftRange and rightRange // in lefwLayerRoutingSpacing are non zero // Returns 0 if successful. extern int lefwLayerRoutingSpacingRangeUseLengthThreshold(); // Either this routine or lefwLayerRoutingSpacingRangeUseLengthThreshold or // lefwLayerRoutingSpacingRangeRange can be called once after // lefwLayerRoutingSpacingRange. // subMinWidth & subMaxWidth are optional. // Returns 0 if successful. extern int lefwLayerRoutingSpacingRangeInfluence(double infValue, double subMinWidth, double subMaxWidth); // Either this routine or lefwLayerRoutingSpacingRangeUseLengthThreshold or // lefwLayerRoutingSpacingRangeInfluence can be called once after // lefwLayerRoutingSpacingRange. // Returns 0 if successful. extern int lefwLayerRoutingSpacingRangeRange(double minWidth, double maxWidth); // Either this routine, lefwLayerRoutingSpacingRange or // lefwLayerRoutingSpacingSameNet can be // be called once after lefwLayerRoutingSpacing. // minWidth & maxWidth are optional. // Returns 0 if successful. extern int lefwLayerRoutingSpacingLengthThreshold(double lengthValue, double minWidth, double maxWidth); // Either this routine, lefwLayerRoutingSpacingRange or // lefwLayerRoutingSpacingRange can be // be called once after lefwLayerRoutingSpacing. // This is a 5.7 routine. // Returns 0 if successful. extern int lefwLayerRoutingSpacingSameNet(int PGOnly) ; // optional (0) // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // This is a 5.7 syntax. // Returns 0 if successful. extern int lefwLayerRoutingSpacingEndOfLine(double eolWidth, double eolWithin); // This routine must be called only once after lefwLayerRoutingSpacingEndOfLine // This routine is optional // This is a 5.7 syntax. // Returns 0 if successful. extern int lefwLayerRoutingSpacingEOLParallel(double parSpace, double parWithin, int twoEdges); // optional(0) // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // This is a 5.7 syntax. // Returns 0 if successful. extern int lefwLayerRoutingSpacingNotchLength(double minNLength); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // This is a 5.7 syntax. // Returns 0 if successful. extern int lefwLayerRoutingSpacingEndOfNotchWidth(double eonWidth, double minNSpacing, double minNLength); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingWireExtension(double wireExtension); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingResistance(const char* resistance); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingCapacitance(const char* capacitance); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingHeight(double height); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingThickness(double thickness); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingShrinkage(double shrinkage); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingCapMultiplier(double capMultiplier); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingEdgeCap(double edgeCap); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingAntennaArea(double antennaArea); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional // Returns 0 if successful. extern int lefwLayerRoutingAntennaLength(double antennaLength); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional and can be called once. // This is a 5.5 syntax. // width is the maximum width. // Returns 0 if successful. extern int lefwLayerRoutingMaxwidth(double width); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional and can be called once. // This is a 5.5 syntax. // width is the maximum width. // Returns 0 if successful. extern int lefwLayerRoutingMinwidth(double width); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional. // This is a 5.5 syntax. // Area is the minimum area size limit for metal that encloses an empty area. // Width is optional, it says the rule only applies when a donut is careted // from a wire of width <= width. The parameter width is required for the // routine lefwLayerRoutineMinenclosedarea. If width is optional, a "0" // value is assigned for that index slot of the array. // Returns 0 if successful. extern int lefwLayerRoutingMinenclosedarea(int numMinenclosed, double* area, double* width); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional and can be called once. // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwLayerRoutingMinstep(double distance); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional and can be called once. // This routine is equivalent to lefwLayerRoutingMinstep, except it also // takes the options for type & Lengthsum. // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwLayerRoutingMinstepWithOptions(double distance, const char* rule, // INSIDECORNER|OUTSIDECORNER|STEP double maxLength); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional and can be called once. // This routine is equivalent to lefwLayerRoutingMinstep, except it also // takes the option for MaxEdges. // This is a 5.7 syntax. // Returns 0 if successful. extern int lefwLayerRoutingMinstepMaxEdges(double distance, double maxEdges); // This routine must be called only once after lefwStartLayerRouting. // This routine is optional and can be called once. // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwLayerRoutingProtrusion(double width1, double length, double width2); // This routine must be called only after lefwStartLayerRouting. // This routine is optional and can be called multiple times. // This is a 5.5 syntax. // numLength has the size of the array length. // length is an array of length values. // Returns 0 if successful. extern int lefwLayerRoutingStartSpacingtableParallel(int numLength, double* length); // This routine must be called only after // lefwLayerRoutingStartSpacingtableParallel. // This routine is required after lefwLayerRoutingStartSpacingtableParallel. // This routine can be called multiple times. // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwLayerRoutingSpacingtableParallelWidth(double width, int numSpacing, double* spacing); // This routine must be called only after lefwStartLayerRouting. // This routine is optional and can be called multiple times. // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwLayerRoutingStartSpacingtableInfluence(); // This routine must be called only after // lefwLayerRoutingStartSpacingtableInfluence. // This routine is required after lefwLayerRoutingStartSpacingtableInfluence. // This routine can be called multiple times. // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwLayerRoutingSpacingInfluenceWidth(double width, double distance, double spacing); // This routine must be called only after lefwStartLayerRouting. // This routine is optional and can be called multiple times. // This is a 5.7 syntax. // Returns 0 if successful. extern int lefwLayerRoutingStartSpacingtableTwoWidths(); // This routine must be called only after // lefwLayerRoutingStartSpacingtableInfluence. // This routine is required after lefwLayerRoutingStartSpacingtableTwoWidths. // This routine can be called multiple times. // This is a 5.7 syntax. // Returns 0 if successful. extern int lefwLayerRoutingSpacingtableTwoWidthsWidth(double width, double runLength, // PRL, optional (0) int numSpacing, double* spacing); // This routine can be called after lefwLayerRoutingStartSpacingtableParallel // or lefwLayerRoutingStartSpacingtableInfluence. // It can only be called once. // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwLayerRoutineEndSpacingtable(); // This routine must be called after the lefwStartLayer call (if any). // The routine can be called only once per section. // Returns 0 if successful. extern int lefwEndLayerRouting(const char* layerName); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called multiple times. // if the value for the variable value is not 0, one of the following // routines have to be called: lefwLayerACFrequency, // lefwLayerACWidth, lefwLayerACCutarea, or // lefwLayerACTableEntries // Returns 0 if successful. extern int lefwLayerACCurrentDensity(const char* type, double value); // This routine must be called after lefwLayerACCurrentDensity. // This routine is required and can be called only once after each // lefwLayerACCurrentDensity. // Returns 0 if successful. extern int lefwLayerACFrequency(int numFrequency, double* frequency); // This routine must be called after lefwLayerACCurrentDensity. // This routine is optional and can be called only once after each // lefwLayerACCurrentDensity. // This routine can only be called in Layer Routing // Returns 0 if successful. extern int lefwLayerACWidth(int numWidths, double* widths); // This routine must be called after lefwLayerACCurrentDensity. // This routine is optional and can be called only once after each // lefwLayerACCurrentDensity. // This routine can only be called in Layer // Returns 0 if successful. extern int lefwLayerACCutarea(int numCutareas, double* cutareas); // This routine must be called after lefwLayerACCurrentDensity. // This routine is required and can be called only once after each // lefwLayerACCurrentDensity. // Returns 0 if successful. extern int lefwLayerACTableEntries(int numEntries, double* entries); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called multiple times. // if the value for the variable value is not 0, one of the following // routines have to be called: lefwLayerDCWidth, lefwLayerDCCutarea, or // lefwLayerDCTableEntries // Returns 0 if successful. extern int lefwLayerDCCurrentDensity(const char* type, double value); // This routine must be called after lefwLayerDCCurrentDensity. // This routine is optional and can be called only once after each // lefwLayerDCCurrentDensity. // This routine can only be called in Layer Routing // Returns 0 if successful. extern int lefwLayerDCWidth(int numWidths, double* widths); // This routine must be called after lefwLayerDCCurrentDensity. // This routine is optional and can be called only once after each // lefwLayerDCCurrentDensity. // This routine can only be called in Layer // Returns 0 if successful. extern int lefwLayerDCCutarea(int numCutareas, double* cutareas); // This routine must be called after lefwLayerDCCurrentDensity. // This routine is required and can be called only once after each // lefwLayerDCCurrentDensity. // Returns 0 if successful. extern int lefwLayerDCTableEntries(int numEntries, double* entries); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional. The oxide value, can be either OXIDE1, OXIDE2, // OXIDE3, or OXIDE4. Each can only be called once within a layer. // This routine is valid only if the layer type is either ROUTING or CUT. // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwLayerAntennaModel(const char* oxide); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaAreaRatio(double value); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // Either this routine or lefwLayerAntennaDiffAreaRatioPwl can be called, but // not both // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaDiffAreaRatio(double value); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // Either this routine or lefwLayerAntennaDiffAreaRatio can be called, but // not both // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaDiffAreaRatioPwl(int numPwls, double* diffusions, double* ratios); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaCumAreaRatio(double value); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // Either this routine or lefwLayerAntennaCumDiffAreaRatioPwl can be called, // but not both // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaCumDiffAreaRatio(double value); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // Either this routine or lefwLayerAntennaCumDiffAreaRatio can be called, but // not both // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaCumDiffAreaRatioPwl(int numPwls, double* diffusions, double* ratios); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // The option DIFFUSEONLY is a 5.4 syntax. // If DIFFUSEONLY, lefwLayerRoutingAntennaLength is not allowed. // This function is similar to lefwLayerRoutingAntennaArea // diffUseOnly has to be DIFFUSEONLY. // Returns 0 if successful. extern int lefwLayerAntennaAreaFactor(double value, const char* diffUseOnly); // optional(NULL) // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING. // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaSideAreaRatio(double value); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING. // Either this routine or lefwLayerAntennaDiffSideAreaRatioPwl can be // called, but not both // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaDiffSideAreaRatio(double value); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // Either this routine or lefwLayerAntennaDiffSideAreaRatio can be called, // but not both // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaDiffSideAreaRatioPwl(int numPwls, double* diffusions, double* ratios); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING. // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaCumSideAreaRatio(double value); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING. // Either this routine or lefwLayerAntennaCumDiffSideAreaRatioPwl can be // called, but not both // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaCumDiffSideAreaRatio(double value); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // Either this routine or lefwLayerAntennaCumDiffSideAreaRatio can be called, // but not both // This is a 5.4 syntax. // Either this routine or lefwLayerRoutingAntennaLength is allowed, not both. // Returns 0 if successful. extern int lefwLayerAntennaCumDiffSideAreaRatioPwl(int numPwls, double* diffusions, double* ratios); // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING. // The option DIFFUSEONLY is a 5.4 syntax. // diffUseOnly has to be DIFFUSEONLY. // Returns 0 if successful. extern int lefwLayerAntennaSideAreaFactor(double value, const char* diffUseOnly); // optional(NULL) // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // This is a 5.7 routine. // Returns 0 if successful. extern int lefwLayerAntennaCumRoutingPlusCut() ; // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // This is a 5.7 routine. // Returns 0 if successful. extern int lefwLayerAntennaGatePlusDiff(double plusDiffFactor) ; // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // This is a 5.7 routine. // Returns 0 if successful. extern int lefwLayerAntennaAreaMinusDiff(double minusDiffFactor) ; // This routine must be called after lefwStartLayerRouting or lefwStartLayer. // This routine is optional and can be called only once within a layer // after each lefwLayerAntennaModel function. // This routine is valid only if the layer type is either ROUTING or CUT. // This is a 5.7 routine. // Returns 0 if successful. extern int lefwLayerAntennaAreaDiffReducePwl(int numPwls, double* diffAreas, double* metalDiffFactors); // This routine must be called only once after lefwStartLayer. // The option MINIMUMDENSITY is a 5.4 syntax. // Returns 0 if successful. extern int lefwMinimumDensity(double minDensity); // This routine must be called only once after lefwStartLayer. // The option MAXIMUMDENSITY is a 5.4 syntax. // Returns 0 if successful. extern int lefwMaximumDensity(double maxDensity); // This routine must be called only once after lefwStartLayer. // The option DENSITYCHECKWINDOW is a 5.4 syntax. // Returns 0 if successful. extern int lefwDensityCheckWindow(double checkWindowLength, double checkWindowWidth); // This routine must be called only once after lefwStartLayer. // The option DENSITYCHECKSTEP is a 5.4 syntax. // Returns 0 if successful. extern int lefwDensityCheckStep(double checkStepValue); // This routine must be called only once after lefwStartLayer. // The option FILLACTIVESPACING is a 5.4 syntax. // Returns 0 if successful. extern int lefwFillActiveSpacing(double fillToActiveSpacing); // This routine must be called only once after all the layers. // This routine is optional. // This is a 5.5 syntax. // Returns 0 if succesful. extern int lefwMaxviastack(int value, const char* bottomLayer, // optional (NULL) const char* topLayer); // optional (NULL) // This routine is called after lefwInit. // This section of routines is optional. // The routine can be called only once. // Returns 0 if successful. // The routine starts propertydefinitions section. extern int lefwStartPropDef(); // This routine must be called after lefwStartPropDef. // This routine can be called multiple times. // It adds integer property definition to the statement. // Returns 0 if successful. // The objType can be LIBRARY or VIA or MACRO or PIN. extern int lefwIntPropDef( const char* objType, // LIBRARY | LAYER | VIA | VIARULE | // NONDEFAULTRULE | MACRO | PIN const char* propName, double leftRange, // optional(0) - RANGE double rightRange, // optional(0) int propValue); // optional(NULL) // This routine must be called after lefwStartPropDef. // This routine can be called multiple times. // It adds real property definition to the statement. // Returns 0 if successful. // The objType can be LIBRARY or VIA or MACRO or PIN. extern int lefwRealPropDef( const char* objType, // LIBRARY | LAYER | VIA | VIARULE | // NONDEFAULTRULE | MACRO | PIN const char* propName, double leftRange, // optional(0) - RANGE double rightRange, // optional(0) double propValue); // optional(NULL) // This routine must be called after lefwStartPropDef. // This routine can be called multiple times. // It adds string property definition to the statement. // Returns 0 if successful. // The objType can be LIBRARY or VIA or MACRO or PIN. extern int lefwStringPropDef( const char* objType, // LIBRARY | LAYER | VIA | VIARULE | // NONDEFAULTRULE | MACRO | PIN const char* propName, double leftRange, // optional(0) - RANGE double rightRange, // optional(0) const char* propValue); // optional(NULL) // This routine must be called after the lefwStartPropDef call (if any). // The routine can be called only once. // Returns 0 if successful. extern int lefwEndPropDef(); // This routine is called after lefwInit. // This routine must be called only once. // Returns 0 if successful. // The routine starts the via section. All of the vias must follow. extern int lefwStartVia(const char* viaName, const char* isDefault); // optional(NULL) - DEFAULT // This routine is optional, it call only be called after lefwStartVia. // It can only be called once. // Returns 0 if successful. extern int lefwViaTopofstackonly(); // TOPOFSTACKONLY // This routine is optional, it call only be called after lefwStartVia. // It can only be called once. // Returns 0 if successful. extern int lefwViaForeign(const char* foreignName, double xl, // optional(0) - pt(x) double yl, // optional(0) - pt(y) int orient); // optional(-1) // This routine is optional, it call only be called after lefwStartVia. // It can only be called once. // Returns 0 if successful. // This routine is the same as lefwViaForeign, except orient is a char* extern int lefwViaForeignStr(const char* foreignName, double xl, // optional(0) - pt(x) double yl, // optional(0) - pt(y) const char* orient); // optional("") // This routine is optional, it call only be called after lefwStartVia. // Either this routine or lefwViaViarule can be called within a via. // It can only be called once in a via. // Returns 0 if successful. extern int lefwViaResistance(double resistance); // RESISTANCE // This routine must be called after lefwStartVia. // It can be called multiple times. // Returns 0 if successful. extern int lefwViaLayer(const char* layerName); // LAYER // This routine can call only after lefwViaLayer. // Either this routine or lefwViaLayerPolygon can be called within a layer // It can be called multiple times. // Returns 0 if successful. // mask is 5.8 syntax extern int lefwViaLayerRect(double x1l, // RECT pt1(x) double y1l, // RECT pt1(y) double x2l, // RECT pt2(x) double y2l, // RECT pt2(y) int mask = 0); // This routine can call only after lefwViaLayer. // Either this routine or lefwViaLayerRect can be called within a layer // It can be called multiple times. // This is a 5.6 syntax. // Returns 0 if successful. // mask is 5.8 syntax extern int lefwViaLayerPolygon(int num_polys, double* xl, double* yl, int mask = 0); // This routine can call only after lefwStartVia. // Either this routine or lefwViaResistance can be called within a via. // It can only be called once in a via. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwViaViarule(const char* viaRuleName, double xCutSize, double yCutSize, const char* botMetalLayer, const char* cutLayer, const char* topMetalLayer, double xCutSpacing, double yCutSpacing, double xBotEnc, double yBotEnc, double xTopEnc, double yTopEnc); // This routine can call only after lefwViaViarule. // It can only be called once. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwViaViaruleRowCol(int numCutRows, int numCutCols); // This routine can call only after lefwViaViarule. // It can only be called once. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwViaViaruleOrigin(double xOffset, double yOffset); // This routine can call only after lefwViaViarule. // It can only be called once. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwViaViaruleOffset(double xBotOffset, double yBotOffset, double xTopOffset, double yTopOffset); // This routine can call only after lefwViaViarule. // It can only be called once. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwViaViarulePattern(const char* cutPattern); // This routine is called after lefwVia. // This routine is optional, it adds string property to the statement. // It can be called multiple times. // Returns 0 if successful. extern int lefwStringProperty(const char* propName, const char* propValue); // This routine is called after lefwVia. // This routine is optional, it adds real property to the statement. // It can be called multiple times. // Returns 0 if successful. extern int lefwRealProperty(const char* propName, double propValue); // This routine is called after lefwVia. // This routine is optional, it adds int property to the statement. // It can be called multiple times. // Returns 0 if successful. extern int lefwIntProperty(const char* propName, int propValue); // This routine must be called after the lefwStartVia call (if any). // The routine can be called only once. // Returns 0 if successful. extern int lefwEndVia(const char* viaName); // This routine is called after lefwInit. // This routine must be called as a set with lefwViaRuleLayer, lefwViaRuleVia // and lefwEndViaRule // multiple times. // Returns 0 if successful. // The routine starts the via rule section. The via rule data and its property // must follow extern int lefwStartViaRule(const char* viaRuleName); // This routine is called after lefwStartViaRule. // This routine has to be called 2 times exact. // Returns 0 if successful. // The direction1 or direction2 can be HORIZONTAL or VERTICAL. extern int lefwViaRuleLayer( const char* layerName, const char* direction, // HORIZONTAL | VERTICAL double minWidth, // optional(0) - WIDTH double maxWidth, // optional(0) - WIDTH double overhang, // optional(0) - OVERHANG double metalOverhang); // optional(0) - METALOVERHANG // This routine is called after lefwViaRuleLayer is called twice. // This routine is required in a viarule and can be called more than once. // Returns 0 if successful. // The direction1 or direction2 can be HORIZONTAL or VERTICAL. extern int lefwViaRuleVia( const char* viaName); // This routine must be called after the lefwStartViaRule call (if any). // The routine can be called only once per lefwStartViaRule. // Returns 0 if successful. extern int lefwEndViaRule(const char* viaRuleName); // This routine is called after lefwInit. // This routine must be called as a set with lefwViaRuleGenLayer, // lefwViaRuleGenLayer3, and lefwEndViaRuleGen multiple times. // Returns 0 if successful. // The routine starts the via rule section. The via rule data and its property // must follow extern int lefwStartViaRuleGen(const char* viaRuleName); // This routine is called after lefwSartViaRuleGen. // This routine is optional // Returns 0 if successful extern int lefwViaRuleGenDefault(); // This routine is called after lefwStartViaRuleGen. // This routine has to be called 2 times exact. // Returns 0 if successful. // Either this routine or lefwViaRuleGenLayerEnclosure, not both. // The direction1 or direction2 can be HORIZONTAL or VERTICAL. extern int lefwViaRuleGenLayer( const char* layerName, const char* direction, // HORIZONTAL | VERTICAL double minWidth, // optional(0) - WIDTH double maxWidth, // optional(0) - WIDTH double overhang, // optional(0) - OVERHANG double metalOverhang); // optional(0) - METALOVERHANG // This routine is called after lefwStartViaRuleGen. // This routine has to be called 2 times exact. // This is 5.5 syntax // Returns 0 if successful. // Either this routine or lefwViaRuleGenLayer, not both. extern int lefwViaRuleGenLayerEnclosure( const char* layerName, double overhang1, double overhang2, double minWidth, // optional(0) - WIDTH double maxWidth); // optional(0) - WIDTH // This routine is called after lefwViaRuleLayerGen is called twice. // This routine is optional in a viarule generate and can be called once. // Returns 0 if successful. // The direction1 or direction2 can be HORIZONTAL or VERTICAL. extern int lefwViaRuleGenLayer3( const char* layerName, double xl, double yl, // RECT pt1(x), pt1(y) double xh, double yh, // RECT pt2(x), pt2(y) double xSpacing, double ySpacing, // SPACING x and y double resistance); // optional(0) - RESISTANCE // This routine must be called after the lefwStartViaRuleGen call (if any). // The routine can be called only once per lefwStartViaRuleGen. // Returns 0 if successful. extern int lefwEndViaRuleGen(const char* viaRuleName); // This routine is called after lefwInit. // This routine must be called only once. // Returns 0 if successful. // The routine starts the nonDefaultRule section. The nonDefaultRule layers // must follow extern int lefwStartNonDefaultRule(const char* ruleName); // This routine is called after lefwInit. // This routine must be called after lefwStartNonDefaultRule // This routine can be called multiple times. // Returns 0 if successful. extern int lefwNonDefaultRuleLayer(const char* routingLayerName, double width, // WIDTH double minSpacing, // MINSPACING double wireExtension, // optinal(0) - WIREEXTENSION double resistance, // optinal(0) - RESISTANCE RPERQ double capacitance, // optinal(0) - CAPACITANCE CPERSQDIST double edgeCap); // optinal(0) - EDGECAPACITANCE // This routine is called after lefwInit. // This routine must be called after lefwStartNonDefaultRule // This routine is optional and it can be called only once. // Returns 0 if successful. extern int lefwNonDefaultRuleHardspacing(); // This routine is called after lefwStartNonDefaultRule. // This routine must be called only once for each via section. // Returns 0 if successful. // The routine starts the nondefaultrule via section. // Call the following via functions for the rest of NONDEFAULTRULE VIA: // lefwViaTopofstackonly // lefwViaForeign // lefwViaForeignStr // lefwViaResistance // lefwViaLayer // lefwViaLayerRect // lefwNonDefaultRuleEndVia extern int lefwNonDefaultRuleStartVia(const char* viaName, const char* isDefault); // optional(NULL) - DEFAULT // This routine must be called after the lefwNonDefaultRuleStartVia call. // The routine can be called only once per via section. // Returns 0 if successful. extern int lefwNonDefaultRuleEndVia(const char* viaName); // This routine is called after lefwStartNonDefaultRule. // This routine can be called multiple times. // Returns 0 if successful. extern int lefwNonDefaultRuleUseVia(const char* viaName); // This routine is called after lefwStartNonDefaultRule. // This routine can be called multiple times. // Returns 0 if successful. extern int lefwNonDefaultRuleUseViaRule(const char* viaRuleName); // This routine is called after lefwStartNonDefaultRule. // This routine can be called multiple times. // Returns 0 if successful. extern int lefwNonDefaultRuleMinCuts(const char* layerName, int numCuts); // This routine must be called after the lefwStartNonDefaultRule call (if any). // The routine can be called only once. // Returns 0 if successful. extern int lefwEndNonDefaultRule(const char* ruleName); // This routine is called after lefwInit. // This section of routines is optional. // This routine can be called only once. // Returns 0 if successful. // It starts the spacing section. extern int lefwStartSpacing(); // This routine must be called after lefwStartSpacing. // It can be called multiple times. // Returns 0 if successful. // The stack has to be STACK. extern int lefwSpacing(const char* layerName1, const char* layerName2, double minSpace, const char* stack); // optional(NULL) // This routine must be called after the lefwStartSpacing call (if any). // The routine can be called only once. // Returns 0 if successful. extern int lefwEndSpacing(); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwUniversalNoiseMargin (double high, double low); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwEdgeRateThreshold1 (double num); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwEdgeRateThreshold2 (double num); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwEdgeRateScaleFactor (double num); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. // This routine starts the noisetable section. // This api is obsolete in 5.4. extern int lefwStartNoiseTable(int num); // This routine is called after lefwStartNoiseTable or lefwStartCorrectTable. // This routine is optional and it can be called multiple times // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwEdgeRate(double num) ; // This routine is called after lefwEdgeRate. // This routine is optional and it can be called only once inside lefwEdgeRate. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwOutputResistance(int numResists, double* resistance); // This routine is called after lefwOutputResistance. // This routine is optional and it can be called multiple times inside // lefwOutputResistance // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwVictims(int length, int numNoises, double* noises); // This routine must be called after the lefwStartNoiseTable call (if any). // The routine can be called only once per section. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwEndNoiseTable(); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. // This routine starts the correctTable section. // This api is obsolete in 5.4. extern int lefwStartCorrectTable(int num); // This routine must be called after the lefwStartCorrectTable call (if any). // The routine can be called only once per section. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwEndCorrectTable(); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. extern int lefwMinFeature (double x, double y); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. // extern int lefwDielectric (float dielectric); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. // This routine starts the irdrop section. // This api is obsolete in 5.4. extern int lefwStartIrdrop(); // This routine is must be called after lefwStartIrdrop. // It can be called multiple times. // Returns 0 if successful. // The currentsNvolts is a list of current and volts. // This api is obsolete in 5.4. extern int lefwIrdropTable(const char* tableName, const char* currentsNvolts); // This routine must be called after the lefwStartIrdrop call (if any). // The routine can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwEndIrdrop(); // This routine is must be called after lefwInit. // It can be called multiple times. // Returns 0 if successful. // The classType can be PAD or CORE. // The symmetry can be a list of X or Y or R90. extern int lefwSite(const char* siteName, const char* classType, const char* symmetry, double width, double height); // This routine is must be called after lefwSite. // It can be called multiple times. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwSiteRowPattern(const char* siteName, int orient); // This routine is must be called after lefwSite. // It can be called multiple times. // This is a 5.6 syntax. // Returns 0 if successful. // This routine is the same as lefwSiteRowPattern, except orient is a char* extern int lefwSiteRowPatternStr(const char* siteName, const char *orient); // This routine must be called after the lefwSite call (if any). // The routine can be called only once after lefwSite. // This is a 5.4 syntax. // Returns 0 if successful. extern int lefwEndSite(const char* siteName); // This routine is called after lefwInit. // This routine is optional and it can be called multiple times. // Returns 0 if successful. // This routine starts the array section. extern int lefwStartArray(const char* arrayName); // This routine is called after lefwStartArray. // Either this routine, lefwArrayCanplace, lefwArrayCannotoccupy, // lefwArrayTracks, or lefwStartArrayFloorplan must be called at least once. // It can be call multiple times. // Returns 0 if successful. extern int lefwArraySite(const char* name, double origX, double origY, int orient, double numX, double numY, double spaceX, double spaceY); // This routine is called after lefwStartArray. // Either this routine, lefwArrayCanplace, lefwArrayCannotoccupy, // lefwArrayTracks, or lefwStartArrayFloorplan must be called at least once. // It can be call multiple times. // Returns 0 if successful. // This routine is the same as lefwArraySite, except orient is a char* extern int lefwArraySiteStr(const char* name, double origX, double origY, const char *orient, double numX, double numY, double spaceX, double spaceY); // This routine is called after lefwStartArray. // Either this routine, lefwArraySite, lefwArrayCannotoccupy, // lefwArrayTracks, or lefwStartArrayFloorplan must be called at least once. // It can be call multiple times. // Returns 0 if successful. extern int lefwArrayCanplace(const char* name, double origX, double origY, int orient, double numX, double numY, double spaceX, double spaceY); // This routine is called after lefwStartArray. // Either this routine, lefwArraySite, lefwArrayCannotoccupy, // lefwArrayTracks, or lefwStartArrayFloorplan must be called at least once. // It can be call multiple times. // Returns 0 if successful. // This routine is the same as lefwArrayCanplace, except orient is a char* extern int lefwArrayCanplaceStr(const char* name, double origX, double origY, const char *orient, double numX, double numY, double spaceX, double spaceY); // This routine is called after lefwStartArray. // Either this routine, lefwArraySite, lefwArrayCanplace, // lefwArrayTracks, or lefwStartArrayFloorplan must be called at least once. // It can be call multiple times. // Returns 0 if successful. extern int lefwArrayCannotoccupy(const char* name, double origX, double origY, int orient, double numX, double numY, double spaceX, double spaceY); // This routine is called after lefwStartArray. // Either this routine, lefwArraySite, lefwArrayCanplace, // lefwArrayTracks, or lefwStartArrayFloorplan must be called at least once. // It can be call multiple times. // Returns 0 if successful. // This routine is the same as lefwArrayTracks, except orient is a char* extern int lefwArrayCannotoccupyStr(const char* name, double origX, double origY, const char *orient, double numX, double numY, double spaceX, double spaceY); // This routine is called after lefwStartArray. // Either this routine, lefwArraySite, lefwArrayCanplace, lefwArrayCannotoccupy, // or lefwStartArrayFloorplan must be called at least once. // It can be call multiple times. // Returns 0 if successful. extern int lefwArrayTracks(const char* xy, double start, int numTracks, double space, const char* layers); // This routine is called after lefwStartArray. // Either this routine, lefwArraySite, lefwArrayCanplace, lefwArrayCannotoccupy, // or lefwArrayTracks must be called at least once. // It can be call multiple times. // Returns 0 if successful. // The routine starts the array floorplan section extern int lefwStartArrayFloorplan(const char* name); // This routine must be called after lefwStartArrayFloorplan. // It can be called multiple times. // Returns 0 if successful. // The site can be CANPLACE or CANNOTOCCUPY extern int lefwArrayFloorplan(const char* site, const char* name, double origX, double origY, int orient, int numX, int numY, double spaceX, double spaceY); // This routine must be called after lefwStartArrayFloorplan. // It can be called multiple times. // Returns 0 if successful. // The site can be CANPLACE or CANNOTOCCUPY // This routine is the same as lefwArrayFloorplan, except orient is a char* extern int lefwArrayFloorplanStr(const char* site, const char* name, double origX, double origY, const char *orient, int numX, int numY, double spaceX, double spaceY); // This routine must be called after the lefwStartArrayFloorplan call (if any). // The routine can be called only once per section. // Returns 0 if successful. extern int lefwEndArrayFloorplan(const char* name); // This routine is called after lefwStartArray. // This routine is optional. // It can be called multiple times. // Returns 0 if successful. // The xy can be X or Y. extern int lefwArrayGcellgrid(const char* xy, double startXY, int colRows, double spaceXY); // This routine is called after lefwStartArray. // This section of routines is optional and can be call only once. // Returns 0 if successful. // The routine starts the array defaultcap section extern int lefwStartArrayDefaultCap(int size); // This routine must be called after lefwStartArrayDefaultCap. // It can be called multiple times. // Returns 0 if successful. extern int lefwArrayDefaultCap(double numPins, double cap); // This routine must be called after the lefwStartArrayDefaultCap call (if any). // The routine can be called only once. // Returns 0 if successful. extern int lefwEndArrayDefaultCap(); // This routine must be called after the lefwStartArray call (if any). // The routine can be called only once per section. // Returns 0 if successful. extern int lefwEndArray(const char* arrayName); // This routine is must be called after lefwInit. // This routine can be called multiple times. // Returns 0 if successful. // This routine starts the macro section. extern int lefwStartMacro(const char* macroName); // This routine is called after lefwStartMacro. // This routine is optional and can be called only once per macro section. // Returns 0 if successful. // The value1 can be COVER, RING, BLOCK, PAD, CORE, or ENCAP. // The value2 can be BUMP if value1 is COVER, // or BLACKBOX, or SOFT if value1 is BLOCK, // or INPUT, OUTPUT, INOUT, POWER, or SPACER if value1 is PAD, // or FEEDTHRU, TIEHIGH, TIELOW, SPACER, ANTENNACELL, or WELLTAP // if value1 is CORE, // or PRE, POST, TOPLEFT, TOPRIGHT, BOOTOMLEFT, or BOTTOMRIGHT if value1 is // ENCAP. extern int lefwMacroClass(const char* value1, const char* value2); // optional(NULL) // This routine is must be called after lefwInit. // This routine can be called multiple times. // Returns 0 if successful. // This is a 5.8 syntax. extern int lefwMacroFixedMask(); // This routine is called after lefwStartMacro. // This routine is optional and can be called only once per macro section. // Returns 0 if successful. // The value1 can be USER, GENERATE, or BLOCK. extern int lefwMacroSource(const char* value1); // This routine is called after lefwStartMacro. // This routine is optional and can be called multiple times per macro section. // Returns 0 if successful. extern int lefwMacroForeign(const char* name, double xl, // optional(0) - pt(x) double yl, // optional(0) - pt(y) int orient); // optional(-1) - 0 to 7 // This routine is called after lefwStartMacro. // This routine is optional and can be called multiple times per macro section. // Returns 0 if successful. // This routine is the same as lefwMacroForeign, except orient is a char* extern int lefwMacroForeignStr(const char* name, double xl, // optional(0) - pt(x) double yl, // optional(0) - pt(y) const char *orient); // optional("") // This routine is called after lefwStartMacro. // This routine is optional and can be called only once per macro section. // Returns 0 if successful. extern int lefwMacroOrigin(double xl, // pt(x) double yl); // pt(y) // This routine is called after lefwStartMacro. // This routine is optional and can be called only once per macro section. // Returns 0 if successful. extern int lefwMacroEEQ(const char* macroName); // This routine is called after lefwStartMacro. // This routine is optional and can be called only once per macro section. // Returns 0 if successful. extern int lefwMacroLEQ(const char* macroName); // This routine is called after lefwStartMacro. // This routine must be called only once per macro section. // Returns 0 if successful. extern int lefwMacroSize(double width, double height); // This routine is called after lefwStartMacro. // This routine is optional and can be called only once per macro section. // Returns 0 if successful. // The symmetry can be a list of X, Y, or R90 extern int lefwMacroSymmetry(const char* symmetry); // This routine is called after lefwStartMacro. // This routine must be called only once per macro section. // Returns 0 if successful. extern int lefwMacroSite(const char* siteName); // This routine is called after lefwStartMacro. // This routine must be called at least once per macro section. // Returns 0 if successful. extern int lefwMacroSitePattern(const char* name, double origX, double origY, // optional(0) int orient, // optional(-1) int numX, int numY, // optional(0) double spaceX, double spaceY); // optional(0) // This routine is called after lefwStartMacro. // This routine must be called at least once per macro section. // Returns 0 if successful. // This routine is the same as lefwMacroSitePattern, except orient is a char* extern int lefwMacroSitePatternStr(const char* name, double origX, double origY, // optional(0) const char *orient, // optional (-1) int numX, int numY, // optional(0) double spaceX, double spaceY); // optional(0) // This routine is called after lefwStartMacro. // This routine is optional and can be called only once per macro section. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPower(double power); // This routine must be called after the lefwStartMacro call (if any). // The routine can be called only once per macro section. // Returns 0 if successful. extern int lefwEndMacro(const char* macroName); // This routine is called after lefwStartMacro. // This routine is optional and can be called only once per macro section. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwStartMacroDensity(const char* layerName); // This routine is called after lefwStartMacroDensity. // This routine can be called multiple times. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwMacroDensityLayerRect(double x1, double y1, double x2, double y2, double densityValue); // This routine must be called after the lefwStartMacroPin call (if any). // The routine can be called only once per macro section. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwEndMacroDensity(); // This routine must be called after the lefwStartMacro call (if any). // The routine can be called multiple time. // Returns 0 if successful. // It starts the macro pin section within macro. extern int lefwStartMacroPin(const char* pinName); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. extern int lefwMacroPinTaperRule(const char* ruleName); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. extern int lefwMacroPinForeign(const char* name, double xl, // optional(0) double yl, // optional(0) int orient); // optional(-1) - 0 to 7 // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // Ths routine is the same as lefwMacroPinForeign, except orient is a char* extern int lefwMacroPinForeignStr(const char* name, double xl, // optional(0) double yl, // optional(0) const char* orient); // optional("") // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. extern int lefwMacroPinLEQ(const char* pinName); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // The direction can be INPUT, OUTPUT, OUTPUT TRISTATE, INOUT, or FEEDTHRU. extern int lefwMacroPinDirection(const char* direction); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // The use can be SIGNAL, ANALOG, POWER, GROUND, or CLOCK. extern int lefwMacroPinUse(const char* use); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // The namce can be ABUTMENT, RING, or FEEDTHRU. extern int lefwMacroPinShape(const char* name); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. extern int lefwMacroPinMustjoin(const char* name); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwMacroPinNetExpr(const char* name); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwMacroPinSupplySensitivity(const char* pinName); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // This is a 5.6 syntax. // Returns 0 if successful. extern int lefwMacroPinGroundSensitivity(const char* pinName); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinOutputnoisemargin(int high, int low); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinOutputresistance(int high, int low); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinInputnoisemargin(int high, int low); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinPower(double power); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinLeakage(double leakage); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinCapacitance(double capacitance); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinResistance(double resistance); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinPulldownres(double resistance); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinTieoffr(double resistance); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinVHI(double voltage); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinVLO(double voltage); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinRisevoltagethreshold(double voltage); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinFallvoltagethreshold(double voltage); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinRisethresh(double capacitance); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinFallthresh(double capacitance); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinRisesatcur(double current); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinFallsatcur(double current); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // The name can be ACTIVE or RESISTIVE. // This api is obsolete in 5.4. extern int lefwMacroPinCurrentsource(const char* name); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroPinIV_Tables(const char* lowName, const char* highName); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called multiple times. // Either this routine or 5.4 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennasize(double value, const char* layerName); // optional(NULL) // This routine is called after lefwStartMacroPin. // This routine is optional and can be called multiple times. // Either this routine or 5.4 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennaMetalArea(double value, const char* layerName); // optional(NULL) // This routine is called after lefwStartMacroPin. // This routine is optional and can be called multiple times. // Either this routine or 5.4 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennaMetalLength(double value, const char* layerName); // optional(NULL) // This routine is called after lefwStartMacroPin. // This routine is optional and can be called multiple times. // This is a 5.4 syntax. // Either this routine or 5.3 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennaPartialMetalArea(double value, const char* layerName); // optional(NULL) // This routine is called after lefwStartMacroPin. // This routine is optional and can be called multiple times. // This is a 5.4 syntax. // Either this routine or 5.3 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennaPartialMetalSideArea(double value, const char* layerName); // optional(NULL) // This routine is called after lefwStartMacroPin. // This routine is optional and can be called multiple times. // This is a 5.4 syntax. // Either this routine or 5.3 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennaPartialCutArea(double value, const char* layerName); // optional(NULL) // This routine is called after lefwStartMacroPin. // This routine is optional and can be called multiple times. // This is a 5.4 syntax. // Either this routine or 5.3 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennaDiffArea(double value, const char* layerName); // optional(NULL) // This routine is called after lefwStartMacroPin. // The oxide value, can be either OXIDE1, OXIDE2, OXIDE3, or OXIDE4. // This routine is optional. Each oxide value can be called only once // after the lefwStartMacroPin. // This is a 5.5 syntax. // Returns 0 if successful. extern int lefwMacroPinAntennaModel(const char* oxide); // This routine is called after lefwStartMacroPin. // This routine is optional and can be called multiple times. // This is a 5.4 syntax. // Either this routine or 5.3 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennaGateArea(double value, const char* layerName); // optional(NULL) // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // This is a 5.4 syntax. // Either this routine or 5.3 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennaMaxAreaCar(double value, const char* layerName); // optional(NULL) // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // This is a 5.4 syntax. // Either this routine or 5.3 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennaMaxSideAreaCar(double value, const char* layerName); // optional(NULL) // This routine is called after lefwStartMacroPin. // This routine is optional and can be called only once. // This is a 5.4 syntax. // Either this routine or 5.3 Antenna syntax, cannot be both // Returns 0 if successful. extern int lefwMacroPinAntennaMaxCutCar(double value, const char* layerName); // optional(NULL) // This routine must be called after the lefwStartMacroPin call (if any). // The routine can be called only once per macro section. // Returns 0 if successful. extern int lefwEndMacroPin(const char* pinName); // This routine must be called after the lefwStartMacroPin call (if any). // The routine can be called multiple time. // Returns 0 if successful. // It starts the macro pin port section within macro pin. // The classType can be NONE or CORE. extern int lefwStartMacroPinPort(const char* classType); // optional(NULL) // This routine is called after lefwStartMacroPinPort. // Either this routine or lefwMacroPinPortDesignRuleWidth must be called, // but can't be both. // Spacing is optional for minimum spacing. // Returns 0 if successful. extern int lefwMacroPinPortLayer(const char* layerName, double spacing); // optional(0) // This routine is called after lefwStartMacroPinPort. // Either this routine or lefwMacroPinPortLayer must be called, but can't // be both. // width is optional for DesignRuleWidth // This is a 5.4 syntax. // Returns 0 if successful. extern int lefwMacroPinPortDesignRuleWidth(const char* layerName, double width); // optional(0) // This routine is called after lefwMacroPinPortLayer. // Returns 0 if successful. extern int lefwMacroPinPortLayerWidth(double width); // This routine is called after lefwStartMacroPinPortLayer. // Either this routine, lefwStartMacroPinPortLayerRect, or // lefwStartMacroPinPortLayerPolygon must be called. // Returns 0 if successful. extern int lefwMacroPinPortLayerPath(int num_paths, double* xl, double* yl, int numX, // optional(0) int numY, // optional(0) double spaceX, // optional(0) double spaceY, // optional(0) int mask = 0); // optional(0) // This routine is called after lefwStartMacroPinPortLayer. // Either this routine, lefwStartMacroPinPortLayerPath, or // lefwStartMacroPinPortLayerPolygon must be called. // Returns 0 if successful. extern int lefwMacroPinPortLayerRect(double xl1, double yl1, double xl2, double yl2, int numX, // optional(0) int numY, // optional(0) double spaceX, // optional(0) double spaceY, // optional(0) int mask = 0); // optional(0) // This routine is called after lefwStartMacroPinPortLayer. // Either this routine, lefwStartMacroPinPortLayerPath, or // lefwStartMacroPinPortLayerRect must be called. // Returns 0 if successful. extern int lefwMacroPinPortLayerPolygon(int num_polys, double* xl, double* yl, int numX, // optional(0) int numY, // optional(0) double spaceX, // optional(0) double spaceY, // optional(0) int mask = 0); // optional(0) // This routine is called after lefwStartMacroPinPort. // Either this routine or lefwStartMacroPinPortLayer must be called. // Returns 0 if successful. extern int lefwMacroPinPortVia(double xl, double yl, const char* viaName, int numX, // optional(0) int numY, // optional(0) double spaceX, // optional(0) double spaceY, // optional(0) int mask = 0); // optional(0) // This routine must be called after the lefwStartMacroPinPort call (if any). // The routine can be called only once per macro section. // Returns 0 if successful. extern int lefwEndMacroPinPort(); // This routine is called after the lefwStartMacro call (if any). // The routine is optional and can be called multiple times. // Returns 0 if successful. // It starts the macro obs section within macro. extern int lefwStartMacroObs(); // This routine is called after lefwStartMacroObs. // Either this routine, lefwMacroObsDesignRuleWidth, lefwMacroObsVia or // lefwMacroExceptPGNet must be called. // Spacing is optional for minimum spacing. // Returns 0 if successful. extern int lefwMacroObsLayer(const char* layerName, double spacing); // optional(0) // This routine is called after lefwStartMacroObs. // Either this routine, lefwMacroObsLayer, lefwMacroObsVia or // lefwMacroExceptPGNet must be called. // Spacing is optional for minimum spacing. // This is a 5.4 syntax. // Returns 0 if successful. extern int lefwMacroObsDesignRuleWidth(const char* layerName, double width); // optional(0) // This routine is called after lefwStartMacroObs. // Either this routine, lefwMacroObsLayer, lefwMacroObsVia or // lefwMacroObsDesignRuleWidth must be called. // Spacing is optional for minimum spacing. // This is a 5.4 syntax. // Returns 0 if successful. extern int lefwMacroExceptPGNet(const char* layerName); // This routine is called after lefwStartMacroObs. // Returns 0 if successful. extern int lefwMacroObsLayerWidth(double width); // This routine is called after lefwStartMacroObsLayer. // Either this routine, lefwMacroObsLayerRect, or // lefwStartMacroObsLayerPolygon must be called. // Returns 0 if successful. extern int lefwMacroObsLayerPath(int num_paths, double* xl, double* yl, int numX, // optional(0) int numY, // optional(0) double spaceX, // optional(0) double spaceY, // optional(0) int mask = 0); // optional(0) // This routine is called after lefwStartMacroObsLayer. // Either this routine, lefwMacroObsLayerPath, or // lefwStartMacroObsLayerPolygon must be called. // Returns 0 if successful. extern int lefwMacroObsLayerRect(double xl1, double yl1, double xl2, double yl2, int numX, // optional(0) int numY, // optional(0) double spaceX, // optional(0) double spaceY, // optional(0) int mask = 0); // optional(0) // This routine is called after lefwStartMacroObsLayer. // Either this routine, lefwMacroObsLayerPath, or // lefwStartMacroObsLayerPath must be called. // Returns 0 if successful. extern int lefwMacroObsLayerPolygon(int num_polys, double* xl, double* yl, int numX, // optional(0) int numY, // optional(0) double spaceX, // optional(0) double spaceY, // optional(0) int mask = 0); // optional(0) // This routine is called after lefwStartMacroObs. // Either this routine or lefwMacroObsLayer|lefwMacroObsDesignRuleWidth // must be called. // Returns 0 if successful. extern int lefwMacroObsVia(double xl, double yl, const char* viaName, int numX, // optional(0) int numY, // optional(0) double spaceX, // optional(0) double spaceY, // optional(0) int mask = 0); // optional(0) // This routine must be called after the lefwStartMacroObs call (if any). // The routine can be called only once per macro section. // Returns 0 if successful. extern int lefwEndMacroObs(); // This routine is called after the lefwStartMacro call (if any). // The routine is optional and can be called only once. // Returns 0 if successful. // It starts the macro timing section within macro. // This api is obsolete in 5.4. extern int lefwStartMacroTiming(); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // This routine is for {FROMPIN pinName...; [TOPIN pinName...;] | FROMPIN // pinName...;} // This routince can be called multiple times. // The num_frPinNames contains the number of object in the array fromPins. // This api is obsolete in 5.4. extern int lefwMacroTimingPin(const char* fromPin, const char* toPin); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // The riseFall can be RISE or FALL. // This api is obsolete in 5.4. extern int lefwMacroTimingIntrinsic(const char* riseFall, double min, double max, double slewT1, // optional(0) double slewT1Min, // optional(0) double slewT1Max, // optional(0) double slewT2, // optional(0) double slewT2Min, // optional(0) double slewT2Max, // optional(0) double slewT3, // optional(0) double varMin, double varMax); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroTimingRisers(double min, double max); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroTimingFallrs(double min, double max); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroTimingRisecs(double min, double max); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroTimingFallcs(double min, double max); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroTimingRisesatt1(double min, double max); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroTimingFallsatt1(double min, double max); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroTimingRiset0(double min, double max); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwMacroTimingFallt0(double min, double max); // This routine must be called after the lefwStartMacroTiming. // It can be called multiple times. // Returns 0 if successful. // The unateness can be INVERT, NONINVERT or NONUNATE. // This api is obsolete in 5.4. extern int lefwMacroTimingUnateness(const char* unateness); // This routine must be called after the lefwStartMacroTiming call (if any). // The routine can be called only once. // Returns 0 if successful. // This api is obsolete in 5.4. extern int lefwEndMacroTiming(); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. extern int lefwAntenna(const char* type, // INPUTPINANTENNASIZE | // OUTPUTPINANTENNASIZE | // INOUTPINANTENNASIZE double value); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. extern int lefwStartBeginext(const char* name); // This routine is called after lefwBeginext. // This routine is optional, it can be called only once. // Returns 0 if successful. extern int lefwBeginextCreator (const char* creatorName); // This routine is called after lefwBeginext. // This routine is optional, it can be called only once. // It gets the current system time and date. // Returns 0 if successful. extern int lefwBeginextDate (); // This routine is called after lefwBeginext. // This routine is optional, it can be called only once. // Returns 0 if successful. extern int lefwBeginextRevision (int vers1, int vers2); // vers1.vers2 // This routine is called after lefwBeginext. // This routine is optional, it can be called many times. // It allows user to customize their own syntax. // Returns 0 if successful. extern int lefwBeginextSyntax (const char* title, const char* string); // This routine is called after lefwInit. // This routine is optional and it can be called only once. // Returns 0 if successful. extern int lefwEndBeginext(); // General routines that can be called anytime after the Init is called. extern int lefwCurrentLineNumber(); // This routine must call last, it ends the Lef library. // It must be called only once. // Returns 0 if successful. extern int lefwEnd(); // This routine will print the error message. extern void lefwPrintError(int status); // This routine will allow user to write their own comemnt. It will // automactically add a # infront of the line. extern void lefwAddComment(const char* comment); // This routine will indent 3 blank spaces extern void lefwAddIndent(); END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefwWriterCalls.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012 - 2013, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef LEFI_WRITER_H #define LEFI_WRITER_H #include #include #include "lefiKRDefs.hpp" #include "lefiDefs.hpp" #include "lefiUser.hpp" BEGIN_LEFDEF_PARSER_NAMESPACE /* * The main writer function. * The file should already be opened. This requirement allows * the writer to be used with stdin or a pipe. The file name * is only used for error messages. The includeSearchPath is * a colon-delimited list of directories in which to find * include files. */ extern int lefwWrite ( FILE *file, const char *fileName, lefiUserData userData ); /* * Set all of the callbacks that have not yet been set to a function * that will add up how many times a given lef data type was ignored * (ie no callback was done). The statistics can later be printed out. */ extern void lefwSetRegisterUnusedCallbacks ( void ); extern void lefwPrintUnusedCallbacks ( FILE* f ); /* * Set/get the client-provided user data. lefi doesn't look at * this data at all, it simply passes the opaque lefiUserData pointer * back to the application with each callback. The client can * change the data at any time, and it will take effect on the * next callback. The lefi writer and writer maintain separate * user data pointers. */ extern void lefwSetUserData ( lefiUserData ); extern lefiUserData lefwGetUserData ( void ); /* * An enum describing all of the types of writer callbacks. */ typedef enum { lefwUnspecifiedCbkType = 0, lefwVersionCbkType, lefwCaseSensitiveCbkType, lefwNoWireExtensionCbkType, lefwBusBitCharsCbkType, lefwDividerCharCbkType, lefwManufacturingGridCbkType, lefwUseMinSpacingCbkType, lefwClearanceMeasureCbkType, lefwUnitsCbkType, lefwAntennaInputGateAreaCbkType, lefwAntennaInOutDiffAreaCbkType, lefwAntennaOutputDiffAreaCbkType, lefwPropDefCbkType, lefwLayerCbkType, lefwViaCbkType, lefwViaRuleCbkType, lefwNonDefaultCbkType, lefwCrossTalkCbkType, lefwNoiseTableCbkType, lefwCorrectionTableCbkType, lefwSpacingCbkType, lefwMinFeatureCbkType, lefwDielectricCbkType, lefwIRDropCbkType, lefwSiteCbkType, lefwArrayCbkType, lefwMacroCbkType, lefwAntennaCbkType, lefwExtCbkType, lefwEndLibCbkType /* NEW CALLBACKS - each callback has its own type. For each callback * that you add, you must add an item to this enum. */ } lefwCallbackType_e; /* Declarations of function signatures for each type of callback. * These declarations are type-safe when compiling with ANSI C * or C++; you will only be able to register a function pointer * with the correct signature for a given type of callback. * * Each callback function is expected to return 0 if successful. * A non-zero return code will cause the writer to abort. * * The lefwDesignStart and lefwDesignEnd callback is only called once. * Other callbacks may be called multiple times, each time with a different * set of data. * * For each callback, the Lef API will make the callback to the * function supplied by the client, which should either make a copy * of the Lef object, or store the data in the client's own data structures. * The Lef API will delete or reuse each object after making the callback, * so the client should not keep a pointer to it. * * All callbacks pass the user data pointer provided in lefwRead() * or lefwSetUserData() back to the client; this can be used by the * client to obtain access to the rest of the client's data structures. * * The user data pointer is obtained using lefwGetUserData() immediately * prior to making each callback, so the client is free to change the * user data on the fly if necessary. * * Callbacks with the same signature are passed a callback type * parameter, which allows an application to write a single callback * function, register that function for multiple callbacks, then * switch based on the callback type to handle the appropriate type of * data. */ // A declaration of the signature of all callbacks that return nothing. typedef int (*lefwVoidCbkFnType) ( lefwCallbackType_e, lefiUserData ); /* NEW CALLBACK - If your callback returns a pointer to a new class then * you must add a type function here. */ /* Functions to call to register a callback function. */ extern void lefwSetVersionCbk(lefwVoidCbkFnType); extern void lefwSetCaseSensitiveCbk(lefwVoidCbkFnType); extern void lefwSetNoWireExtensionCbk(lefwVoidCbkFnType); extern void lefwSetBusBitCharsCbk(lefwVoidCbkFnType); extern void lefwSetDividerCharCbk(lefwVoidCbkFnType); extern void lefwSetManufacturingGridCbk(lefwVoidCbkFnType); extern void lefwSetUseMinSpacingCbk(lefwVoidCbkFnType); extern void lefwSetClearanceMeasureCbk(lefwVoidCbkFnType); extern void lefwSetUnitsCbk(lefwVoidCbkFnType); extern void lefwAntennaInputGateAreaCbk(lefwVoidCbkFnType); extern void lefwAntennaInOutDiffAreaCbk(lefwVoidCbkFnType); extern void lefwAntennaOutputDiffAreaCbk(lefwVoidCbkFnType); extern void lefwSetPropDefCbk(lefwVoidCbkFnType); extern void lefwSetLayerCbk(lefwVoidCbkFnType); extern void lefwSetViaCbk(lefwVoidCbkFnType); extern void lefwSetViaRuleCbk(lefwVoidCbkFnType); extern void lefwSetNonDefaultCbk(lefwVoidCbkFnType); extern void lefwSetCrossTalkCbk(lefwVoidCbkFnType); extern void lefwSetNoiseTableCbk(lefwVoidCbkFnType); extern void lefwSetCorrectionTableCbk(lefwVoidCbkFnType); extern void lefwSetSpacingCbk(lefwVoidCbkFnType); extern void lefwSetMinFeatureCbk(lefwVoidCbkFnType); extern void lefwSetDielectricCbk(lefwVoidCbkFnType); extern void lefwSetIRDropCbk(lefwVoidCbkFnType); extern void lefwSetSiteCbk(lefwVoidCbkFnType); extern void lefwSetArrayCbk(lefwVoidCbkFnType); extern void lefwSetMacroCbk(lefwVoidCbkFnType); extern void lefwSetAntennaCbk(lefwVoidCbkFnType); extern void lefwSetExtCbk(lefwVoidCbkFnType); extern void lefwSetEndLibCbk(lefwVoidCbkFnType); /* NEW CALLBACK - each callback must have a function to allow the user * to set it. Add the function here. */ /* * Set all of the callbacks that have not yet been set to the following * function. This is especially useful if you want to check to see * if you forgot anything. */ extern void lefwSetUnusedCallbacks (lefwVoidCbkFnType func); // Routine to set the message logging routine for errors typedef void (*LEFI_LOG_FUNCTION)(const char*); extern void lefwSetLogFunction( LEFI_LOG_FUNCTION ); // Routine to set the message logging routine for warnings typedef void (*LEFI_WARNING_LOG_FUNCTION)(const char*); extern void lefwSetWarningLogFunction( LEFI_WARNING_LOG_FUNCTION ); END_LEFDEF_PARSER_NAMESPACE USE_LEFDEF_PARSER_NAMESPACE #endif ================================================ FILE: rsyn/include/lef5.8/lefzlib.hpp ================================================ // ***************************************************************************** // ***************************************************************************** // Copyright 2012, Cadence Design Systems // // This file is part of the Cadence LEF/DEF Open Source // Distribution, Product Version 5.8. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. // // For updates, support, or to become part of the LEF/DEF Community, // check www.openeda.org for details. // // $Author: dell $ // $Revision: #1 $ // $Date: 2017/06/06 $ // $State: $ // ***************************************************************************** // ***************************************************************************** #ifndef LEFZLIB_H typedef void* lefGZFile; /* * Name: lefGZipOpen * Description: Open a gzip file * Returns: A file pointer */ extern lefGZFile lefGZipOpen(const char* gzipFile, const char* mode); /* * Name: lefGZipClose * Description: Close a gzip file * Returns: 0 if no errors */ extern int lefGZipClose(lefGZFile filePtr); /* * Name: lefrReadGZip * Description: Parse a lef gzip file * Returns: 0 if no errors */ extern int lefrReadGZip(lefGZFile file, const char* gzipFile, void* uData); #endif ================================================ FILE: rsyn/src/rsyn/3rdparty/json/json.hpp ================================================ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ | | |__ | | | | | | version 2.0.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . Copyright (c) 2013-2016 Niels Lohmann . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef NLOHMANN_JSON_HPP #define NLOHMANN_JSON_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // exclude unsupported compilers #if defined(__clang__) #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) #if CLANG_VERSION < 30400 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if GCC_VERSION < 40900 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif // disable float-equal warnings on GCC/clang #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" #endif /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @since version 1.0.0 */ namespace nlohmann { /*! @brief unnamed namespace with internal helper functions @since version 1.0.0 */ namespace { /*! @brief Helper to determine whether there's a key_type for T. Thus helper is used to tell associative containers apart from other containers such as sequence containers. For instance, `std::map` passes the test as it contains a `mapped_type`, whereas `std::vector` fails the test. @sa http://stackoverflow.com/a/7728728/266378 @since version 1.0.0 */ template struct has_mapped_type { private: template static char test(typename C::mapped_type*); template static char (&test(...))[2]; public: static constexpr bool value = sizeof(test(0)) == 1; }; /*! @brief helper class to create locales with decimal point This struct is used a default locale during the JSON serialization. JSON requires the decimal point to be `.`, so this function overloads the `do_decimal_point()` function to return `.`. This function is called by float-to-string conversions to retrieve the decimal separator between integer and fractional parts. @sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315 @since version 2.0.0 */ struct DecimalSeparator : std::numpunct { char do_decimal_point() const { return '.'; } }; } /*! @brief a class to store JSON values @tparam ObjectType type for JSON objects (`std::map` by default; will be used in @ref object_t) @tparam ArrayType type for JSON arrays (`std::vector` by default; will be used in @ref array_t) @tparam StringType type for JSON strings and object keys (`std::string` by default; will be used in @ref string_t) @tparam BooleanType type for JSON booleans (`bool` by default; will be used in @ref boolean_t) @tparam NumberIntegerType type for JSON integer numbers (`int64_t` by default; will be used in @ref number_integer_t) @tparam NumberUnsignedType type for JSON unsigned integer numbers (@c `uint64_t` by default; will be used in @ref number_unsigned_t) @tparam NumberFloatType type for JSON floating-point numbers (`double` by default; will be used in @ref number_float_t) @tparam AllocatorType type of the allocator to use (`std::allocator` by default) @requirement The class satisfies the following concept requirements: - Basic - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): JSON values can be default constructed. The result will be a JSON null value. - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): A JSON value can be constructed from an rvalue argument. - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): A JSON value can be copy-constructed from an lvalue expression. - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): A JSON value van be assigned from an rvalue argument. - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): A JSON value can be copy-assigned from an lvalue expression. - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): JSON values can be destructed. - Layout - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): JSON values have [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): All non-static data members are private and standard layout types, the class has no virtual functions or (virtual) base classes. - Library-wide - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): JSON values can be compared with `==`, see @ref operator==(const_reference,const_reference). - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): JSON values can be compared with `<`, see @ref operator<(const_reference,const_reference). - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of other compatible types, using unqualified function call @ref swap(). - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): JSON values can be compared against `std::nullptr_t` objects which are used to model the `null` value. - Container - [Container](http://en.cppreference.com/w/cpp/concept/Container): JSON values can be used like STL containers and provide iterator access. - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); JSON values can be used like STL containers and provide reverse iterator access. @invariant The member variables @a m_value and @a m_type have the following relationship: - If `m_type == value_t::object`, then `m_value.object != nullptr`. - If `m_type == value_t::array`, then `m_value.array != nullptr`. - If `m_type == value_t::string`, then `m_value.string != nullptr`. The invariants are checked by member function assert_invariant(). @internal @note ObjectType trick from http://stackoverflow.com/a/9860911 @endinternal @see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://rfc7159.net/rfc7159) @since version 1.0.0 @nosubgrouping */ template < template class ObjectType = std::map, template class ArrayType = std::vector, class StringType = std::string, class BooleanType = bool, class NumberIntegerType = std::int64_t, class NumberUnsignedType = std::uint64_t, class NumberFloatType = double, template class AllocatorType = std::allocator > class basic_json { private: /// workaround type for MSVC using basic_json_t = basic_json; public: // forward declarations template class json_reverse_iterator; class json_pointer; ///////////////////// // container types // ///////////////////// /// @name container types /// The canonic container types to use @ref basic_json like any other STL /// container. /// @{ /// the type of elements in a basic_json container using value_type = basic_json; /// the type of an element reference using reference = value_type&; /// the type of an element const reference using const_reference = const value_type&; /// a type to represent differences between iterators using difference_type = std::ptrdiff_t; /// a type to represent container sizes using size_type = std::size_t; /// the allocator type using allocator_type = AllocatorType; /// the type of an element pointer using pointer = typename std::allocator_traits::pointer; /// the type of an element const pointer using const_pointer = typename std::allocator_traits::const_pointer; /// an iterator for a basic_json container class iterator; /// a const iterator for a basic_json container class const_iterator; /// a reverse iterator for a basic_json container using reverse_iterator = json_reverse_iterator; /// a const reverse iterator for a basic_json container using const_reverse_iterator = json_reverse_iterator; /// @} /*! @brief returns the allocator associated with the container */ static allocator_type get_allocator() { return allocator_type(); } /////////////////////////// // JSON value data types // /////////////////////////// /// @name JSON value data types /// The data types to store a JSON value. These types are derived from /// the template arguments passed to class @ref basic_json. /// @{ /*! @brief a type for an object [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: > An object is an unordered collection of zero or more name/value pairs, > where a name is a string and a value is a string, number, boolean, null, > object, or array. To store objects in C++, a type is defined by the template parameters described below. @tparam ObjectType the container to store objects (e.g., `std::map` or `std::unordered_map`) @tparam StringType the type of the keys or names (e.g., `std::string`). The comparison function `std::less` is used to order elements inside the container. @tparam AllocatorType the allocator to use for objects (e.g., `std::allocator`) #### Default type With the default values for @a ObjectType (`std::map`), @a StringType (`std::string`), and @a AllocatorType (`std::allocator`), the default value for @a object_t is: @code {.cpp} std::map< std::string, // key_type basic_json, // value_type std::less, // key_compare std::allocator> // allocator_type > @endcode #### Behavior The choice of @a object_t influences the behavior of the JSON class. With the default type, objects have the following behavior: - When all names are unique, objects will be interoperable in the sense that all software implementations receiving that object will agree on the name-value mappings. - When the names within an object are not unique, later stored name/value pairs overwrite previously stored name/value pairs, leaving the used names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will be treated as equal and both stored as `{"key": 1}`. - Internally, name/value pairs are stored in lexicographical order of the names. Objects will also be serialized (see @ref dump) in this order. For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored and serialized as `{"a": 2, "b": 1}`. - When comparing objects, the order of the name/value pairs is irrelevant. This makes objects interoperable in the sense that they will not be affected by these differences. For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be treated as equal. #### Limits [RFC 7159](http://rfc7159.net/rfc7159) specifies: > An implementation may set limits on the maximum depth of nesting. In this class, the object's limit of nesting is not constraint explicitly. However, a maximum depth of nesting may be introduced by the compiler or runtime environment. A theoretical limit can be queried by calling the @ref max_size function of a JSON object. #### Storage Objects are stored as pointers in a @ref basic_json type. That is, for any access to object values, a pointer of type `object_t*` must be dereferenced. @sa @ref array_t -- type for an array value @since version 1.0.0 @note The order name/value pairs are added to the object is *not* preserved by the library. Therefore, iterating an object may return name/value pairs in a different order than they were originally stored. In fact, keys will be traversed in alphabetical order as `std::map` with `std::less` is used by default. Please note this behavior conforms to [RFC 7159](http://rfc7159.net/rfc7159), because any order implements the specified "unordered" nature of JSON objects. */ using object_t = ObjectType, AllocatorType>>; /*! @brief a type for an array [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: > An array is an ordered sequence of zero or more values. To store objects in C++, a type is defined by the template parameters explained below. @tparam ArrayType container type to store arrays (e.g., `std::vector` or `std::list`) @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) #### Default type With the default values for @a ArrayType (`std::vector`) and @a AllocatorType (`std::allocator`), the default value for @a array_t is: @code {.cpp} std::vector< basic_json, // value_type std::allocator // allocator_type > @endcode #### Limits [RFC 7159](http://rfc7159.net/rfc7159) specifies: > An implementation may set limits on the maximum depth of nesting. In this class, the array's limit of nesting is not constraint explicitly. However, a maximum depth of nesting may be introduced by the compiler or runtime environment. A theoretical limit can be queried by calling the @ref max_size function of a JSON array. #### Storage Arrays are stored as pointers in a @ref basic_json type. That is, for any access to array values, a pointer of type `array_t*` must be dereferenced. @sa @ref object_t -- type for an object value @since version 1.0.0 */ using array_t = ArrayType>; /*! @brief a type for a string [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: > A string is a sequence of zero or more Unicode characters. To store objects in C++, a type is defined by the template parameter described below. Unicode values are split by the JSON class into byte-sized characters during deserialization. @tparam StringType the container to store strings (e.g., `std::string`). Note this container is used for keys/names in objects, see @ref object_t. #### Default type With the default values for @a StringType (`std::string`), the default value for @a string_t is: @code {.cpp} std::string @endcode #### String comparison [RFC 7159](http://rfc7159.net/rfc7159) states: > Software implementations are typically required to test names of object > members for equality. Implementations that transform the textual > representation into sequences of Unicode code units and then perform the > comparison numerically, code unit by code unit, are interoperable in the > sense that implementations will agree in all cases on equality or > inequality of two strings. For example, implementations that compare > strings with escaped characters unconverted may incorrectly find that > `"a\\b"` and `"a\u005Cb"` are not equal. This implementation is interoperable as it does compare strings code unit by code unit. #### Storage String values are stored as pointers in a @ref basic_json type. That is, for any access to string values, a pointer of type `string_t*` must be dereferenced. @since version 1.0.0 */ using string_t = StringType; /*! @brief a type for a boolean [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a type which differentiates the two literals `true` and `false`. To store objects in C++, a type is defined by the template parameter @a BooleanType which chooses the type to use. #### Default type With the default values for @a BooleanType (`bool`), the default value for @a boolean_t is: @code {.cpp} bool @endcode #### Storage Boolean values are stored directly inside a @ref basic_json type. @since version 1.0.0 */ using boolean_t = BooleanType; /*! @brief a type for a number (integer) [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: > The representation of numbers is similar to that used in most > programming languages. A number is represented in base 10 using decimal > digits. It contains an integer component that may be prefixed with an > optional minus sign, which may be followed by a fraction part and/or an > exponent part. Leading zeros are not allowed. (...) Numeric values that > cannot be represented in the grammar below (such as Infinity and NaN) > are not permitted. This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is known whether the number is a signed integer, an unsigned integer or a floating-point number. Therefore, three different types, @ref number_integer_t, @ref number_unsigned_t and @ref number_float_t are used. To store integer numbers in C++, a type is defined by the template parameter @a NumberIntegerType which chooses the type to use. #### Default type With the default values for @a NumberIntegerType (`int64_t`), the default value for @a number_integer_t is: @code {.cpp} int64_t @endcode #### Default behavior - The restrictions about leading zeros is not enforced in C++. Instead, leading zeros in integer literals lead to an interpretation as octal number. Internally, the value will be stored as decimal number. For instance, the C++ integer literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `null`. #### Limits [RFC 7159](http://rfc7159.net/rfc7159) specifies: > An implementation may set limits on the range and precision of numbers. When the default type is used, the maximal integer number that can be stored is `9223372036854775807` (INT64_MAX) and the minimal integer number that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers will be automatically be stored as @ref number_unsigned_t or @ref number_float_t. [RFC 7159](http://rfc7159.net/rfc7159) further states: > Note that when such software is used, numbers that are integers and are > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense > that implementations will agree exactly on their numeric values. As this range is a subrange of the exactly supported range [INT64_MIN, INT64_MAX], this class's integer type is interoperable. #### Storage Integer number values are stored directly inside a @ref basic_json type. @sa @ref number_float_t -- type for number values (floating-point) @sa @ref number_unsigned_t -- type for number values (unsigned integer) @since version 1.0.0 */ using number_integer_t = NumberIntegerType; /*! @brief a type for a number (unsigned) [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: > The representation of numbers is similar to that used in most > programming languages. A number is represented in base 10 using decimal > digits. It contains an integer component that may be prefixed with an > optional minus sign, which may be followed by a fraction part and/or an > exponent part. Leading zeros are not allowed. (...) Numeric values that > cannot be represented in the grammar below (such as Infinity and NaN) > are not permitted. This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is known whether the number is a signed integer, an unsigned integer or a floating-point number. Therefore, three different types, @ref number_integer_t, @ref number_unsigned_t and @ref number_float_t are used. To store unsigned integer numbers in C++, a type is defined by the template parameter @a NumberUnsignedType which chooses the type to use. #### Default type With the default values for @a NumberUnsignedType (`uint64_t`), the default value for @a number_unsigned_t is: @code {.cpp} uint64_t @endcode #### Default behavior - The restrictions about leading zeros is not enforced in C++. Instead, leading zeros in integer literals lead to an interpretation as octal number. Internally, the value will be stored as decimal number. For instance, the C++ integer literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `null`. #### Limits [RFC 7159](http://rfc7159.net/rfc7159) specifies: > An implementation may set limits on the range and precision of numbers. When the default type is used, the maximal integer number that can be stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number that can be stored is `0`. Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers will be automatically be stored as @ref number_integer_t or @ref number_float_t. [RFC 7159](http://rfc7159.net/rfc7159) further states: > Note that when such software is used, numbers that are integers and are > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense > that implementations will agree exactly on their numeric values. As this range is a subrange (when considered in conjunction with the number_integer_t type) of the exactly supported range [0, UINT64_MAX], this class's integer type is interoperable. #### Storage Integer number values are stored directly inside a @ref basic_json type. @sa @ref number_float_t -- type for number values (floating-point) @sa @ref number_integer_t -- type for number values (integer) @since version 2.0.0 */ using number_unsigned_t = NumberUnsignedType; /*! @brief a type for a number (floating-point) [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: > The representation of numbers is similar to that used in most > programming languages. A number is represented in base 10 using decimal > digits. It contains an integer component that may be prefixed with an > optional minus sign, which may be followed by a fraction part and/or an > exponent part. Leading zeros are not allowed. (...) Numeric values that > cannot be represented in the grammar below (such as Infinity and NaN) > are not permitted. This description includes both integer and floating-point numbers. However, C++ allows more precise storage if it is known whether the number is a signed integer, an unsigned integer or a floating-point number. Therefore, three different types, @ref number_integer_t, @ref number_unsigned_t and @ref number_float_t are used. To store floating-point numbers in C++, a type is defined by the template parameter @a NumberFloatType which chooses the type to use. #### Default type With the default values for @a NumberFloatType (`double`), the default value for @a number_float_t is: @code {.cpp} double @endcode #### Default behavior - The restrictions about leading zeros is not enforced in C++. Instead, leading zeros in floating-point literals will be ignored. Internally, the value will be stored as decimal number. For instance, the C++ floating-point literal `01.2` will be serialized to `1.2`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `null`. #### Limits [RFC 7159](http://rfc7159.net/rfc7159) states: > This specification allows implementations to set limits on the range and > precision of numbers accepted. Since software that implements IEEE > 754-2008 binary64 (double precision) numbers is generally available and > widely used, good interoperability can be achieved by implementations > that expect no more precision or range than these provide, in the sense > that implementations will approximate JSON numbers within the expected > precision. This implementation does exactly follow this approach, as it uses double precision floating-point numbers. Note values smaller than `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` will be stored as NaN internally and be serialized to `null`. #### Storage Floating-point number values are stored directly inside a @ref basic_json type. @sa @ref number_integer_t -- type for number values (integer) @sa @ref number_unsigned_t -- type for number values (unsigned integer) @since version 1.0.0 */ using number_float_t = NumberFloatType; /// @} /////////////////////////// // JSON type enumeration // /////////////////////////// /*! @brief the JSON type enumeration This enumeration collects the different JSON types. It is internally used to distinguish the stored values, and the functions @ref is_null(), @ref is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref is_number() (with @ref is_number_integer(), @ref is_number_unsigned(), and @ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and @ref is_structured() rely on it. @note There are three enumeration entries (number_integer, number_unsigned, and number_float), because the library distinguishes these three types for numbers: @ref number_unsigned_t is used for unsigned integers, @ref number_integer_t is used for signed integers, and @ref number_float_t is used for floating-point numbers or to approximate integers which do not fit in the limits of their respective type. @sa @ref basic_json(const value_t value_type) -- create a JSON value with the default value for a given type @since version 1.0.0 */ enum class value_t : uint8_t { null, ///< null value object, ///< object (unordered set of name/value pairs) array, ///< array (ordered collection of values) string, ///< string value boolean, ///< boolean value number_integer, ///< number value (signed integer) number_unsigned, ///< number value (unsigned integer) number_float, ///< number value (floating-point) discarded ///< discarded by the the parser callback function }; private: /// helper for exception-safe object creation template static T* create(Args&& ... args) { AllocatorType alloc; auto deleter = [&](T * object) { alloc.deallocate(object, 1); }; std::unique_ptr object(alloc.allocate(1), deleter); alloc.construct(object.get(), std::forward(args)...); assert(object.get() != nullptr); return object.release(); } //////////////////////// // JSON value storage // //////////////////////// /*! @brief a JSON value The actual storage for a JSON value of the @ref basic_json class. This union combines the different storage types for the JSON value types defined in @ref value_t. JSON type | value_t type | used type --------- | --------------- | ------------------------ object | object | pointer to @ref object_t array | array | pointer to @ref array_t string | string | pointer to @ref string_t boolean | boolean | @ref boolean_t number | number_integer | @ref number_integer_t number | number_unsigned | @ref number_unsigned_t number | number_float | @ref number_float_t null | null | *no value is stored* @note Variable-length types (objects, arrays, and strings) are stored as pointers. The size of the union should not exceed 64 bits if the default value types are used. @since version 1.0.0 */ union json_value { /// object (stored with pointer to save storage) object_t* object; /// array (stored with pointer to save storage) array_t* array; /// string (stored with pointer to save storage) string_t* string; /// boolean boolean_t boolean; /// number (integer) number_integer_t number_integer; /// number (unsigned integer) number_unsigned_t number_unsigned; /// number (floating-point) number_float_t number_float; /// default constructor (for null values) json_value() = default; /// constructor for booleans json_value(boolean_t v) noexcept : boolean(v) {} /// constructor for numbers (integer) json_value(number_integer_t v) noexcept : number_integer(v) {} /// constructor for numbers (unsigned) json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} /// constructor for numbers (floating-point) json_value(number_float_t v) noexcept : number_float(v) {} /// constructor for empty values of a given type json_value(value_t t) { switch (t) { case value_t::object: { object = create(); break; } case value_t::array: { array = create(); break; } case value_t::string: { string = create(""); break; } case value_t::boolean: { boolean = boolean_t(false); break; } case value_t::number_integer: { number_integer = number_integer_t(0); break; } case value_t::number_unsigned: { number_unsigned = number_unsigned_t(0); break; } case value_t::number_float: { number_float = number_float_t(0.0); break; } default: { break; } } } /// constructor for strings json_value(const string_t& value) { string = create(value); } /// constructor for objects json_value(const object_t& value) { object = create(value); } /// constructor for arrays json_value(const array_t& value) { array = create(value); } }; /*! @brief checks the class invariants This function asserts the class invariants. It needs to be called at the end of every constructor to make sure that created objects respect the invariant. Furthermore, it has to be called each time the type of a JSON value is changed, because the invariant expresses a relationship between @a m_type and @a m_value. */ void assert_invariant() const { assert(m_type != value_t::object or m_value.object != nullptr); assert(m_type != value_t::array or m_value.array != nullptr); assert(m_type != value_t::string or m_value.string != nullptr); } public: ////////////////////////// // JSON parser callback // ////////////////////////// /*! @brief JSON callback events This enumeration lists the parser events that can trigger calling a callback function of type @ref parser_callback_t during parsing. @image html callback_events.png "Example when certain parse events are triggered" @since version 1.0.0 */ enum class parse_event_t : uint8_t { /// the parser read `{` and started to process a JSON object object_start, /// the parser read `}` and finished processing a JSON object object_end, /// the parser read `[` and started to process a JSON array array_start, /// the parser read `]` and finished processing a JSON array array_end, /// the parser read a key of a value in an object key, /// the parser finished reading a JSON value value }; /*! @brief per-element parser callback type With a parser callback function, the result of parsing a JSON text can be influenced. When passed to @ref parse(std::istream&, const parser_callback_t) or @ref parse(const string_t&, const parser_callback_t), it is called on certain events (passed as @ref parse_event_t via parameter @a event) with a set recursion depth @a depth and context JSON value @a parsed. The return value of the callback function is a boolean indicating whether the element that emitted the callback shall be kept or not. We distinguish six scenarios (determined by the event type) in which the callback function can be called. The following table describes the values of the parameters @a depth, @a event, and @a parsed. parameter @a event | description | parameter @a depth | parameter @a parsed ------------------ | ----------- | ------------------ | ------------------- parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value @image html callback_events.png "Example when certain parse events are triggered" Discarding a value (i.e., returning `false`) has different effects depending on the context in which function was called: - Discarded values in structured types are skipped. That is, the parser will behave as if the discarded value was never read. - In case a value outside a structured type is skipped, it is replaced with `null`. This case happens if the top-level element is skipped. @param[in] depth the depth of the recursion during parsing @param[in] event an event of type parse_event_t indicating the context in the callback function has been called @param[in,out] parsed the current intermediate parse result; note that writing to this value has no effect for parse_event_t::key events @return Whether the JSON value which called the function during parsing should be kept (`true`) or not (`false`). In the latter case, it is either skipped completely or replaced by an empty discarded object. @sa @ref parse(std::istream&, parser_callback_t) or @ref parse(const string_t&, parser_callback_t) for examples @since version 1.0.0 */ using parser_callback_t = std::function; ////////////////// // constructors // ////////////////// /// @name constructors and destructors /// Constructors of class @ref basic_json, copy/move constructor, copy /// assignment, static functions creating objects, and the destructor. /// @{ /*! @brief create an empty value with a given type Create an empty JSON value with a given type. The value will be default initialized with an empty value which depends on the type: Value type | initial value ----------- | ------------- null | `null` boolean | `false` string | `""` number | `0` object | `{}` array | `[]` @param[in] value_type the type of the value to create @complexity Constant. @throw std::bad_alloc if allocation for object, array, or string value fails @liveexample{The following code shows the constructor for different @ref value_t values,basic_json__value_t} @sa @ref basic_json(std::nullptr_t) -- create a `null` value @sa @ref basic_json(boolean_t value) -- create a boolean value @sa @ref basic_json(const string_t&) -- create a string value @sa @ref basic_json(const object_t&) -- create a object value @sa @ref basic_json(const array_t&) -- create a array value @sa @ref basic_json(const number_float_t) -- create a number (floating-point) value @sa @ref basic_json(const number_integer_t) -- create a number (integer) value @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned) value @since version 1.0.0 */ basic_json(const value_t value_type) : m_type(value_type), m_value(value_type) { assert_invariant(); } /*! @brief create a null object (implicitly) Create a `null` JSON value. This is the implicit version of the `null` value constructor as it takes no parameters. @note The class invariant is satisfied, because it poses no requirements for null values. @complexity Constant. @exceptionsafety No-throw guarantee: this constructor never throws exceptions. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is constant. - As postcondition, it holds: `basic_json().empty() == true`. @liveexample{The following code shows the constructor for a `null` JSON value.,basic_json} @sa @ref basic_json(std::nullptr_t) -- create a `null` value @since version 1.0.0 */ basic_json() = default; /*! @brief create a null object (explicitly) Create a `null` JSON value. This is the explicitly version of the `null` value constructor as it takes a null pointer as parameter. It allows to create `null` values by explicitly assigning a `nullptr` to a JSON value. The passed null pointer itself is not read -- it is only used to choose the right constructor. @complexity Constant. @exceptionsafety No-throw guarantee: this constructor never throws exceptions. @liveexample{The following code shows the constructor with null pointer parameter.,basic_json__nullptr_t} @sa @ref basic_json() -- default constructor (implicitly creating a `null` value) @since version 1.0.0 */ basic_json(std::nullptr_t) noexcept : basic_json(value_t::null) { assert_invariant(); } /*! @brief create an object (explicit) Create an object JSON value with a given content. @param[in] val a value for the object @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for object value fails @liveexample{The following code shows the constructor with an @ref object_t parameter.,basic_json__object_t} @sa @ref basic_json(const CompatibleObjectType&) -- create an object value from a compatible STL container @since version 1.0.0 */ basic_json(const object_t& val) : m_type(value_t::object), m_value(val) { assert_invariant(); } /*! @brief create an object (implicit) Create an object JSON value with a given content. This constructor allows any type @a CompatibleObjectType that can be used to construct values of type @ref object_t. @tparam CompatibleObjectType An object type whose `key_type` and `value_type` is compatible to @ref object_t. Examples include `std::map`, `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with a `key_type` of `std::string`, and a `value_type` from which a @ref basic_json value can be constructed. @param[in] val a value for the object @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for object value fails @liveexample{The following code shows the constructor with several compatible object type parameters.,basic_json__CompatibleObjectType} @sa @ref basic_json(const object_t&) -- create an object value @since version 1.0.0 */ template ::value and std::is_constructible::value, int>::type = 0> basic_json(const CompatibleObjectType& val) : m_type(value_t::object) { using std::begin; using std::end; m_value.object = create(begin(val), end(val)); assert_invariant(); } /*! @brief create an array (explicit) Create an array JSON value with a given content. @param[in] val a value for the array @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for array value fails @liveexample{The following code shows the constructor with an @ref array_t parameter.,basic_json__array_t} @sa @ref basic_json(const CompatibleArrayType&) -- create an array value from a compatible STL containers @since version 1.0.0 */ basic_json(const array_t& val) : m_type(value_t::array), m_value(val) { assert_invariant(); } /*! @brief create an array (implicit) Create an array JSON value with a given content. This constructor allows any type @a CompatibleArrayType that can be used to construct values of type @ref array_t. @tparam CompatibleArrayType An object type whose `value_type` is compatible to @ref array_t. Examples include `std::vector`, `std::deque`, `std::list`, `std::forward_list`, `std::array`, `std::set`, `std::unordered_set`, `std::multiset`, and `unordered_multiset` with a `value_type` from which a @ref basic_json value can be constructed. @param[in] val a value for the array @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for array value fails @liveexample{The following code shows the constructor with several compatible array type parameters.,basic_json__CompatibleArrayType} @sa @ref basic_json(const array_t&) -- create an array value @since version 1.0.0 */ template ::value and not std::is_same::value and not std::is_same::value and not std::is_same::value and not std::is_same::value and not std::is_same::value and std::is_constructible::value, int>::type = 0> basic_json(const CompatibleArrayType& val) : m_type(value_t::array) { using std::begin; using std::end; m_value.array = create(begin(val), end(val)); assert_invariant(); } /*! @brief create a string (explicit) Create an string JSON value with a given content. @param[in] val a value for the string @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for string value fails @liveexample{The following code shows the constructor with an @ref string_t parameter.,basic_json__string_t} @sa @ref basic_json(const typename string_t::value_type*) -- create a string value from a character pointer @sa @ref basic_json(const CompatibleStringType&) -- create a string value from a compatible string container @since version 1.0.0 */ basic_json(const string_t& val) : m_type(value_t::string), m_value(val) { assert_invariant(); } /*! @brief create a string (explicit) Create a string JSON value with a given content. @param[in] val a literal value for the string @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for string value fails @liveexample{The following code shows the constructor with string literal parameter.,basic_json__string_t_value_type} @sa @ref basic_json(const string_t&) -- create a string value @sa @ref basic_json(const CompatibleStringType&) -- create a string value from a compatible string container @since version 1.0.0 */ basic_json(const typename string_t::value_type* val) : basic_json(string_t(val)) { assert_invariant(); } /*! @brief create a string (implicit) Create a string JSON value with a given content. @param[in] val a value for the string @tparam CompatibleStringType an string type which is compatible to @ref string_t, for instance `std::string`. @complexity Linear in the size of the passed @a val. @throw std::bad_alloc if allocation for string value fails @liveexample{The following code shows the construction of a string value from a compatible type.,basic_json__CompatibleStringType} @sa @ref basic_json(const string_t&) -- create a string value @sa @ref basic_json(const typename string_t::value_type*) -- create a string value from a character pointer @since version 1.0.0 */ template ::value, int>::type = 0> basic_json(const CompatibleStringType& val) : basic_json(string_t(val)) { assert_invariant(); } /*! @brief create a boolean (explicit) Creates a JSON boolean type from a given value. @param[in] val a boolean value to store @complexity Constant. @liveexample{The example below demonstrates boolean values.,basic_json__boolean_t} @since version 1.0.0 */ basic_json(boolean_t val) noexcept : m_type(value_t::boolean), m_value(val) { assert_invariant(); } /*! @brief create an integer number (explicit) Create an integer number JSON value with a given content. @tparam T A helper type to remove this function via SFINAE in case @ref number_integer_t is the same as `int`. In this case, this constructor would have the same signature as @ref basic_json(const int value). Note the helper type @a T is not visible in this constructor's interface. @param[in] val an integer to create a JSON number from @complexity Constant. @liveexample{The example below shows the construction of an integer number value.,basic_json__number_integer_t} @sa @ref basic_json(const int) -- create a number value (integer) @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number value (integer) from a compatible number type @since version 1.0.0 */ template::value) and std::is_same::value , int>::type = 0> basic_json(const number_integer_t val) noexcept : m_type(value_t::number_integer), m_value(val) { assert_invariant(); } /*! @brief create an integer number from an enum type (explicit) Create an integer number JSON value with a given content. @param[in] val an integer to create a JSON number from @note This constructor allows to pass enums directly to a constructor. As C++ has no way of specifying the type of an anonymous enum explicitly, we can only rely on the fact that such values implicitly convert to int. As int may already be the same type of number_integer_t, we may need to switch off the constructor @ref basic_json(const number_integer_t). @complexity Constant. @liveexample{The example below shows the construction of an integer number value from an anonymous enum.,basic_json__const_int} @sa @ref basic_json(const number_integer_t) -- create a number value (integer) @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number value (integer) from a compatible number type @since version 1.0.0 */ basic_json(const int val) noexcept : m_type(value_t::number_integer), m_value(static_cast(val)) { assert_invariant(); } /*! @brief create an integer number (implicit) Create an integer number JSON value with a given content. This constructor allows any type @a CompatibleNumberIntegerType that can be used to construct values of type @ref number_integer_t. @tparam CompatibleNumberIntegerType An integer type which is compatible to @ref number_integer_t. Examples include the types `int`, `int32_t`, `long`, and `short`. @param[in] val an integer to create a JSON number from @complexity Constant. @liveexample{The example below shows the construction of several integer number values from compatible types.,basic_json__CompatibleIntegerNumberType} @sa @ref basic_json(const number_integer_t) -- create a number value (integer) @sa @ref basic_json(const int) -- create a number value (integer) @since version 1.0.0 */ template::value and std::numeric_limits::is_integer and std::numeric_limits::is_signed, CompatibleNumberIntegerType>::type = 0> basic_json(const CompatibleNumberIntegerType val) noexcept : m_type(value_t::number_integer), m_value(static_cast(val)) { assert_invariant(); } /*! @brief create an unsigned integer number (explicit) Create an unsigned integer number JSON value with a given content. @tparam T helper type to compare number_unsigned_t and unsigned int (not visible in) the interface. @param[in] val an integer to create a JSON number from @complexity Constant. @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number value (unsigned integer) from a compatible number type @since version 2.0.0 */ template::value) and std::is_same::value , int>::type = 0> basic_json(const number_unsigned_t val) noexcept : m_type(value_t::number_unsigned), m_value(val) { assert_invariant(); } /*! @brief create an unsigned number (implicit) Create an unsigned number JSON value with a given content. This constructor allows any type @a CompatibleNumberUnsignedType that can be used to construct values of type @ref number_unsigned_t. @tparam CompatibleNumberUnsignedType An integer type which is compatible to @ref number_unsigned_t. Examples may include the types `unsigned int`, `uint32_t`, or `unsigned short`. @param[in] val an unsigned integer to create a JSON number from @complexity Constant. @sa @ref basic_json(const number_unsigned_t) -- create a number value (unsigned) @since version 2.0.0 */ template ::value and std::numeric_limits::is_integer and not std::numeric_limits::is_signed, CompatibleNumberUnsignedType>::type = 0> basic_json(const CompatibleNumberUnsignedType val) noexcept : m_type(value_t::number_unsigned), m_value(static_cast(val)) { assert_invariant(); } /*! @brief create a floating-point number (explicit) Create a floating-point number JSON value with a given content. @param[in] val a floating-point value to create a JSON number from @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 disallows NaN values: > Numeric values that cannot be represented in the grammar below (such as > Infinity and NaN) are not permitted. In case the parameter @a val is not a number, a JSON null value is created instead. @complexity Constant. @liveexample{The following example creates several floating-point values.,basic_json__number_float_t} @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number value (floating-point) from a compatible number type @since version 1.0.0 */ basic_json(const number_float_t val) noexcept : m_type(value_t::number_float), m_value(val) { // replace infinity and NAN by null if (not std::isfinite(val)) { m_type = value_t::null; m_value = json_value(); } assert_invariant(); } /*! @brief create an floating-point number (implicit) Create an floating-point number JSON value with a given content. This constructor allows any type @a CompatibleNumberFloatType that can be used to construct values of type @ref number_float_t. @tparam CompatibleNumberFloatType A floating-point type which is compatible to @ref number_float_t. Examples may include the types `float` or `double`. @param[in] val a floating-point to create a JSON number from @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 disallows NaN values: > Numeric values that cannot be represented in the grammar below (such as > Infinity and NaN) are not permitted. In case the parameter @a val is not a number, a JSON null value is created instead. @complexity Constant. @liveexample{The example below shows the construction of several floating-point number values from compatible types.,basic_json__CompatibleNumberFloatType} @sa @ref basic_json(const number_float_t) -- create a number value (floating-point) @since version 1.0.0 */ template::value and std::is_floating_point::value>::type > basic_json(const CompatibleNumberFloatType val) noexcept : basic_json(number_float_t(val)) { assert_invariant(); } /*! @brief create a container (array or object) from an initializer list Creates a JSON value of type array or object from the passed initializer list @a init. In case @a type_deduction is `true` (default), the type of the JSON value to be created is deducted from the initializer list @a init according to the following rules: 1. If the list is empty, an empty JSON object value `{}` is created. 2. If the list consists of pairs whose first element is a string, a JSON object value is created where the first elements of the pairs are treated as keys and the second elements are as values. 3. In all other cases, an array is created. The rules aim to create the best fit between a C++ initializer list and JSON values. The rationale is as follows: 1. The empty initializer list is written as `{}` which is exactly an empty JSON object. 2. C++ has now way of describing mapped types other than to list a list of pairs. As JSON requires that keys must be of type string, rule 2 is the weakest constraint one can pose on initializer lists to interpret them as an object. 3. In all other cases, the initializer list could not be interpreted as JSON object type, so interpreting it as JSON array type is safe. With the rules described above, the following JSON values cannot be expressed by an initializer list: - the empty array (`[]`): use @ref array(std::initializer_list) with an empty initializer list in this case - arrays whose elements satisfy rule 2: use @ref array(std::initializer_list) with the same initializer list in this case @note When used without parentheses around an empty initializer list, @ref basic_json() is called instead of this function, yielding the JSON null value. @param[in] init initializer list with JSON values @param[in] type_deduction internal parameter; when set to `true`, the type of the JSON value is deducted from the initializer list @a init; when set to `false`, the type provided via @a manual_type is forced. This mode is used by the functions @ref array(std::initializer_list) and @ref object(std::initializer_list). @param[in] manual_type internal parameter; when @a type_deduction is set to `false`, the created JSON value will use the provided type (only @ref value_t::array and @ref value_t::object are valid); when @a type_deduction is set to `true`, this parameter has no effect @throw std::domain_error if @a type_deduction is `false`, @a manual_type is `value_t::object`, but @a init contains an element which is not a pair whose first element is a string; example: `"cannot create object from initializer list"` @complexity Linear in the size of the initializer list @a init. @liveexample{The example below shows how JSON values are created from initializer lists.,basic_json__list_init_t} @sa @ref array(std::initializer_list) -- create a JSON array value from an initializer list @sa @ref object(std::initializer_list) -- create a JSON object value from an initializer list @since version 1.0.0 */ basic_json(std::initializer_list init, bool type_deduction = true, value_t manual_type = value_t::array) { // check if each element is an array with two elements whose first // element is a string bool is_an_object = std::all_of(init.begin(), init.end(), [](const basic_json & element) { return element.is_array() and element.size() == 2 and element[0].is_string(); }); // adjust type if type deduction is not wanted if (not type_deduction) { // if array is wanted, do not create an object though possible if (manual_type == value_t::array) { is_an_object = false; } // if object is wanted but impossible, throw an exception if (manual_type == value_t::object and not is_an_object) { throw std::domain_error("cannot create object from initializer list"); } } if (is_an_object) { // the initializer list is a list of pairs -> create object m_type = value_t::object; m_value = value_t::object; std::for_each(init.begin(), init.end(), [this](const basic_json & element) { m_value.object->emplace(*(element[0].m_value.string), element[1]); }); } else { // the initializer list describes an array -> create array m_type = value_t::array; m_value.array = create(init); } assert_invariant(); } /*! @brief explicitly create an array from an initializer list Creates a JSON array value from a given initializer list. That is, given a list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the initializer list is empty, the empty array `[]` is created. @note This function is only needed to express two edge cases that cannot be realized with the initializer list constructor (@ref basic_json(std::initializer_list, bool, value_t)). These cases are: 1. creating an array whose elements are all pairs whose first element is a string -- in this case, the initializer list constructor would create an object, taking the first elements as keys 2. creating an empty array -- passing the empty initializer list to the initializer list constructor yields an empty object @param[in] init initializer list with JSON values to create an array from (optional) @return JSON array value @complexity Linear in the size of @a init. @liveexample{The following code shows an example for the `array` function.,array} @sa @ref basic_json(std::initializer_list, bool, value_t) -- create a JSON value from an initializer list @sa @ref object(std::initializer_list) -- create a JSON object value from an initializer list @since version 1.0.0 */ static basic_json array(std::initializer_list init = std::initializer_list()) { return basic_json(init, false, value_t::array); } /*! @brief explicitly create an object from an initializer list Creates a JSON object value from a given initializer list. The initializer lists elements must be pairs, and their first elements must be strings. If the initializer list is empty, the empty object `{}` is created. @note This function is only added for symmetry reasons. In contrast to the related function @ref array(std::initializer_list), there are no cases which can only be expressed by this function. That is, any initializer list @a init can also be passed to the initializer list constructor @ref basic_json(std::initializer_list, bool, value_t). @param[in] init initializer list to create an object from (optional) @return JSON object value @throw std::domain_error if @a init is not a pair whose first elements are strings; thrown by @ref basic_json(std::initializer_list, bool, value_t) @complexity Linear in the size of @a init. @liveexample{The following code shows an example for the `object` function.,object} @sa @ref basic_json(std::initializer_list, bool, value_t) -- create a JSON value from an initializer list @sa @ref array(std::initializer_list) -- create a JSON array value from an initializer list @since version 1.0.0 */ static basic_json object(std::initializer_list init = std::initializer_list()) { return basic_json(init, false, value_t::object); } /*! @brief construct an array with count copies of given value Constructs a JSON array value by creating @a cnt copies of a passed value. In case @a cnt is `0`, an empty array is created. As postcondition, `std::distance(begin(),end()) == cnt` holds. @param[in] cnt the number of JSON copies of @a val to create @param[in] val the JSON value to copy @complexity Linear in @a cnt. @liveexample{The following code shows examples for the @ref basic_json(size_type\, const basic_json&) constructor.,basic_json__size_type_basic_json} @since version 1.0.0 */ basic_json(size_type cnt, const basic_json& val) : m_type(value_t::array) { m_value.array = create(cnt, val); assert_invariant(); } /*! @brief construct a JSON container given an iterator range Constructs the JSON value with the contents of the range `[first, last)`. The semantics depends on the different types a JSON value can have: - In case of primitive types (number, boolean, or string), @a first must be `begin()` and @a last must be `end()`. In this case, the value is copied. Otherwise, std::out_of_range is thrown. - In case of structured types (array, object), the constructor behaves as similar versions for `std::vector`. - In case of a null type, std::domain_error is thrown. @tparam InputIT an input iterator type (@ref iterator or @ref const_iterator) @param[in] first begin of the range to copy from (included) @param[in] last end of the range to copy from (excluded) @pre Iterators @a first and @a last must be initialized. **This precondition is enforced with an assertion.** @throw std::domain_error if iterators are not compatible; that is, do not belong to the same JSON value; example: `"iterators are not compatible"` @throw std::out_of_range if iterators are for a primitive type (number, boolean, or string) where an out of range error can be detected easily; example: `"iterators out of range"` @throw std::bad_alloc if allocation for object, array, or string fails @throw std::domain_error if called with a null value; example: `"cannot use construct with iterators from null"` @complexity Linear in distance between @a first and @a last. @liveexample{The example below shows several ways to create JSON values by specifying a subrange with iterators.,basic_json__InputIt_InputIt} @since version 1.0.0 */ template ::value or std::is_same::value , int>::type = 0> basic_json(InputIT first, InputIT last) { assert(first.m_object != nullptr); assert(last.m_object != nullptr); // make sure iterator fits the current value if (first.m_object != last.m_object) { throw std::domain_error("iterators are not compatible"); } // copy type from first iterator m_type = first.m_object->m_type; // check if iterator range is complete for primitive values switch (m_type) { case value_t::boolean: case value_t::number_float: case value_t::number_integer: case value_t::number_unsigned: case value_t::string: { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) { throw std::out_of_range("iterators out of range"); } break; } default: { break; } } switch (m_type) { case value_t::number_integer: { m_value.number_integer = first.m_object->m_value.number_integer; break; } case value_t::number_unsigned: { m_value.number_unsigned = first.m_object->m_value.number_unsigned; break; } case value_t::number_float: { m_value.number_float = first.m_object->m_value.number_float; break; } case value_t::boolean: { m_value.boolean = first.m_object->m_value.boolean; break; } case value_t::string: { m_value = *first.m_object->m_value.string; break; } case value_t::object: { m_value.object = create(first.m_it.object_iterator, last.m_it.object_iterator); break; } case value_t::array: { m_value.array = create(first.m_it.array_iterator, last.m_it.array_iterator); break; } default: { throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); } } assert_invariant(); } /*! @brief construct a JSON value given an input stream @param[in,out] i stream to read a serialized JSON value from @param[in] cb a parser callback function of type @ref parser_callback_t which is used to control the deserialization by filtering unwanted values (optional) @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @note A UTF-8 byte order mark is silently ignored. @liveexample{The example below demonstrates constructing a JSON value from a `std::stringstream` with and without callback function.,basic_json__istream} @since version 2.0.0 */ explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr) { *this = parser(i, cb).parse(); assert_invariant(); } /////////////////////////////////////// // other constructors and destructor // /////////////////////////////////////// /*! @brief copy constructor Creates a copy of a given JSON value. @param[in] other the JSON value to copy @complexity Linear in the size of @a other. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is linear. - As postcondition, it holds: `other == basic_json(other)`. @throw std::bad_alloc if allocation for object, array, or string fails. @liveexample{The following code shows an example for the copy constructor.,basic_json__basic_json} @since version 1.0.0 */ basic_json(const basic_json& other) : m_type(other.m_type) { // check of passed value is valid other.assert_invariant(); switch (m_type) { case value_t::object: { m_value = *other.m_value.object; break; } case value_t::array: { m_value = *other.m_value.array; break; } case value_t::string: { m_value = *other.m_value.string; break; } case value_t::boolean: { m_value = other.m_value.boolean; break; } case value_t::number_integer: { m_value = other.m_value.number_integer; break; } case value_t::number_unsigned: { m_value = other.m_value.number_unsigned; break; } case value_t::number_float: { m_value = other.m_value.number_float; break; } default: { break; } } assert_invariant(); } /*! @brief move constructor Move constructor. Constructs a JSON value with the contents of the given value @a other using move semantics. It "steals" the resources from @a other and leaves it as JSON null value. @param[in,out] other value to move to this object @post @a other is a JSON null value @complexity Constant. @liveexample{The code below shows the move constructor explicitly called via std::move.,basic_json__moveconstructor} @since version 1.0.0 */ basic_json(basic_json&& other) noexcept : m_type(std::move(other.m_type)), m_value(std::move(other.m_value)) { // check that passed value is valid other.assert_invariant(); // invalidate payload other.m_type = value_t::null; other.m_value = {}; assert_invariant(); } /*! @brief copy assignment Copy assignment operator. Copies a JSON value via the "copy and swap" strategy: It is expressed in terms of the copy constructor, destructor, and the swap() member function. @param[in] other value to copy from @complexity Linear. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is linear. @liveexample{The code below shows and example for the copy assignment. It creates a copy of value `a` which is then swapped with `b`. Finally\, the copy of `a` (which is the null value after the swap) is destroyed.,basic_json__copyassignment} @since version 1.0.0 */ reference& operator=(basic_json other) noexcept ( std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value ) { // check that passed value is valid other.assert_invariant(); using std::swap; swap(m_type, other.m_type); swap(m_value, other.m_value); assert_invariant(); return *this; } /*! @brief destructor Destroys the JSON value and frees all allocated memory. @complexity Linear. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is linear. - All stored elements are destroyed and all memory is freed. @since version 1.0.0 */ ~basic_json() { assert_invariant(); switch (m_type) { case value_t::object: { AllocatorType alloc; alloc.destroy(m_value.object); alloc.deallocate(m_value.object, 1); break; } case value_t::array: { AllocatorType alloc; alloc.destroy(m_value.array); alloc.deallocate(m_value.array, 1); break; } case value_t::string: { AllocatorType alloc; alloc.destroy(m_value.string); alloc.deallocate(m_value.string, 1); break; } default: { // all other types need no specific destructor break; } } } /// @} public: /////////////////////// // object inspection // /////////////////////// /// @name object inspection /// Functions to inspect the type of a JSON value. /// @{ /*! @brief serialization Serialization function for JSON values. The function tries to mimic Python's `json.dumps()` function, and currently supports its @a indent parameter. @param[in] indent If indent is nonnegative, then array elements and object members will be pretty-printed with that indent level. An indent level of `0` will only insert newlines. `-1` (the default) selects the most compact representation. @return string containing the serialization of the JSON value @complexity Linear. @liveexample{The following example shows the effect of different @a indent parameters to the result of the serialization.,dump} @see https://docs.python.org/2/library/json.html#json.dump @since version 1.0.0 */ string_t dump(const int indent = -1) const { std::stringstream ss; // fix locale problems ss.imbue(std::locale(std::locale(), new DecimalSeparator)); // 6, 15 or 16 digits of precision allows round-trip IEEE 754 // string->float->string, string->double->string or string->long // double->string; to be safe, we read this value from // std::numeric_limits::digits10 ss.precision(std::numeric_limits::digits10); if (indent >= 0) { dump(ss, true, static_cast(indent)); } else { dump(ss, false, 0); } return ss.str(); } /*! @brief return the type of the JSON value (explicit) Return the type of the JSON value as a value from the @ref value_t enumeration. @return the type of the JSON value @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `type()` for all JSON types.,type} @since version 1.0.0 */ constexpr value_t type() const noexcept { return m_type; } /*! @brief return whether type is primitive This function returns true iff the JSON type is primitive (string, number, boolean, or null). @return `true` if type is primitive (string, number, boolean, or null), `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_primitive()` for all JSON types.,is_primitive} @sa @ref is_structured() -- returns whether JSON value is structured @sa @ref is_null() -- returns whether JSON value is `null` @sa @ref is_string() -- returns whether JSON value is a string @sa @ref is_boolean() -- returns whether JSON value is a boolean @sa @ref is_number() -- returns whether JSON value is a number @since version 1.0.0 */ constexpr bool is_primitive() const noexcept { return is_null() or is_string() or is_boolean() or is_number(); } /*! @brief return whether type is structured This function returns true iff the JSON type is structured (array or object). @return `true` if type is structured (array or object), `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_structured()` for all JSON types.,is_structured} @sa @ref is_primitive() -- returns whether value is primitive @sa @ref is_array() -- returns whether value is an array @sa @ref is_object() -- returns whether value is an object @since version 1.0.0 */ constexpr bool is_structured() const noexcept { return is_array() or is_object(); } /*! @brief return whether value is null This function returns true iff the JSON value is null. @return `true` if type is null, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_null()` for all JSON types.,is_null} @since version 1.0.0 */ constexpr bool is_null() const noexcept { return m_type == value_t::null; } /*! @brief return whether value is a boolean This function returns true iff the JSON value is a boolean. @return `true` if type is boolean, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_boolean()` for all JSON types.,is_boolean} @since version 1.0.0 */ constexpr bool is_boolean() const noexcept { return m_type == value_t::boolean; } /*! @brief return whether value is a number This function returns true iff the JSON value is a number. This includes both integer and floating-point values. @return `true` if type is number (regardless whether integer, unsigned integer or floating-type), `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_number()` for all JSON types.,is_number} @sa @ref is_number_integer() -- check if value is an integer or unsigned integer number @sa @ref is_number_unsigned() -- check if value is an unsigned integer number @sa @ref is_number_float() -- check if value is a floating-point number @since version 1.0.0 */ constexpr bool is_number() const noexcept { return is_number_integer() or is_number_float(); } /*! @brief return whether value is an integer number This function returns true iff the JSON value is an integer or unsigned integer number. This excludes floating-point values. @return `true` if type is an integer or unsigned integer number, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_number_integer()` for all JSON types.,is_number_integer} @sa @ref is_number() -- check if value is a number @sa @ref is_number_unsigned() -- check if value is an unsigned integer number @sa @ref is_number_float() -- check if value is a floating-point number @since version 1.0.0 */ constexpr bool is_number_integer() const noexcept { return m_type == value_t::number_integer or m_type == value_t::number_unsigned; } /*! @brief return whether value is an unsigned integer number This function returns true iff the JSON value is an unsigned integer number. This excludes floating-point and (signed) integer values. @return `true` if type is an unsigned integer number, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_number_unsigned()` for all JSON types.,is_number_unsigned} @sa @ref is_number() -- check if value is a number @sa @ref is_number_integer() -- check if value is an integer or unsigned integer number @sa @ref is_number_float() -- check if value is a floating-point number @since version 2.0.0 */ constexpr bool is_number_unsigned() const noexcept { return m_type == value_t::number_unsigned; } /*! @brief return whether value is a floating-point number This function returns true iff the JSON value is a floating-point number. This excludes integer and unsigned integer values. @return `true` if type is a floating-point number, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_number_float()` for all JSON types.,is_number_float} @sa @ref is_number() -- check if value is number @sa @ref is_number_integer() -- check if value is an integer number @sa @ref is_number_unsigned() -- check if value is an unsigned integer number @since version 1.0.0 */ constexpr bool is_number_float() const noexcept { return m_type == value_t::number_float; } /*! @brief return whether value is an object This function returns true iff the JSON value is an object. @return `true` if type is object, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_object()` for all JSON types.,is_object} @since version 1.0.0 */ constexpr bool is_object() const noexcept { return m_type == value_t::object; } /*! @brief return whether value is an array This function returns true iff the JSON value is an array. @return `true` if type is array, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_array()` for all JSON types.,is_array} @since version 1.0.0 */ constexpr bool is_array() const noexcept { return m_type == value_t::array; } /*! @brief return whether value is a string This function returns true iff the JSON value is a string. @return `true` if type is string, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_string()` for all JSON types.,is_string} @since version 1.0.0 */ constexpr bool is_string() const noexcept { return m_type == value_t::string; } /*! @brief return whether value is discarded This function returns true iff the JSON value was discarded during parsing with a callback function (see @ref parser_callback_t). @note This function will always be `false` for JSON values after parsing. That is, discarded values can only occur during parsing, but will be removed when inside a structured value or replaced by null in other cases. @return `true` if type is discarded, `false` otherwise. @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies `is_discarded()` for all JSON types.,is_discarded} @since version 1.0.0 */ constexpr bool is_discarded() const noexcept { return m_type == value_t::discarded; } /*! @brief return the type of the JSON value (implicit) Implicitly return the type of the JSON value as a value from the @ref value_t enumeration. @return the type of the JSON value @complexity Constant. @exceptionsafety No-throw guarantee: this member function never throws exceptions. @liveexample{The following code exemplifies the @ref value_t operator for all JSON types.,operator__value_t} @since version 1.0.0 */ constexpr operator value_t() const noexcept { return m_type; } /// @} private: ////////////////// // value access // ////////////////// /// get an object (explicit) template ::value and std::is_convertible::value , int>::type = 0> T get_impl(T*) const { if (is_object()) { return T(m_value.object->begin(), m_value.object->end()); } else { throw std::domain_error("type must be object, but is " + type_name()); } } /// get an object (explicit) object_t get_impl(object_t*) const { if (is_object()) { return *(m_value.object); } else { throw std::domain_error("type must be object, but is " + type_name()); } } /// get an array (explicit) template ::value and not std::is_same::value and not std::is_arithmetic::value and not std::is_convertible::value and not has_mapped_type::value , int>::type = 0> T get_impl(T*) const { if (is_array()) { T to_vector; std::transform(m_value.array->begin(), m_value.array->end(), std::inserter(to_vector, to_vector.end()), [](basic_json i) { return i.get(); }); return to_vector; } else { throw std::domain_error("type must be array, but is " + type_name()); } } /// get an array (explicit) template ::value and not std::is_same::value , int>::type = 0> std::vector get_impl(std::vector*) const { if (is_array()) { std::vector to_vector; to_vector.reserve(m_value.array->size()); std::transform(m_value.array->begin(), m_value.array->end(), std::inserter(to_vector, to_vector.end()), [](basic_json i) { return i.get(); }); return to_vector; } else { throw std::domain_error("type must be array, but is " + type_name()); } } /// get an array (explicit) template ::value and not has_mapped_type::value , int>::type = 0> T get_impl(T*) const { if (is_array()) { return T(m_value.array->begin(), m_value.array->end()); } else { throw std::domain_error("type must be array, but is " + type_name()); } } /// get an array (explicit) array_t get_impl(array_t*) const { if (is_array()) { return *(m_value.array); } else { throw std::domain_error("type must be array, but is " + type_name()); } } /// get a string (explicit) template ::value , int>::type = 0> T get_impl(T*) const { if (is_string()) { return *m_value.string; } else { throw std::domain_error("type must be string, but is " + type_name()); } } /// get a number (explicit) template::value , int>::type = 0> T get_impl(T*) const { switch (m_type) { case value_t::number_integer: { return static_cast(m_value.number_integer); } case value_t::number_unsigned: { return static_cast(m_value.number_unsigned); } case value_t::number_float: { return static_cast(m_value.number_float); } default: { throw std::domain_error("type must be number, but is " + type_name()); } } } /// get a boolean (explicit) constexpr boolean_t get_impl(boolean_t*) const { return is_boolean() ? m_value.boolean : throw std::domain_error("type must be boolean, but is " + type_name()); } /// get a pointer to the value (object) object_t* get_impl_ptr(object_t*) noexcept { return is_object() ? m_value.object : nullptr; } /// get a pointer to the value (object) constexpr const object_t* get_impl_ptr(const object_t*) const noexcept { return is_object() ? m_value.object : nullptr; } /// get a pointer to the value (array) array_t* get_impl_ptr(array_t*) noexcept { return is_array() ? m_value.array : nullptr; } /// get a pointer to the value (array) constexpr const array_t* get_impl_ptr(const array_t*) const noexcept { return is_array() ? m_value.array : nullptr; } /// get a pointer to the value (string) string_t* get_impl_ptr(string_t*) noexcept { return is_string() ? m_value.string : nullptr; } /// get a pointer to the value (string) constexpr const string_t* get_impl_ptr(const string_t*) const noexcept { return is_string() ? m_value.string : nullptr; } /// get a pointer to the value (boolean) boolean_t* get_impl_ptr(boolean_t*) noexcept { return is_boolean() ? &m_value.boolean : nullptr; } /// get a pointer to the value (boolean) constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept { return is_boolean() ? &m_value.boolean : nullptr; } /// get a pointer to the value (integer number) number_integer_t* get_impl_ptr(number_integer_t*) noexcept { return is_number_integer() ? &m_value.number_integer : nullptr; } /// get a pointer to the value (integer number) constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept { return is_number_integer() ? &m_value.number_integer : nullptr; } /// get a pointer to the value (unsigned number) number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept { return is_number_unsigned() ? &m_value.number_unsigned : nullptr; } /// get a pointer to the value (unsigned number) constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept { return is_number_unsigned() ? &m_value.number_unsigned : nullptr; } /// get a pointer to the value (floating-point number) number_float_t* get_impl_ptr(number_float_t*) noexcept { return is_number_float() ? &m_value.number_float : nullptr; } /// get a pointer to the value (floating-point number) constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept { return is_number_float() ? &m_value.number_float : nullptr; } /*! @brief helper function to implement get_ref() This funcion helps to implement get_ref() without code duplication for const and non-const overloads @tparam ThisType will be deduced as `basic_json` or `const basic_json` @throw std::domain_error if ReferenceType does not match underlying value type of the current JSON */ template static ReferenceType get_ref_impl(ThisType& obj) { // helper type using PointerType = typename std::add_pointer::type; // delegate the call to get_ptr<>() auto ptr = obj.template get_ptr(); if (ptr != nullptr) { return *ptr; } else { throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + obj.type_name()); } } public: /// @name value access /// Direct access to the stored value of a JSON value. /// @{ /*! @brief get a value (explicit) Explicit type conversion between the JSON value and a compatible value. @tparam ValueType non-pointer type compatible to the JSON value, for instance `int` for JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for JSON arrays @return copy of the JSON value, converted to type @a ValueType @throw std::domain_error in case passed type @a ValueType is incompatible to JSON; example: `"type must be object, but is null"` @complexity Linear in the size of the JSON value. @liveexample{The example below shows several conversions from JSON values to other types. There a few things to note: (1) Floating-point numbers can be converted to integers\, (2) A JSON array can be converted to a standard `std::vector`\, (3) A JSON object can be converted to C++ associative containers such as `std::unordered_map`.,get__ValueType_const} @internal The idea of using a casted null pointer to choose the correct implementation is from . @endinternal @sa @ref operator ValueType() const for implicit conversion @sa @ref get() for pointer-member access @since version 1.0.0 */ template::value , int>::type = 0> ValueType get() const { return get_impl(static_cast(nullptr)); } /*! @brief get a pointer value (explicit) Explicit pointer access to the internally stored JSON value. No copies are made. @warning The pointer becomes invalid if the underlying JSON object changes. @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, @ref number_unsigned_t, or @ref number_float_t. @return pointer to the internally stored JSON value if the requested pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @complexity Constant. @liveexample{The example below shows how pointers to internal values of a JSON value can be requested. Note that no type conversions are made and a `nullptr` is returned if the value and the requested pointer type does not match.,get__PointerType} @sa @ref get_ptr() for explicit pointer-member access @since version 1.0.0 */ template::value , int>::type = 0> PointerType get() noexcept { // delegate the call to get_ptr return get_ptr(); } /*! @brief get a pointer value (explicit) @copydoc get() */ template::value , int>::type = 0> constexpr const PointerType get() const noexcept { // delegate the call to get_ptr return get_ptr(); } /*! @brief get a pointer value (implicit) Implicit pointer access to the internally stored JSON value. No copies are made. @warning Writing data to the pointee of the result yields an undefined state. @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, @ref number_unsigned_t, or @ref number_float_t. Enforced by a static assertion. @return pointer to the internally stored JSON value if the requested pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @complexity Constant. @liveexample{The example below shows how pointers to internal values of a JSON value can be requested. Note that no type conversions are made and a `nullptr` is returned if the value and the requested pointer type does not match.,get_ptr} @since version 1.0.0 */ template::value , int>::type = 0> PointerType get_ptr() noexcept { // get the type of the PointerType (remove pointer and const) using pointee_t = typename std::remove_const::type>::type>::type; // make sure the type matches the allowed types static_assert( std::is_same::value or std::is_same::value or std::is_same::value or std::is_same::value or std::is_same::value or std::is_same::value or std::is_same::value , "incompatible pointer type"); // delegate the call to get_impl_ptr<>() return get_impl_ptr(static_cast(nullptr)); } /*! @brief get a pointer value (implicit) @copydoc get_ptr() */ template::value and std::is_const::type>::value , int>::type = 0> constexpr const PointerType get_ptr() const noexcept { // get the type of the PointerType (remove pointer and const) using pointee_t = typename std::remove_const::type>::type>::type; // make sure the type matches the allowed types static_assert( std::is_same::value or std::is_same::value or std::is_same::value or std::is_same::value or std::is_same::value or std::is_same::value or std::is_same::value , "incompatible pointer type"); // delegate the call to get_impl_ptr<>() const return get_impl_ptr(static_cast(nullptr)); } /*! @brief get a reference value (implicit) Implict reference access to the internally stored JSON value. No copies are made. @warning Writing data to the referee of the result yields an undefined state. @tparam ReferenceType reference type; must be a reference to @ref array_t, @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref number_float_t. Enforced by static assertion. @return reference to the internally stored JSON value if the requested reference type @a ReferenceType fits to the JSON value; throws std::domain_error otherwise @throw std::domain_error in case passed type @a ReferenceType is incompatible with the stored JSON value @complexity Constant. @liveexample{The example shows several calls to `get_ref()`.,get_ref} @since version 1.1.0 */ template::value , int>::type = 0> ReferenceType get_ref() { // delegate call to get_ref_impl return get_ref_impl(*this); } /*! @brief get a reference value (implicit) @copydoc get_ref() */ template::value and std::is_const::type>::value , int>::type = 0> ReferenceType get_ref() const { // delegate call to get_ref_impl return get_ref_impl(*this); } /*! @brief get a value (implicit) Implicit type conversion between the JSON value and a compatible value. The call is realized by calling @ref get() const. @tparam ValueType non-pointer type compatible to the JSON value, for instance `int` for JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for JSON arrays. The character type of @ref string_t as well as an initializer list of this type is excluded to avoid ambiguities as these types implicitly convert to `std::string`. @return copy of the JSON value, converted to type @a ValueType @throw std::domain_error in case passed type @a ValueType is incompatible to JSON, thrown by @ref get() const @complexity Linear in the size of the JSON value. @liveexample{The example below shows several conversions from JSON values to other types. There a few things to note: (1) Floating-point numbers can be converted to integers\, (2) A JSON array can be converted to a standard `std::vector`\, (3) A JSON object can be converted to C++ associative containers such as `std::unordered_map`.,operator__ValueType} @since version 1.0.0 */ template < typename ValueType, typename std::enable_if < not std::is_pointer::value and not std::is_same::value #ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015 and not std::is_same>::value #endif , int >::type = 0 > operator ValueType() const { // delegate the call to get<>() const return get(); } /// @} //////////////////// // element access // //////////////////// /// @name element access /// Access to the JSON value. /// @{ /*! @brief access specified array element with bounds checking Returns a reference to the element at specified location @a idx, with bounds checking. @param[in] idx index of the element to access @return reference to the element at index @a idx @throw std::domain_error if the JSON value is not an array; example: `"cannot use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @liveexample{The example below shows how array elements can be read and written using `at()`.,at__size_type} @since version 1.0.0 */ reference at(size_type idx) { // at only works for arrays if (is_array()) { try { return m_value.array->at(idx); } catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); } } else { throw std::domain_error("cannot use at() with " + type_name()); } } /*! @brief access specified array element with bounds checking Returns a const reference to the element at specified location @a idx, with bounds checking. @param[in] idx index of the element to access @return const reference to the element at index @a idx @throw std::domain_error if the JSON value is not an array; example: `"cannot use at() with string"` @throw std::out_of_range if the index @a idx is out of range of the array; that is, `idx >= size()`; example: `"array index 7 is out of range"` @complexity Constant. @liveexample{The example below shows how array elements can be read using `at()`.,at__size_type_const} @since version 1.0.0 */ const_reference at(size_type idx) const { // at only works for arrays if (is_array()) { try { return m_value.array->at(idx); } catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); } } else { throw std::domain_error("cannot use at() with " + type_name()); } } /*! @brief access specified object element with bounds checking Returns a reference to the element at with specified key @a key, with bounds checking. @param[in] key key of the element to access @return reference to the element at key @a key @throw std::domain_error if the JSON value is not an object; example: `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read and written using `at()`.,at__object_t_key_type} @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa @ref value() for access by value with a default value @since version 1.0.0 */ reference at(const typename object_t::key_type& key) { // at only works for objects if (is_object()) { try { return m_value.object->at(key); } catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("key '" + key + "' not found"); } } else { throw std::domain_error("cannot use at() with " + type_name()); } } /*! @brief access specified object element with bounds checking Returns a const reference to the element at with specified key @a key, with bounds checking. @param[in] key key of the element to access @return const reference to the element at key @a key @throw std::domain_error if the JSON value is not an object; example: `"cannot use at() with boolean"` @throw std::out_of_range if the key @a key is is not stored in the object; that is, `find(key) == end()`; example: `"key "the fast" not found"` @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read using `at()`.,at__object_t_key_type_const} @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @sa @ref value() for access by value with a default value @since version 1.0.0 */ const_reference at(const typename object_t::key_type& key) const { // at only works for objects if (is_object()) { try { return m_value.object->at(key); } catch (std::out_of_range&) { // create better exception explanation throw std::out_of_range("key '" + key + "' not found"); } } else { throw std::domain_error("cannot use at() with " + type_name()); } } /*! @brief access specified array element Returns a reference to the element at specified location @a idx. @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), then the array is silently filled up with `null` values to make `idx` a valid reference to the last stored element. @param[in] idx index of the element to access @return reference to the element at index @a idx @throw std::domain_error if JSON is not an array or null; example: `"cannot use operator[] with string"` @complexity Constant if @a idx is in the range of the array. Otherwise linear in `idx - size()`. @liveexample{The example below shows how array elements can be read and written using `[]` operator. Note the addition of `null` values.,operatorarray__size_type} @since version 1.0.0 */ reference operator[](size_type idx) { // implicitly convert null value to an empty array if (is_null()) { m_type = value_t::array; m_value.array = create(); assert_invariant(); } // operator[] only works for arrays if (is_array()) { // fill up array with null values if given idx is outside range if (idx >= m_value.array->size()) { m_value.array->insert(m_value.array->end(), idx - m_value.array->size() + 1, basic_json()); } return m_value.array->operator[](idx); } else { throw std::domain_error("cannot use operator[] with " + type_name()); } } /*! @brief access specified array element Returns a const reference to the element at specified location @a idx. @param[in] idx index of the element to access @return const reference to the element at index @a idx @throw std::domain_error if JSON is not an array; example: `"cannot use operator[] with null"` @complexity Constant. @liveexample{The example below shows how array elements can be read using the `[]` operator.,operatorarray__size_type_const} @since version 1.0.0 */ const_reference operator[](size_type idx) const { // const operator[] only works for arrays if (is_array()) { return m_value.array->operator[](idx); } else { throw std::domain_error("cannot use operator[] with " + type_name()); } } /*! @brief access specified object element Returns a reference to the element at with specified key @a key. @note If @a key is not found in the object, then it is silently added to the object and filled with a `null` value to make `key` a valid reference. In case the value was `null` before, it is converted to an object. @param[in] key key of the element to access @return reference to the element at key @a key @throw std::domain_error if JSON is not an object or null; example: `"cannot use operator[] with string"` @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read and written using the `[]` operator.,operatorarray__key_type} @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref value() for access by value with a default value @since version 1.0.0 */ reference operator[](const typename object_t::key_type& key) { // implicitly convert null value to an empty object if (is_null()) { m_type = value_t::object; m_value.object = create(); assert_invariant(); } // operator[] only works for objects if (is_object()) { return m_value.object->operator[](key); } else { throw std::domain_error("cannot use operator[] with " + type_name()); } } /*! @brief read-only access specified object element Returns a const reference to the element at with specified key @a key. No bounds checking is performed. @warning If the element with key @a key does not exist, the behavior is undefined. @param[in] key key of the element to access @return const reference to the element at key @a key @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** @throw std::domain_error if JSON is not an object; example: `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read using the `[]` operator.,operatorarray__key_type_const} @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref value() for access by value with a default value @since version 1.0.0 */ const_reference operator[](const typename object_t::key_type& key) const { // const operator[] only works for objects if (is_object()) { assert(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } else { throw std::domain_error("cannot use operator[] with " + type_name()); } } /*! @brief access specified object element Returns a reference to the element at with specified key @a key. @note If @a key is not found in the object, then it is silently added to the object and filled with a `null` value to make `key` a valid reference. In case the value was `null` before, it is converted to an object. @param[in] key key of the element to access @return reference to the element at key @a key @throw std::domain_error if JSON is not an object or null; example: `"cannot use operator[] with string"` @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read and written using the `[]` operator.,operatorarray__key_type} @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref value() for access by value with a default value @since version 1.0.0 */ template reference operator[](T * (&key)[n]) { return operator[](static_cast(key)); } /*! @brief read-only access specified object element Returns a const reference to the element at with specified key @a key. No bounds checking is performed. @warning If the element with key @a key does not exist, the behavior is undefined. @note This function is required for compatibility reasons with Clang. @param[in] key key of the element to access @return const reference to the element at key @a key @throw std::domain_error if JSON is not an object; example: `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read using the `[]` operator.,operatorarray__key_type_const} @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref value() for access by value with a default value @since version 1.0.0 */ template const_reference operator[](T * (&key)[n]) const { return operator[](static_cast(key)); } /*! @brief access specified object element Returns a reference to the element at with specified key @a key. @note If @a key is not found in the object, then it is silently added to the object and filled with a `null` value to make `key` a valid reference. In case the value was `null` before, it is converted to an object. @param[in] key key of the element to access @return reference to the element at key @a key @throw std::domain_error if JSON is not an object or null; example: `"cannot use operator[] with string"` @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read and written using the `[]` operator.,operatorarray__key_type} @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref value() for access by value with a default value @since version 1.1.0 */ template reference operator[](T* key) { // implicitly convert null to object if (is_null()) { m_type = value_t::object; m_value = value_t::object; assert_invariant(); } // at only works for objects if (is_object()) { return m_value.object->operator[](key); } else { throw std::domain_error("cannot use operator[] with " + type_name()); } } /*! @brief read-only access specified object element Returns a const reference to the element at with specified key @a key. No bounds checking is performed. @warning If the element with key @a key does not exist, the behavior is undefined. @param[in] key key of the element to access @return const reference to the element at key @a key @pre The element with key @a key must exist. **This precondition is enforced with an assertion.** @throw std::domain_error if JSON is not an object; example: `"cannot use operator[] with null"` @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be read using the `[]` operator.,operatorarray__key_type_const} @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref value() for access by value with a default value @since version 1.1.0 */ template const_reference operator[](T* key) const { // at only works for objects if (is_object()) { assert(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } else { throw std::domain_error("cannot use operator[] with " + type_name()); } } /*! @brief access specified object element with default value Returns either a copy of an object's element at the specified key @a key or a given default value if no element with key @a key exists. The function is basically equivalent to executing @code {.cpp} try { return at(key); } catch(std::out_of_range) { return default_value; } @endcode @note Unlike @ref at(const typename object_t::key_type&), this function does not throw if the given key @a key was not found. @note Unlike @ref operator[](const typename object_t::key_type& key), this function does not implicitly add an element to the position defined by @a key. This function is furthermore also applicable to const objects. @param[in] key key of the element to access @param[in] default_value the value to return if @a key is not found @tparam ValueType type compatible to JSON values, for instance `int` for JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for JSON arrays. Note the type of the expected value at @a key and the default value @a default_value must be compatible. @return copy of the element at key @a key or @a default_value if @a key is not found @throw std::domain_error if JSON is not an object; example: `"cannot use value() with null"` @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be queried with a default value.,basic_json__value} @sa @ref at(const typename object_t::key_type&) for access by reference with range checking @sa @ref operator[](const typename object_t::key_type&) for unchecked access by reference @since version 1.0.0 */ template ::value , int>::type = 0> ValueType value(const typename object_t::key_type& key, ValueType default_value) const { // at only works for objects if (is_object()) { // if key is found, return value and given default value otherwise const auto it = find(key); if (it != end()) { return *it; } else { return default_value; } } else { throw std::domain_error("cannot use value() with " + type_name()); } } /*! @brief overload for a default value of type const char* @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const */ string_t value(const typename object_t::key_type& key, const char* default_value) const { return value(key, string_t(default_value)); } /*! @brief access specified object element via JSON Pointer with default value Returns either a copy of an object's element at the specified key @a key or a given default value if no element with key @a key exists. The function is basically equivalent to executing @code {.cpp} try { return at(ptr); } catch(std::out_of_range) { return default_value; } @endcode @note Unlike @ref at(const json_pointer&), this function does not throw if the given key @a key was not found. @param[in] ptr a JSON pointer to the element to access @param[in] default_value the value to return if @a ptr found no value @tparam ValueType type compatible to JSON values, for instance `int` for JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for JSON arrays. Note the type of the expected value at @a key and the default value @a default_value must be compatible. @return copy of the element at key @a key or @a default_value if @a key is not found @throw std::domain_error if JSON is not an object; example: `"cannot use value() with null"` @complexity Logarithmic in the size of the container. @liveexample{The example below shows how object elements can be queried with a default value.,basic_json__value_ptr} @sa @ref operator[](const json_pointer&) for unchecked access by reference @since version 2.0.2 */ template ::value , int>::type = 0> ValueType value(const json_pointer& ptr, ValueType default_value) const { // at only works for objects if (is_object()) { // if pointer resolves a value, return it or use default value try { return ptr.get_checked(this); } catch (std::out_of_range&) { return default_value; } } else { throw std::domain_error("cannot use value() with " + type_name()); } } /*! @brief overload for a default value of type const char* @copydoc basic_json::value(const json_pointer&, ValueType) const */ string_t value(const json_pointer& ptr, const char* default_value) const { return value(ptr, string_t(default_value)); } /*! @brief access the first element Returns a reference to the first element in the container. For a JSON container `c`, the expression `c.front()` is equivalent to `*c.begin()`. @return In case of a structured type (array or object), a reference to the first element is returned. In cast of number, string, or boolean values, a reference to the value is returned. @complexity Constant. @pre The JSON value must not be `null` (would throw `std::out_of_range`) or an empty array or object (undefined behavior, **guarded by assertions**). @post The JSON value remains unchanged. @throw std::out_of_range when called on `null` value @liveexample{The following code shows an example for `front()`.,front} @sa @ref back() -- access the last element @since version 1.0.0 */ reference front() { return *begin(); } /*! @copydoc basic_json::front() */ const_reference front() const { return *cbegin(); } /*! @brief access the last element Returns a reference to the last element in the container. For a JSON container `c`, the expression `c.back()` is equivalent to @code {.cpp} auto tmp = c.end(); --tmp; return *tmp; @endcode @return In case of a structured type (array or object), a reference to the last element is returned. In cast of number, string, or boolean values, a reference to the value is returned. @complexity Constant. @pre The JSON value must not be `null` (would throw `std::out_of_range`) or an empty array or object (undefined behavior, **guarded by assertions**). @post The JSON value remains unchanged. @throw std::out_of_range when called on `null` value. @liveexample{The following code shows an example for `back()`.,back} @sa @ref front() -- access the first element @since version 1.0.0 */ reference back() { auto tmp = end(); --tmp; return *tmp; } /*! @copydoc basic_json::back() */ const_reference back() const { auto tmp = cend(); --tmp; return *tmp; } /*! @brief remove element given an iterator Removes the element specified by iterator @a pos. The iterator @a pos must be valid and dereferenceable. Thus the `end()` iterator (which is valid, but is not dereferenceable) cannot be used as a value for @a pos. If called on a primitive type other than `null`, the resulting JSON value will be `null`. @param[in] pos iterator to the element to remove @return Iterator following the last removed element. If the iterator @a pos refers to the last element, the `end()` iterator is returned. @tparam InteratorType an @ref iterator or @ref const_iterator @post Invalidates iterators and references at or after the point of the erase, including the `end()` iterator. @throw std::domain_error if called on a `null` value; example: `"cannot use erase() with null"` @throw std::domain_error if called on an iterator which does not belong to the current JSON value; example: `"iterator does not fit current value"` @throw std::out_of_range if called on a primitive type with invalid iterator (i.e., any iterator which is not `begin()`); example: `"iterator out of range"` @complexity The complexity depends on the type: - objects: amortized constant - arrays: linear in distance between pos and the end of the container - strings: linear in the length of the string - other types: constant @liveexample{The example shows the result of `erase()` for different JSON types.,erase__IteratorType} @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the given range @sa @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @sa @ref erase(const size_type) -- removes the element from an array at the given index @since version 1.0.0 */ template ::value or std::is_same::value , int>::type = 0> InteratorType erase(InteratorType pos) { // make sure iterator fits the current value if (this != pos.m_object) { throw std::domain_error("iterator does not fit current value"); } InteratorType result = end(); switch (m_type) { case value_t::boolean: case value_t::number_float: case value_t::number_integer: case value_t::number_unsigned: case value_t::string: { if (not pos.m_it.primitive_iterator.is_begin()) { throw std::out_of_range("iterator out of range"); } if (is_string()) { AllocatorType alloc; alloc.destroy(m_value.string); alloc.deallocate(m_value.string, 1); m_value.string = nullptr; } m_type = value_t::null; assert_invariant(); break; } case value_t::object: { result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); break; } case value_t::array: { result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); break; } default: { throw std::domain_error("cannot use erase() with " + type_name()); } } return result; } /*! @brief remove elements given an iterator range Removes the element specified by the range `[first; last)`. The iterator @a first does not need to be dereferenceable if `first == last`: erasing an empty range is a no-op. If called on a primitive type other than `null`, the resulting JSON value will be `null`. @param[in] first iterator to the beginning of the range to remove @param[in] last iterator past the end of the range to remove @return Iterator following the last removed element. If the iterator @a second refers to the last element, the `end()` iterator is returned. @tparam InteratorType an @ref iterator or @ref const_iterator @post Invalidates iterators and references at or after the point of the erase, including the `end()` iterator. @throw std::domain_error if called on a `null` value; example: `"cannot use erase() with null"` @throw std::domain_error if called on iterators which does not belong to the current JSON value; example: `"iterators do not fit current value"` @throw std::out_of_range if called on a primitive type with invalid iterators (i.e., if `first != begin()` and `last != end()`); example: `"iterators out of range"` @complexity The complexity depends on the type: - objects: `log(size()) + std::distance(first, last)` - arrays: linear in the distance between @a first and @a last, plus linear in the distance between @a last and end of the container - strings: linear in the length of the string - other types: constant @liveexample{The example shows the result of `erase()` for different JSON types.,erase__IteratorType_IteratorType} @sa @ref erase(InteratorType) -- removes the element at a given position @sa @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @sa @ref erase(const size_type) -- removes the element from an array at the given index @since version 1.0.0 */ template ::value or std::is_same::value , int>::type = 0> InteratorType erase(InteratorType first, InteratorType last) { // make sure iterator fits the current value if (this != first.m_object or this != last.m_object) { throw std::domain_error("iterators do not fit current value"); } InteratorType result = end(); switch (m_type) { case value_t::boolean: case value_t::number_float: case value_t::number_integer: case value_t::number_unsigned: case value_t::string: { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) { throw std::out_of_range("iterators out of range"); } if (is_string()) { AllocatorType alloc; alloc.destroy(m_value.string); alloc.deallocate(m_value.string, 1); m_value.string = nullptr; } m_type = value_t::null; assert_invariant(); break; } case value_t::object: { result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, last.m_it.object_iterator); break; } case value_t::array: { result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, last.m_it.array_iterator); break; } default: { throw std::domain_error("cannot use erase() with " + type_name()); } } return result; } /*! @brief remove element from a JSON object given a key Removes elements from a JSON object with the key value @a key. @param[in] key value of the elements to remove @return Number of elements removed. If @a ObjectType is the default `std::map` type, the return value will always be `0` (@a key was not found) or `1` (@a key was found). @post References and iterators to the erased elements are invalidated. Other references and iterators are not affected. @throw std::domain_error when called on a type other than JSON object; example: `"cannot use erase() with null"` @complexity `log(size()) + count(key)` @liveexample{The example shows the effect of `erase()`.,erase__key_type} @sa @ref erase(InteratorType) -- removes the element at a given position @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the given range @sa @ref erase(const size_type) -- removes the element from an array at the given index @since version 1.0.0 */ size_type erase(const typename object_t::key_type& key) { // this erase only works for objects if (is_object()) { return m_value.object->erase(key); } else { throw std::domain_error("cannot use erase() with " + type_name()); } } /*! @brief remove element from a JSON array given an index Removes element from a JSON array at the index @a idx. @param[in] idx index of the element to remove @throw std::domain_error when called on a type other than JSON array; example: `"cannot use erase() with null"` @throw std::out_of_range when `idx >= size()`; example: `"array index 17 is out of range"` @complexity Linear in distance between @a idx and the end of the container. @liveexample{The example shows the effect of `erase()`.,erase__size_type} @sa @ref erase(InteratorType) -- removes the element at a given position @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the given range @sa @ref erase(const typename object_t::key_type&) -- removes the element from an object at the given key @since version 1.0.0 */ void erase(const size_type idx) { // this erase only works for arrays if (is_array()) { if (idx >= size()) { throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); } m_value.array->erase(m_value.array->begin() + static_cast(idx)); } else { throw std::domain_error("cannot use erase() with " + type_name()); } } /// @} //////////// // lookup // //////////// /// @name lookup /// @{ /*! @brief find an element in a JSON object Finds an element in a JSON object with key equivalent to @a key. If the element is not found or the JSON value is not an object, end() is returned. @param[in] key key value of the element to search for @return Iterator to an element with key equivalent to @a key. If no such element is found, past-the-end (see end()) iterator is returned. @complexity Logarithmic in the size of the JSON object. @liveexample{The example shows how `find()` is used.,find__key_type} @since version 1.0.0 */ iterator find(typename object_t::key_type key) { auto result = end(); if (is_object()) { result.m_it.object_iterator = m_value.object->find(key); } return result; } /*! @brief find an element in a JSON object @copydoc find(typename object_t::key_type) */ const_iterator find(typename object_t::key_type key) const { auto result = cend(); if (is_object()) { result.m_it.object_iterator = m_value.object->find(key); } return result; } /*! @brief returns the number of occurrences of a key in a JSON object Returns the number of elements with key @a key. If ObjectType is the default `std::map` type, the return value will always be `0` (@a key was not found) or `1` (@a key was found). @param[in] key key value of the element to count @return Number of elements with key @a key. If the JSON value is not an object, the return value will be `0`. @complexity Logarithmic in the size of the JSON object. @liveexample{The example shows how `count()` is used.,count} @since version 1.0.0 */ size_type count(typename object_t::key_type key) const { // return 0 for all nonobject types return is_object() ? m_value.object->count(key) : 0; } /// @} /////////////// // iterators // /////////////// /// @name iterators /// @{ /*! @brief returns an iterator to the first element Returns an iterator to the first element. @image html range-begin-end.svg "Illustration from cppreference.com" @return iterator to the first element @complexity Constant. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is constant. @liveexample{The following code shows an example for `begin()`.,begin} @sa @ref cbegin() -- returns a const iterator to the beginning @sa @ref end() -- returns an iterator to the end @sa @ref cend() -- returns a const iterator to the end @since version 1.0.0 */ iterator begin() noexcept { iterator result(this); result.set_begin(); return result; } /*! @copydoc basic_json::cbegin() */ const_iterator begin() const noexcept { return cbegin(); } /*! @brief returns a const iterator to the first element Returns a const iterator to the first element. @image html range-begin-end.svg "Illustration from cppreference.com" @return const iterator to the first element @complexity Constant. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is constant. - Has the semantics of `const_cast(*this).begin()`. @liveexample{The following code shows an example for `cbegin()`.,cbegin} @sa @ref begin() -- returns an iterator to the beginning @sa @ref end() -- returns an iterator to the end @sa @ref cend() -- returns a const iterator to the end @since version 1.0.0 */ const_iterator cbegin() const noexcept { const_iterator result(this); result.set_begin(); return result; } /*! @brief returns an iterator to one past the last element Returns an iterator to one past the last element. @image html range-begin-end.svg "Illustration from cppreference.com" @return iterator one past the last element @complexity Constant. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is constant. @liveexample{The following code shows an example for `end()`.,end} @sa @ref cend() -- returns a const iterator to the end @sa @ref begin() -- returns an iterator to the beginning @sa @ref cbegin() -- returns a const iterator to the beginning @since version 1.0.0 */ iterator end() noexcept { iterator result(this); result.set_end(); return result; } /*! @copydoc basic_json::cend() */ const_iterator end() const noexcept { return cend(); } /*! @brief returns a const iterator to one past the last element Returns a const iterator to one past the last element. @image html range-begin-end.svg "Illustration from cppreference.com" @return const iterator one past the last element @complexity Constant. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is constant. - Has the semantics of `const_cast(*this).end()`. @liveexample{The following code shows an example for `cend()`.,cend} @sa @ref end() -- returns an iterator to the end @sa @ref begin() -- returns an iterator to the beginning @sa @ref cbegin() -- returns a const iterator to the beginning @since version 1.0.0 */ const_iterator cend() const noexcept { const_iterator result(this); result.set_end(); return result; } /*! @brief returns an iterator to the reverse-beginning Returns an iterator to the reverse-beginning; that is, the last element. @image html range-rbegin-rend.svg "Illustration from cppreference.com" @complexity Constant. @requirement This function helps `basic_json` satisfying the [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirements: - The complexity is constant. - Has the semantics of `reverse_iterator(end())`. @liveexample{The following code shows an example for `rbegin()`.,rbegin} @sa @ref crbegin() -- returns a const reverse iterator to the beginning @sa @ref rend() -- returns a reverse iterator to the end @sa @ref crend() -- returns a const reverse iterator to the end @since version 1.0.0 */ reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } /*! @copydoc basic_json::crbegin() */ const_reverse_iterator rbegin() const noexcept { return crbegin(); } /*! @brief returns an iterator to the reverse-end Returns an iterator to the reverse-end; that is, one before the first element. @image html range-rbegin-rend.svg "Illustration from cppreference.com" @complexity Constant. @requirement This function helps `basic_json` satisfying the [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirements: - The complexity is constant. - Has the semantics of `reverse_iterator(begin())`. @liveexample{The following code shows an example for `rend()`.,rend} @sa @ref crend() -- returns a const reverse iterator to the end @sa @ref rbegin() -- returns a reverse iterator to the beginning @sa @ref crbegin() -- returns a const reverse iterator to the beginning @since version 1.0.0 */ reverse_iterator rend() noexcept { return reverse_iterator(begin()); } /*! @copydoc basic_json::crend() */ const_reverse_iterator rend() const noexcept { return crend(); } /*! @brief returns a const reverse iterator to the last element Returns a const iterator to the reverse-beginning; that is, the last element. @image html range-rbegin-rend.svg "Illustration from cppreference.com" @complexity Constant. @requirement This function helps `basic_json` satisfying the [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirements: - The complexity is constant. - Has the semantics of `const_cast(*this).rbegin()`. @liveexample{The following code shows an example for `crbegin()`.,crbegin} @sa @ref rbegin() -- returns a reverse iterator to the beginning @sa @ref rend() -- returns a reverse iterator to the end @sa @ref crend() -- returns a const reverse iterator to the end @since version 1.0.0 */ const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(cend()); } /*! @brief returns a const reverse iterator to one before the first Returns a const reverse iterator to the reverse-end; that is, one before the first element. @image html range-rbegin-rend.svg "Illustration from cppreference.com" @complexity Constant. @requirement This function helps `basic_json` satisfying the [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirements: - The complexity is constant. - Has the semantics of `const_cast(*this).rend()`. @liveexample{The following code shows an example for `crend()`.,crend} @sa @ref rend() -- returns a reverse iterator to the end @sa @ref rbegin() -- returns a reverse iterator to the beginning @sa @ref crbegin() -- returns a const reverse iterator to the beginning @since version 1.0.0 */ const_reverse_iterator crend() const noexcept { return const_reverse_iterator(cbegin()); } private: // forward declaration template class iteration_proxy; public: /*! @brief wrapper to access iterator member functions in range-based for This function allows to access @ref iterator::key() and @ref iterator::value() during range-based for loops. In these loops, a reference to the JSON values is returned, so there is no access to the underlying iterator. @note The name of this function is not yet final and may change in the future. */ static iteration_proxy iterator_wrapper(reference cont) { return iteration_proxy(cont); } /*! @copydoc iterator_wrapper(reference) */ static iteration_proxy iterator_wrapper(const_reference cont) { return iteration_proxy(cont); } /// @} ////////////// // capacity // ////////////// /// @name capacity /// @{ /*! @brief checks whether the container is empty Checks if a JSON value has no elements. @return The return value depends on the different types and is defined as follows: Value type | return value ----------- | ------------- null | `true` boolean | `false` string | `false` number | `false` object | result of function `object_t::empty()` array | result of function `array_t::empty()` @note This function does not return whether a string stored as JSON value is empty - it returns whether the JSON container itself is empty which is false in the case of a string. @complexity Constant, as long as @ref array_t and @ref object_t satisfy the Container concept; that is, their `empty()` functions have constant complexity. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is constant. - Has the semantics of `begin() == end()`. @liveexample{The following code uses `empty()` to check if a JSON object contains any elements.,empty} @sa @ref size() -- returns the number of elements @since version 1.0.0 */ bool empty() const noexcept { switch (m_type) { case value_t::null: { // null values are empty return true; } case value_t::array: { // delegate call to array_t::empty() return m_value.array->empty(); } case value_t::object: { // delegate call to object_t::empty() return m_value.object->empty(); } default: { // all other types are nonempty return false; } } } /*! @brief returns the number of elements Returns the number of elements in a JSON value. @return The return value depends on the different types and is defined as follows: Value type | return value ----------- | ------------- null | `0` boolean | `1` string | `1` number | `1` object | result of function object_t::size() array | result of function array_t::size() @note This function does not return the length of a string stored as JSON value - it returns the number of elements in the JSON value which is 1 in the case of a string. @complexity Constant, as long as @ref array_t and @ref object_t satisfy the Container concept; that is, their size() functions have constant complexity. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is constant. - Has the semantics of `std::distance(begin(), end())`. @liveexample{The following code calls `size()` on the different value types.,size} @sa @ref empty() -- checks whether the container is empty @sa @ref max_size() -- returns the maximal number of elements @since version 1.0.0 */ size_type size() const noexcept { switch (m_type) { case value_t::null: { // null values are empty return 0; } case value_t::array: { // delegate call to array_t::size() return m_value.array->size(); } case value_t::object: { // delegate call to object_t::size() return m_value.object->size(); } default: { // all other types have size 1 return 1; } } } /*! @brief returns the maximum possible number of elements Returns the maximum number of elements a JSON value is able to hold due to system or library implementation limitations, i.e. `std::distance(begin(), end())` for the JSON value. @return The return value depends on the different types and is defined as follows: Value type | return value ----------- | ------------- null | `0` (same as `size()`) boolean | `1` (same as `size()`) string | `1` (same as `size()`) number | `1` (same as `size()`) object | result of function `object_t::max_size()` array | result of function `array_t::max_size()` @complexity Constant, as long as @ref array_t and @ref object_t satisfy the Container concept; that is, their `max_size()` functions have constant complexity. @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is constant. - Has the semantics of returning `b.size()` where `b` is the largest possible JSON value. @liveexample{The following code calls `max_size()` on the different value types. Note the output is implementation specific.,max_size} @sa @ref size() -- returns the number of elements @since version 1.0.0 */ size_type max_size() const noexcept { switch (m_type) { case value_t::array: { // delegate call to array_t::max_size() return m_value.array->max_size(); } case value_t::object: { // delegate call to object_t::max_size() return m_value.object->max_size(); } default: { // all other types have max_size() == size() return size(); } } } /// @} /////////////// // modifiers // /////////////// /// @name modifiers /// @{ /*! @brief clears the contents Clears the content of a JSON value and resets it to the default value as if @ref basic_json(value_t) would have been called: Value type | initial value ----------- | ------------- null | `null` boolean | `false` string | `""` number | `0` object | `{}` array | `[]` @note Floating-point numbers are set to `0.0` which will be serialized to `0`. The vale type remains @ref number_float_t. @complexity Linear in the size of the JSON value. @liveexample{The example below shows the effect of `clear()` to different JSON types.,clear} @since version 1.0.0 */ void clear() noexcept { switch (m_type) { case value_t::number_integer: { m_value.number_integer = 0; break; } case value_t::number_unsigned: { m_value.number_unsigned = 0; break; } case value_t::number_float: { m_value.number_float = 0.0; break; } case value_t::boolean: { m_value.boolean = false; break; } case value_t::string: { m_value.string->clear(); break; } case value_t::array: { m_value.array->clear(); break; } case value_t::object: { m_value.object->clear(); break; } default: { break; } } } /*! @brief add an object to an array Appends the given element @a val to the end of the JSON value. If the function is called on a JSON null value, an empty array is created before appending @a val. @param[in] val the value to add to the JSON array @throw std::domain_error when called on a type other than JSON array or null; example: `"cannot use push_back() with number"` @complexity Amortized constant. @liveexample{The example shows how `push_back()` and `+=` can be used to add elements to a JSON array. Note how the `null` value was silently converted to a JSON array.,push_back} @since version 1.0.0 */ void push_back(basic_json&& val) { // push_back only works for null objects or arrays if (not(is_null() or is_array())) { throw std::domain_error("cannot use push_back() with " + type_name()); } // transform null object into an array if (is_null()) { m_type = value_t::array; m_value = value_t::array; assert_invariant(); } // add element to array (move semantics) m_value.array->push_back(std::move(val)); // invalidate object val.m_type = value_t::null; } /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ reference operator+=(basic_json&& val) { push_back(std::move(val)); return *this; } /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ void push_back(const basic_json& val) { // push_back only works for null objects or arrays if (not(is_null() or is_array())) { throw std::domain_error("cannot use push_back() with " + type_name()); } // transform null object into an array if (is_null()) { m_type = value_t::array; m_value = value_t::array; assert_invariant(); } // add element to array m_value.array->push_back(val); } /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ reference operator+=(const basic_json& val) { push_back(val); return *this; } /*! @brief add an object to an object Inserts the given element @a val to the JSON object. If the function is called on a JSON null value, an empty object is created before inserting @a val. @param[in] val the value to add to the JSON object @throw std::domain_error when called on a type other than JSON object or null; example: `"cannot use push_back() with number"` @complexity Logarithmic in the size of the container, O(log(`size()`)). @liveexample{The example shows how `push_back()` and `+=` can be used to add elements to a JSON object. Note how the `null` value was silently converted to a JSON object.,push_back__object_t__value} @since version 1.0.0 */ void push_back(const typename object_t::value_type& val) { // push_back only works for null objects or objects if (not(is_null() or is_object())) { throw std::domain_error("cannot use push_back() with " + type_name()); } // transform null object into an object if (is_null()) { m_type = value_t::object; m_value = value_t::object; assert_invariant(); } // add element to array m_value.object->insert(val); } /*! @brief add an object to an object @copydoc push_back(const typename object_t::value_type&) */ reference operator+=(const typename object_t::value_type& val) { push_back(val); return *this; } /*! @brief add an object to an object This function allows to use `push_back` with an initializer list. In case 1. the current value is an object, 2. the initializer list @a init contains only two elements, and 3. the first element of @a init is a string, @a init is converted into an object element and added using @ref push_back(const typename object_t::value_type&). Otherwise, @a init is converted to a JSON value and added using @ref push_back(basic_json&&). @param init an initializer list @complexity Linear in the size of the initializer list @a init. @note This function is required to resolve an ambiguous overload error, because pairs like `{"key", "value"}` can be both interpreted as `object_t::value_type` or `std::initializer_list`, see https://github.com/nlohmann/json/issues/235 for more information. @liveexample{The example shows how initializer lists are treated as objects when possible.,push_back__initializer_list} */ void push_back(std::initializer_list init) { if (is_object() and init.size() == 2 and init.begin()->is_string()) { const string_t key = *init.begin(); push_back(typename object_t::value_type(key, *(init.begin() + 1))); } else { push_back(basic_json(init)); } } /*! @brief add an object to an object @copydoc push_back(std::initializer_list) */ reference operator+=(std::initializer_list init) { push_back(init); return *this; } /*! @brief inserts element Inserts element @a val before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator @param[in] val element to insert @return iterator pointing to the inserted @a val. @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @complexity Constant plus linear in the distance between pos and end of the container. @liveexample{The example shows how `insert()` is used.,insert} @since version 1.0.0 */ iterator insert(const_iterator pos, const basic_json& val) { // insert only works for arrays if (is_array()) { // check if iterator pos fits to this JSON value if (pos.m_object != this) { throw std::domain_error("iterator does not fit current value"); } // insert to array and return iterator iterator result(this); result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); return result; } else { throw std::domain_error("cannot use insert() with " + type_name()); } } /*! @brief inserts element @copydoc insert(const_iterator, const basic_json&) */ iterator insert(const_iterator pos, basic_json&& val) { return insert(pos, val); } /*! @brief inserts elements Inserts @a cnt copies of @a val before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator @param[in] cnt number of copies of @a val to insert @param[in] val element to insert @return iterator pointing to the first element inserted, or @a pos if `cnt==0` @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @complexity Linear in @a cnt plus linear in the distance between @a pos and end of the container. @liveexample{The example shows how `insert()` is used.,insert__count} @since version 1.0.0 */ iterator insert(const_iterator pos, size_type cnt, const basic_json& val) { // insert only works for arrays if (is_array()) { // check if iterator pos fits to this JSON value if (pos.m_object != this) { throw std::domain_error("iterator does not fit current value"); } // insert to array and return iterator iterator result(this); result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); return result; } else { throw std::domain_error("cannot use insert() with " + type_name()); } } /*! @brief inserts elements Inserts elements from range `[first, last)` before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator @param[in] first begin of the range of elements to insert @param[in] last end of the range of elements to insert @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @throw std::domain_error if @a first and @a last do not belong to the same JSON value; example: `"iterators do not fit"` @throw std::domain_error if @a first or @a last are iterators into container for which insert is called; example: `"passed iterators may not belong to container"` @return iterator pointing to the first element inserted, or @a pos if `first==last` @complexity Linear in `std::distance(first, last)` plus linear in the distance between @a pos and end of the container. @liveexample{The example shows how `insert()` is used.,insert__range} @since version 1.0.0 */ iterator insert(const_iterator pos, const_iterator first, const_iterator last) { // insert only works for arrays if (not is_array()) { throw std::domain_error("cannot use insert() with " + type_name()); } // check if iterator pos fits to this JSON value if (pos.m_object != this) { throw std::domain_error("iterator does not fit current value"); } // check if range iterators belong to the same JSON object if (first.m_object != last.m_object) { throw std::domain_error("iterators do not fit"); } if (first.m_object == this or last.m_object == this) { throw std::domain_error("passed iterators may not belong to container"); } // insert to array and return iterator iterator result(this); result.m_it.array_iterator = m_value.array->insert( pos.m_it.array_iterator, first.m_it.array_iterator, last.m_it.array_iterator); return result; } /*! @brief inserts elements Inserts elements from initializer list @a ilist before iterator @a pos. @param[in] pos iterator before which the content will be inserted; may be the end() iterator @param[in] ilist initializer list to insert the values from @throw std::domain_error if called on JSON values other than arrays; example: `"cannot use insert() with string"` @throw std::domain_error if @a pos is not an iterator of *this; example: `"iterator does not fit current value"` @return iterator pointing to the first element inserted, or @a pos if `ilist` is empty @complexity Linear in `ilist.size()` plus linear in the distance between @a pos and end of the container. @liveexample{The example shows how `insert()` is used.,insert__ilist} @since version 1.0.0 */ iterator insert(const_iterator pos, std::initializer_list ilist) { // insert only works for arrays if (not is_array()) { throw std::domain_error("cannot use insert() with " + type_name()); } // check if iterator pos fits to this JSON value if (pos.m_object != this) { throw std::domain_error("iterator does not fit current value"); } // insert to array and return iterator iterator result(this); result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); return result; } /*! @brief exchanges the values Exchanges the contents of the JSON value with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is invalidated. @param[in,out] other JSON value to exchange the contents with @complexity Constant. @liveexample{The example below shows how JSON values can be swapped with `swap()`.,swap__reference} @since version 1.0.0 */ void swap(reference other) noexcept ( std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value ) { std::swap(m_type, other.m_type); std::swap(m_value, other.m_value); assert_invariant(); } /*! @brief exchanges the values Exchanges the contents of a JSON array with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is invalidated. @param[in,out] other array to exchange the contents with @throw std::domain_error when JSON value is not an array; example: `"cannot use swap() with string"` @complexity Constant. @liveexample{The example below shows how arrays can be swapped with `swap()`.,swap__array_t} @since version 1.0.0 */ void swap(array_t& other) { // swap only works for arrays if (is_array()) { std::swap(*(m_value.array), other); } else { throw std::domain_error("cannot use swap() with " + type_name()); } } /*! @brief exchanges the values Exchanges the contents of a JSON object with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is invalidated. @param[in,out] other object to exchange the contents with @throw std::domain_error when JSON value is not an object; example: `"cannot use swap() with string"` @complexity Constant. @liveexample{The example below shows how objects can be swapped with `swap()`.,swap__object_t} @since version 1.0.0 */ void swap(object_t& other) { // swap only works for objects if (is_object()) { std::swap(*(m_value.object), other); } else { throw std::domain_error("cannot use swap() with " + type_name()); } } /*! @brief exchanges the values Exchanges the contents of a JSON string with those of @a other. Does not invoke any move, copy, or swap operations on individual elements. All iterators and references remain valid. The past-the-end iterator is invalidated. @param[in,out] other string to exchange the contents with @throw std::domain_error when JSON value is not a string; example: `"cannot use swap() with boolean"` @complexity Constant. @liveexample{The example below shows how strings can be swapped with `swap()`.,swap__string_t} @since version 1.0.0 */ void swap(string_t& other) { // swap only works for strings if (is_string()) { std::swap(*(m_value.string), other); } else { throw std::domain_error("cannot use swap() with " + type_name()); } } /// @} ////////////////////////////////////////// // lexicographical comparison operators // ////////////////////////////////////////// /// @name lexicographical comparison operators /// @{ private: /*! @brief comparison operator for JSON types Returns an ordering that is similar to Python: - order: null < boolean < number < object < array < string - furthermore, each type is not smaller than itself @since version 1.0.0 */ friend bool operator<(const value_t lhs, const value_t rhs) noexcept { static constexpr std::array order = {{ 0, // null 3, // object 4, // array 5, // string 1, // boolean 2, // integer 2, // unsigned 2, // float } }; // discarded values are not comparable if (lhs == value_t::discarded or rhs == value_t::discarded) { return false; } return order[static_cast(lhs)] < order[static_cast(rhs)]; } public: /*! @brief comparison: equal Compares two JSON values for equality according to the following rules: - Two JSON values are equal if (1) they are from the same type and (2) their stored values are the same. - Integer and floating-point numbers are automatically converted before comparison. Floating-point numbers are compared indirectly: two floating-point numbers `f1` and `f2` are considered equal if neither `f1 > f2` nor `f2 > f1` holds. - Two JSON null values are equal. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether the values @a lhs and @a rhs are equal @complexity Linear. @liveexample{The example demonstrates comparing several JSON types.,operator__equal} @since version 1.0.0 */ friend bool operator==(const_reference lhs, const_reference rhs) noexcept { const auto lhs_type = lhs.type(); const auto rhs_type = rhs.type(); if (lhs_type == rhs_type) { switch (lhs_type) { case value_t::array: { return *lhs.m_value.array == *rhs.m_value.array; } case value_t::object: { return *lhs.m_value.object == *rhs.m_value.object; } case value_t::null: { return true; } case value_t::string: { return *lhs.m_value.string == *rhs.m_value.string; } case value_t::boolean: { return lhs.m_value.boolean == rhs.m_value.boolean; } case value_t::number_integer: { return lhs.m_value.number_integer == rhs.m_value.number_integer; } case value_t::number_unsigned: { return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; } case value_t::number_float: { return lhs.m_value.number_float == rhs.m_value.number_float; } default: { return false; } } } else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) { return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; } else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) { return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); } else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) { return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; } else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) { return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); } else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) { return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; } else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) { return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); } return false; } /*! @brief comparison: equal The functions compares the given JSON value against a null pointer. As the null pointer can be used to initialize a JSON value to null, a comparison of JSON value @a v with a null pointer should be equivalent to call `v.is_null()`. @param[in] v JSON value to consider @return whether @a v is null @complexity Constant. @liveexample{The example compares several JSON types to the null pointer. ,operator__equal__nullptr_t} @since version 1.0.0 */ friend bool operator==(const_reference v, std::nullptr_t) noexcept { return v.is_null(); } /*! @brief comparison: equal @copydoc operator==(const_reference, std::nullptr_t) */ friend bool operator==(std::nullptr_t, const_reference v) noexcept { return v.is_null(); } /*! @brief comparison: not equal Compares two JSON values for inequality by calculating `not (lhs == rhs)`. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether the values @a lhs and @a rhs are not equal @complexity Linear. @liveexample{The example demonstrates comparing several JSON types.,operator__notequal} @since version 1.0.0 */ friend bool operator!=(const_reference lhs, const_reference rhs) noexcept { return not (lhs == rhs); } /*! @brief comparison: not equal The functions compares the given JSON value against a null pointer. As the null pointer can be used to initialize a JSON value to null, a comparison of JSON value @a v with a null pointer should be equivalent to call `not v.is_null()`. @param[in] v JSON value to consider @return whether @a v is not null @complexity Constant. @liveexample{The example compares several JSON types to the null pointer. ,operator__notequal__nullptr_t} @since version 1.0.0 */ friend bool operator!=(const_reference v, std::nullptr_t) noexcept { return not v.is_null(); } /*! @brief comparison: not equal @copydoc operator!=(const_reference, std::nullptr_t) */ friend bool operator!=(std::nullptr_t, const_reference v) noexcept { return not v.is_null(); } /*! @brief comparison: less than Compares whether one JSON value @a lhs is less than another JSON value @a rhs according to the following rules: - If @a lhs and @a rhs have the same type, the values are compared using the default `<` operator. - Integer and floating-point numbers are automatically converted before comparison - In case @a lhs and @a rhs have different types, the values are ignored and the order of the types is considered, see @ref operator<(const value_t, const value_t). @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether @a lhs is less than @a rhs @complexity Linear. @liveexample{The example demonstrates comparing several JSON types.,operator__less} @since version 1.0.0 */ friend bool operator<(const_reference lhs, const_reference rhs) noexcept { const auto lhs_type = lhs.type(); const auto rhs_type = rhs.type(); if (lhs_type == rhs_type) { switch (lhs_type) { case value_t::array: { return *lhs.m_value.array < *rhs.m_value.array; } case value_t::object: { return *lhs.m_value.object < *rhs.m_value.object; } case value_t::null: { return false; } case value_t::string: { return *lhs.m_value.string < *rhs.m_value.string; } case value_t::boolean: { return lhs.m_value.boolean < rhs.m_value.boolean; } case value_t::number_integer: { return lhs.m_value.number_integer < rhs.m_value.number_integer; } case value_t::number_unsigned: { return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; } case value_t::number_float: { return lhs.m_value.number_float < rhs.m_value.number_float; } default: { return false; } } } else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) { return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; } else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) { return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); } else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) { return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; } else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) { return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); } else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) { return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); } else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) { return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; } // We only reach this line if we cannot compare values. In that case, // we compare types. Note we have to call the operator explicitly, // because MSVC has problems otherwise. return operator<(lhs_type, rhs_type); } /*! @brief comparison: less than or equal Compares whether one JSON value @a lhs is less than or equal to another JSON value by calculating `not (rhs < lhs)`. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether @a lhs is less than or equal to @a rhs @complexity Linear. @liveexample{The example demonstrates comparing several JSON types.,operator__greater} @since version 1.0.0 */ friend bool operator<=(const_reference lhs, const_reference rhs) noexcept { return not (rhs < lhs); } /*! @brief comparison: greater than Compares whether one JSON value @a lhs is greater than another JSON value by calculating `not (lhs <= rhs)`. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether @a lhs is greater than to @a rhs @complexity Linear. @liveexample{The example demonstrates comparing several JSON types.,operator__lessequal} @since version 1.0.0 */ friend bool operator>(const_reference lhs, const_reference rhs) noexcept { return not (lhs <= rhs); } /*! @brief comparison: greater than or equal Compares whether one JSON value @a lhs is greater than or equal to another JSON value by calculating `not (lhs < rhs)`. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether @a lhs is greater than or equal to @a rhs @complexity Linear. @liveexample{The example demonstrates comparing several JSON types.,operator__greaterequal} @since version 1.0.0 */ friend bool operator>=(const_reference lhs, const_reference rhs) noexcept { return not (lhs < rhs); } /// @} /////////////////// // serialization // /////////////////// /// @name serialization /// @{ /*! @brief serialize to stream Serialize the given JSON value @a j to the output stream @a o. The JSON value will be serialized using the @ref dump member function. The indentation of the output can be controlled with the member variable `width` of the output stream @a o. For instance, using the manipulator `std::setw(4)` on @a o sets the indentation level to `4` and the serialization result is the same as calling `dump(4)`. @note During serializaion, the locale and the precision of the output stream @a o are changed. The original values are restored when the function returns. @param[in,out] o stream to serialize to @param[in] j JSON value to serialize @return the stream @a o @complexity Linear. @liveexample{The example below shows the serialization with different parameters to `width` to adjust the indentation level.,operator_serialize} @since version 1.0.0 */ friend std::ostream& operator<<(std::ostream& o, const basic_json& j) { // read width member and use it as indentation parameter if nonzero const bool pretty_print = (o.width() > 0); const auto indentation = (pretty_print ? o.width() : 0); // reset width to 0 for subsequent calls to this stream o.width(0); // fix locale problems const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); // set precision // 6, 15 or 16 digits of precision allows round-trip IEEE 754 // string->float->string, string->double->string or string->long // double->string; to be safe, we read this value from // std::numeric_limits::digits10 const auto old_precision = o.precision(std::numeric_limits::digits10); // do the actual serialization j.dump(o, pretty_print, static_cast(indentation)); // reset locale and precision o.imbue(old_locale); o.precision(old_precision); return o; } /*! @brief serialize to stream @copydoc operator<<(std::ostream&, const basic_json&) */ friend std::ostream& operator>>(const basic_json& j, std::ostream& o) { return o << j; } /// @} ///////////////////// // deserialization // ///////////////////// /// @name deserialization /// @{ /*! @brief deserialize from string @param[in] s string to read a serialized JSON value from @param[in] cb a parser callback function of type @ref parser_callback_t which is used to control the deserialization by filtering unwanted values (optional) @return result of the deserialization @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @note A UTF-8 byte order mark is silently ignored. @liveexample{The example below demonstrates the `parse()` function with and without callback function.,parse__string__parser_callback_t} @sa @ref parse(std::istream&, const parser_callback_t) for a version that reads from an input stream @since version 1.0.0 */ static basic_json parse(const string_t& s, const parser_callback_t cb = nullptr) { return parser(s, cb).parse(); } /*! @brief deserialize from stream @param[in,out] i stream to read a serialized JSON value from @param[in] cb a parser callback function of type @ref parser_callback_t which is used to control the deserialization by filtering unwanted values (optional) @return result of the deserialization @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function @a cb has a super-linear complexity. @note A UTF-8 byte order mark is silently ignored. @liveexample{The example below demonstrates the `parse()` function with and without callback function.,parse__istream__parser_callback_t} @sa @ref parse(const string_t&, const parser_callback_t) for a version that reads from a string @since version 1.0.0 */ static basic_json parse(std::istream& i, const parser_callback_t cb = nullptr) { return parser(i, cb).parse(); } /*! @copydoc parse(std::istream&, const parser_callback_t) */ static basic_json parse(std::istream&& i, const parser_callback_t cb = nullptr) { return parser(i, cb).parse(); } /*! @brief deserialize from stream Deserializes an input stream to a JSON value. @param[in,out] i input stream to read a serialized JSON value from @param[in,out] j JSON value to write the deserialized input to @throw std::invalid_argument in case of parse errors @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. @note A UTF-8 byte order mark is silently ignored. @liveexample{The example below shows how a JSON value is constructed by reading a serialization from a stream.,operator_deserialize} @sa parse(std::istream&, const parser_callback_t) for a variant with a parser callback function to filter values while parsing @since version 1.0.0 */ friend std::istream& operator<<(basic_json& j, std::istream& i) { j = parser(i).parse(); return i; } /*! @brief deserialize from stream @copydoc operator<<(basic_json&, std::istream&) */ friend std::istream& operator>>(std::istream& i, basic_json& j) { j = parser(i).parse(); return i; } /// @} private: /////////////////////////// // convenience functions // /////////////////////////// /*! @brief return the type as string Returns the type name as string to be used in error messages - usually to indicate that a function was called on a wrong JSON type. @return basically a string representation of a the @ref m_type member @complexity Constant. @since version 1.0.0 */ std::string type_name() const { switch (m_type) { case value_t::null: return "null"; case value_t::object: return "object"; case value_t::array: return "array"; case value_t::string: return "string"; case value_t::boolean: return "boolean"; case value_t::discarded: return "discarded"; default: return "number"; } } /*! @brief calculates the extra space to escape a JSON string @param[in] s the string to escape @return the number of characters required to escape string @a s @complexity Linear in the length of string @a s. */ static std::size_t extra_space(const string_t& s) noexcept { return std::accumulate(s.begin(), s.end(), size_t{}, [](size_t res, typename string_t::value_type c) { switch (c) { case '"': case '\\': case '\b': case '\f': case '\n': case '\r': case '\t': { // from c (1 byte) to \x (2 bytes) return res + 1; } default: { if (c >= 0x00 and c <= 0x1f) { // from c (1 byte) to \uxxxx (6 bytes) return res + 5; } else { return res; } } } }); } /*! @brief escape a string Escape a string by replacing certain special characters by a sequence of an escape character (backslash) and another character and other control characters by a sequence of "\u" followed by a four-digit hex representation. @param[in] s the string to escape @return the escaped string @complexity Linear in the length of string @a s. */ static string_t escape_string(const string_t& s) { const auto space = extra_space(s); if (space == 0) { return s; } // create a result string of necessary size string_t result(s.size() + space, '\\'); std::size_t pos = 0; for (const auto& c : s) { switch (c) { // quotation mark (0x22) case '"': { result[pos + 1] = '"'; pos += 2; break; } // reverse solidus (0x5c) case '\\': { // nothing to change pos += 2; break; } // backspace (0x08) case '\b': { result[pos + 1] = 'b'; pos += 2; break; } // formfeed (0x0c) case '\f': { result[pos + 1] = 'f'; pos += 2; break; } // newline (0x0a) case '\n': { result[pos + 1] = 'n'; pos += 2; break; } // carriage return (0x0d) case '\r': { result[pos + 1] = 'r'; pos += 2; break; } // horizontal tab (0x09) case '\t': { result[pos + 1] = 't'; pos += 2; break; } default: { if (c >= 0x00 and c <= 0x1f) { // convert a number 0..15 to its hex representation // (0..f) static const char hexify[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; // print character c as \uxxxx for (const char m : { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f] }) { result[++pos] = m; } ++pos; } else { // all other characters are added as-is result[pos++] = c; } break; } } } return result; } /*! @brief internal implementation of the serialization function This function is called by the public member function dump and organizes the serialization internally. The indentation level is propagated as additional parameter. In case of arrays and objects, the function is called recursively. Note that - strings and object keys are escaped using `escape_string()` - integer numbers are converted implicitly via `operator<<` - floating-point numbers are converted to a string using `"%g"` format @param[out] o stream to write to @param[in] pretty_print whether the output shall be pretty-printed @param[in] indent_step the indent level @param[in] current_indent the current indent level (only used internally) */ void dump(std::ostream& o, const bool pretty_print, const unsigned int indent_step, const unsigned int current_indent = 0) const { // variable to hold indentation for recursive calls unsigned int new_indent = current_indent; switch (m_type) { case value_t::object: { if (m_value.object->empty()) { o << "{}"; return; } o << "{"; // increase indentation if (pretty_print) { new_indent += indent_step; o << "\n"; } for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) { if (i != m_value.object->cbegin()) { o << (pretty_print ? ",\n" : ","); } o << string_t(new_indent, ' ') << "\"" << escape_string(i->first) << "\":" << (pretty_print ? " " : ""); i->second.dump(o, pretty_print, indent_step, new_indent); } // decrease indentation if (pretty_print) { new_indent -= indent_step; o << "\n"; } o << string_t(new_indent, ' ') + "}"; return; } case value_t::array: { if (m_value.array->empty()) { o << "[]"; return; } o << "["; // increase indentation if (pretty_print) { new_indent += indent_step; o << "\n"; } for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) { if (i != m_value.array->cbegin()) { o << (pretty_print ? ",\n" : ","); } o << string_t(new_indent, ' '); i->dump(o, pretty_print, indent_step, new_indent); } // decrease indentation if (pretty_print) { new_indent -= indent_step; o << "\n"; } o << string_t(new_indent, ' ') << "]"; return; } case value_t::string: { o << string_t("\"") << escape_string(*m_value.string) << "\""; return; } case value_t::boolean: { o << (m_value.boolean ? "true" : "false"); return; } case value_t::number_integer: { o << m_value.number_integer; return; } case value_t::number_unsigned: { o << m_value.number_unsigned; return; } case value_t::number_float: { if (m_value.number_float == 0) { // special case for zero to get "0.0"/"-0.0" o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0"); } else { o << m_value.number_float; } return; } case value_t::discarded: { o << ""; return; } case value_t::null: { o << "null"; return; } } } private: ////////////////////// // member variables // ////////////////////// /// the type of the current element value_t m_type = value_t::null; /// the value of the current element json_value m_value = {}; private: /////////////// // iterators // /////////////// /*! @brief an iterator for primitive JSON types This class models an iterator for primitive JSON types (boolean, number, string). It's only purpose is to allow the iterator/const_iterator classes to "iterate" over primitive values. Internally, the iterator is modeled by a `difference_type` variable. Value begin_value (`0`) models the begin, end_value (`1`) models past the end. */ class primitive_iterator_t { public: /// set iterator to a defined beginning void set_begin() noexcept { m_it = begin_value; } /// set iterator to a defined past the end void set_end() noexcept { m_it = end_value; } /// return whether the iterator can be dereferenced constexpr bool is_begin() const noexcept { return (m_it == begin_value); } /// return whether the iterator is at end constexpr bool is_end() const noexcept { return (m_it == end_value); } /// return reference to the value to change and compare operator difference_type& () noexcept { return m_it; } /// return value to compare constexpr operator difference_type () const noexcept { return m_it; } private: static constexpr difference_type begin_value = 0; static constexpr difference_type end_value = begin_value + 1; /// iterator as signed integer type difference_type m_it = std::numeric_limits::denorm_min(); }; /*! @brief an iterator value @note This structure could easily be a union, but MSVC currently does not allow unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. */ struct internal_iterator { /// iterator for JSON objects typename object_t::iterator object_iterator; /// iterator for JSON arrays typename array_t::iterator array_iterator; /// generic iterator for all other types primitive_iterator_t primitive_iterator; /// create an uninitialized internal_iterator internal_iterator() noexcept : object_iterator(), array_iterator(), primitive_iterator() {} }; /// proxy class for the iterator_wrapper functions template class iteration_proxy { private: /// helper class for iteration class iteration_proxy_internal { private: /// the iterator IteratorType anchor; /// an index for arrays (used to create key names) size_t array_index = 0; public: explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} /// dereference operator (needed for range-based for) iteration_proxy_internal& operator*() { return *this; } /// increment operator (needed for range-based for) iteration_proxy_internal& operator++() { ++anchor; ++array_index; return *this; } /// inequality operator (needed for range-based for) bool operator!= (const iteration_proxy_internal& o) const { return anchor != o.anchor; } /// return key of the iterator typename basic_json::string_t key() const { assert(anchor.m_object != nullptr); switch (anchor.m_object->type()) { // use integer array index as key case value_t::array: { return std::to_string(array_index); } // use key from the object case value_t::object: { return anchor.key(); } // use an empty key for all primitive types default: { return ""; } } } /// return value of the iterator typename IteratorType::reference value() const { return anchor.value(); } }; /// the container to iterate typename IteratorType::reference container; public: /// construct iteration proxy from a container explicit iteration_proxy(typename IteratorType::reference cont) : container(cont) {} /// return iterator begin (needed for range-based for) iteration_proxy_internal begin() noexcept { return iteration_proxy_internal(container.begin()); } /// return iterator end (needed for range-based for) iteration_proxy_internal end() noexcept { return iteration_proxy_internal(container.end()); } }; public: /*! @brief a const random access iterator for the @ref basic_json class This class implements a const iterator for the @ref basic_json class. From this class, the @ref iterator class is derived. @note An iterator is called *initialized* when a pointer to a JSON value has been set (e.g., by a constructor or a copy assignment). If the iterator is default-constructed, it is *uninitialized* and most methods are undefined. **The library uses assertions to detect calls on uninitialized iterators.** @requirement The class satisfies the following concept requirements: - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): The iterator that can be moved to point (forward and backward) to any element in constant time. @since version 1.0.0 */ class const_iterator : public std::iterator { /// allow basic_json to access private members friend class basic_json; public: /// the type of the values when the iterator is dereferenced using value_type = typename basic_json::value_type; /// a type to represent differences between iterators using difference_type = typename basic_json::difference_type; /// defines a pointer to the type iterated over (value_type) using pointer = typename basic_json::const_pointer; /// defines a reference to the type iterated over (value_type) using reference = typename basic_json::const_reference; /// the category of the iterator using iterator_category = std::bidirectional_iterator_tag; /// default constructor const_iterator() = default; /*! @brief constructor for a given JSON instance @param[in] object pointer to a JSON object for this iterator @pre object != nullptr @post The iterator is initialized; i.e. `m_object != nullptr`. */ explicit const_iterator(pointer object) noexcept : m_object(object) { assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { m_it.object_iterator = typename object_t::iterator(); break; } case basic_json::value_t::array: { m_it.array_iterator = typename array_t::iterator(); break; } default: { m_it.primitive_iterator = primitive_iterator_t(); break; } } } /*! @brief copy constructor given a non-const iterator @param[in] other iterator to copy from @note It is not checked whether @a other is initialized. */ explicit const_iterator(const iterator& other) noexcept : m_object(other.m_object) { if (m_object != nullptr) { switch (m_object->m_type) { case basic_json::value_t::object: { m_it.object_iterator = other.m_it.object_iterator; break; } case basic_json::value_t::array: { m_it.array_iterator = other.m_it.array_iterator; break; } default: { m_it.primitive_iterator = other.m_it.primitive_iterator; break; } } } } /*! @brief copy constructor @param[in] other iterator to copy from @note It is not checked whether @a other is initialized. */ const_iterator(const const_iterator& other) noexcept : m_object(other.m_object), m_it(other.m_it) {} /*! @brief copy assignment @param[in,out] other iterator to copy from @note It is not checked whether @a other is initialized. */ const_iterator& operator=(const_iterator other) noexcept( std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value ) { std::swap(m_object, other.m_object); std::swap(m_it, other.m_it); return *this; } private: /*! @brief set the iterator to the first value @pre The iterator is initialized; i.e. `m_object != nullptr`. */ void set_begin() noexcept { assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { m_it.object_iterator = m_object->m_value.object->begin(); break; } case basic_json::value_t::array: { m_it.array_iterator = m_object->m_value.array->begin(); break; } case basic_json::value_t::null: { // set to end so begin()==end() is true: null is empty m_it.primitive_iterator.set_end(); break; } default: { m_it.primitive_iterator.set_begin(); break; } } } /*! @brief set the iterator past the last value @pre The iterator is initialized; i.e. `m_object != nullptr`. */ void set_end() noexcept { assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { m_it.object_iterator = m_object->m_value.object->end(); break; } case basic_json::value_t::array: { m_it.array_iterator = m_object->m_value.array->end(); break; } default: { m_it.primitive_iterator.set_end(); break; } } } public: /*! @brief return a reference to the value pointed to by the iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ reference operator*() const { assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { assert(m_it.object_iterator != m_object->m_value.object->end()); return m_it.object_iterator->second; } case basic_json::value_t::array: { assert(m_it.array_iterator != m_object->m_value.array->end()); return *m_it.array_iterator; } case basic_json::value_t::null: { throw std::out_of_range("cannot get value"); } default: { if (m_it.primitive_iterator.is_begin()) { return *m_object; } else { throw std::out_of_range("cannot get value"); } } } } /*! @brief dereference the iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ pointer operator->() const { assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { assert(m_it.object_iterator != m_object->m_value.object->end()); return &(m_it.object_iterator->second); } case basic_json::value_t::array: { assert(m_it.array_iterator != m_object->m_value.array->end()); return &*m_it.array_iterator; } default: { if (m_it.primitive_iterator.is_begin()) { return m_object; } else { throw std::out_of_range("cannot get value"); } } } } /*! @brief post-increment (it++) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ const_iterator operator++(int) { auto result = *this; ++(*this); return result; } /*! @brief pre-increment (++it) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ const_iterator& operator++() { assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { std::advance(m_it.object_iterator, 1); break; } case basic_json::value_t::array: { std::advance(m_it.array_iterator, 1); break; } default: { ++m_it.primitive_iterator; break; } } return *this; } /*! @brief post-decrement (it--) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ const_iterator operator--(int) { auto result = *this; --(*this); return result; } /*! @brief pre-decrement (--it) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ const_iterator& operator--() { assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { std::advance(m_it.object_iterator, -1); break; } case basic_json::value_t::array: { std::advance(m_it.array_iterator, -1); break; } default: { --m_it.primitive_iterator; break; } } return *this; } /*! @brief comparison: equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ bool operator==(const const_iterator& other) const { // if objects are not the same, the comparison is undefined if (m_object != other.m_object) { throw std::domain_error("cannot compare iterators of different containers"); } assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { return (m_it.object_iterator == other.m_it.object_iterator); } case basic_json::value_t::array: { return (m_it.array_iterator == other.m_it.array_iterator); } default: { return (m_it.primitive_iterator == other.m_it.primitive_iterator); } } } /*! @brief comparison: not equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ bool operator!=(const const_iterator& other) const { return not operator==(other); } /*! @brief comparison: smaller @pre The iterator is initialized; i.e. `m_object != nullptr`. */ bool operator<(const const_iterator& other) const { // if objects are not the same, the comparison is undefined if (m_object != other.m_object) { throw std::domain_error("cannot compare iterators of different containers"); } assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { throw std::domain_error("cannot compare order of object iterators"); } case basic_json::value_t::array: { return (m_it.array_iterator < other.m_it.array_iterator); } default: { return (m_it.primitive_iterator < other.m_it.primitive_iterator); } } } /*! @brief comparison: less than or equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ bool operator<=(const const_iterator& other) const { return not other.operator < (*this); } /*! @brief comparison: greater than @pre The iterator is initialized; i.e. `m_object != nullptr`. */ bool operator>(const const_iterator& other) const { return not operator<=(other); } /*! @brief comparison: greater than or equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ bool operator>=(const const_iterator& other) const { return not operator<(other); } /*! @brief add to iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ const_iterator& operator+=(difference_type i) { assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { throw std::domain_error("cannot use offsets with object iterators"); } case basic_json::value_t::array: { std::advance(m_it.array_iterator, i); break; } default: { m_it.primitive_iterator += i; break; } } return *this; } /*! @brief subtract from iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ const_iterator& operator-=(difference_type i) { return operator+=(-i); } /*! @brief add to iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ const_iterator operator+(difference_type i) { auto result = *this; result += i; return result; } /*! @brief subtract from iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ const_iterator operator-(difference_type i) { auto result = *this; result -= i; return result; } /*! @brief return difference @pre The iterator is initialized; i.e. `m_object != nullptr`. */ difference_type operator-(const const_iterator& other) const { assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { throw std::domain_error("cannot use offsets with object iterators"); } case basic_json::value_t::array: { return m_it.array_iterator - other.m_it.array_iterator; } default: { return m_it.primitive_iterator - other.m_it.primitive_iterator; } } } /*! @brief access to successor @pre The iterator is initialized; i.e. `m_object != nullptr`. */ reference operator[](difference_type n) const { assert(m_object != nullptr); switch (m_object->m_type) { case basic_json::value_t::object: { throw std::domain_error("cannot use operator[] for object iterators"); } case basic_json::value_t::array: { return *std::next(m_it.array_iterator, n); } case basic_json::value_t::null: { throw std::out_of_range("cannot get value"); } default: { if (m_it.primitive_iterator == -n) { return *m_object; } else { throw std::out_of_range("cannot get value"); } } } } /*! @brief return the key of an object iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ typename object_t::key_type key() const { assert(m_object != nullptr); if (m_object->is_object()) { return m_it.object_iterator->first; } else { throw std::domain_error("cannot use key() for non-object iterators"); } } /*! @brief return the value of an iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ reference value() const { return operator*(); } private: /// associated JSON instance pointer m_object = nullptr; /// the actual iterator of the associated instance internal_iterator m_it = internal_iterator(); }; /*! @brief a mutable random access iterator for the @ref basic_json class @requirement The class satisfies the following concept requirements: - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): The iterator that can be moved to point (forward and backward) to any element in constant time. - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): It is possible to write to the pointed-to element. @since version 1.0.0 */ class iterator : public const_iterator { public: using base_iterator = const_iterator; using pointer = typename basic_json::pointer; using reference = typename basic_json::reference; /// default constructor iterator() = default; /// constructor for a given JSON instance explicit iterator(pointer object) noexcept : base_iterator(object) {} /// copy constructor iterator(const iterator& other) noexcept : base_iterator(other) {} /// copy assignment iterator& operator=(iterator other) noexcept( std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value ) { base_iterator::operator=(other); return *this; } /// return a reference to the value pointed to by the iterator reference operator*() const { return const_cast(base_iterator::operator*()); } /// dereference the iterator pointer operator->() const { return const_cast(base_iterator::operator->()); } /// post-increment (it++) iterator operator++(int) { iterator result = *this; base_iterator::operator++(); return result; } /// pre-increment (++it) iterator& operator++() { base_iterator::operator++(); return *this; } /// post-decrement (it--) iterator operator--(int) { iterator result = *this; base_iterator::operator--(); return result; } /// pre-decrement (--it) iterator& operator--() { base_iterator::operator--(); return *this; } /// add to iterator iterator& operator+=(difference_type i) { base_iterator::operator+=(i); return *this; } /// subtract from iterator iterator& operator-=(difference_type i) { base_iterator::operator-=(i); return *this; } /// add to iterator iterator operator+(difference_type i) { auto result = *this; result += i; return result; } /// subtract from iterator iterator operator-(difference_type i) { auto result = *this; result -= i; return result; } /// return difference difference_type operator-(const iterator& other) const { return base_iterator::operator-(other); } /// access to successor reference operator[](difference_type n) const { return const_cast(base_iterator::operator[](n)); } /// return the value of an iterator reference value() const { return const_cast(base_iterator::value()); } }; /*! @brief a template for a reverse iterator class @tparam Base the base iterator type to reverse. Valid types are @ref iterator (to create @ref reverse_iterator) and @ref const_iterator (to create @ref const_reverse_iterator). @requirement The class satisfies the following concept requirements: - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): The iterator that can be moved to point (forward and backward) to any element in constant time. - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): It is possible to write to the pointed-to element (only if @a Base is @ref iterator). @since version 1.0.0 */ template class json_reverse_iterator : public std::reverse_iterator { public: /// shortcut to the reverse iterator adaptor using base_iterator = std::reverse_iterator; /// the reference type for the pointed-to element using reference = typename Base::reference; /// create reverse iterator from iterator json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept : base_iterator(it) {} /// create reverse iterator from base class json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} /// post-increment (it++) json_reverse_iterator operator++(int) { return base_iterator::operator++(1); } /// pre-increment (++it) json_reverse_iterator& operator++() { base_iterator::operator++(); return *this; } /// post-decrement (it--) json_reverse_iterator operator--(int) { return base_iterator::operator--(1); } /// pre-decrement (--it) json_reverse_iterator& operator--() { base_iterator::operator--(); return *this; } /// add to iterator json_reverse_iterator& operator+=(difference_type i) { base_iterator::operator+=(i); return *this; } /// add to iterator json_reverse_iterator operator+(difference_type i) const { auto result = *this; result += i; return result; } /// subtract from iterator json_reverse_iterator operator-(difference_type i) const { auto result = *this; result -= i; return result; } /// return difference difference_type operator-(const json_reverse_iterator& other) const { return this->base() - other.base(); } /// access to successor reference operator[](difference_type n) const { return *(this->operator+(n)); } /// return the key of an object iterator typename object_t::key_type key() const { auto it = --this->base(); return it.key(); } /// return the value of an iterator reference value() const { auto it = --this->base(); return it.operator * (); } }; private: ////////////////////// // lexer and parser // ////////////////////// /*! @brief lexical analysis This class organizes the lexical analysis during JSON deserialization. The core of it is a scanner generated by [re2c](http://re2c.org) that processes a buffer and recognizes tokens according to RFC 7159. */ class lexer { public: /// token types for the parser enum class token_type { uninitialized, ///< indicating the scanner is uninitialized literal_true, ///< the `true` literal literal_false, ///< the `false` literal literal_null, ///< the `null` literal value_string, ///< a string -- use get_string() for actual value value_number, ///< a number -- use get_number() for actual value begin_array, ///< the character for array begin `[` begin_object, ///< the character for object begin `{` end_array, ///< the character for array end `]` end_object, ///< the character for object end `}` name_separator, ///< the name separator `:` value_separator, ///< the value separator `,` parse_error, ///< indicating a parse error end_of_input ///< indicating the end of the input buffer }; /// the char type to use in the lexer using lexer_char_t = unsigned char; /// constructor with a given buffer explicit lexer(const string_t& s) noexcept : m_stream(nullptr), m_buffer(s) { m_content = reinterpret_cast(m_buffer.c_str()); assert(m_content != nullptr); m_start = m_cursor = m_content; m_limit = m_content + s.size(); } /// constructor with a given stream explicit lexer(std::istream* s) noexcept : m_stream(s), m_buffer() { assert(m_stream != nullptr); std::getline(*m_stream, m_buffer); m_content = reinterpret_cast(m_buffer.c_str()); assert(m_content != nullptr); m_start = m_cursor = m_content; m_limit = m_content + m_buffer.size(); } /// default constructor lexer() = default; // switch off unwanted functions lexer(const lexer&) = delete; lexer operator=(const lexer&) = delete; /*! @brief create a string from one or two Unicode code points There are two cases: (1) @a codepoint1 is in the Basic Multilingual Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2) @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to represent a code point above U+FFFF. @param[in] codepoint1 the code point (can be high surrogate) @param[in] codepoint2 the code point (can be low surrogate or 0) @return string representation of the code point; the length of the result string is between 1 and 4 characters. @throw std::out_of_range if code point is > 0x10ffff; example: `"code points above 0x10FFFF are invalid"` @throw std::invalid_argument if the low surrogate is invalid; example: `""missing or wrong low surrogate""` @complexity Constant. @see */ static string_t to_unicode(const std::size_t codepoint1, const std::size_t codepoint2 = 0) { // calculate the code point from the given code points std::size_t codepoint = codepoint1; // check if codepoint1 is a high surrogate if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) { // check if codepoint2 is a low surrogate if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) { codepoint = // high surrogate occupies the most significant 22 bits (codepoint1 << 10) // low surrogate occupies the least significant 15 bits + codepoint2 // there is still the 0xD800, 0xDC00 and 0x10000 noise // in the result so we have to subtract with: // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - 0x35FDC00; } else { throw std::invalid_argument("missing or wrong low surrogate"); } } string_t result; if (codepoint < 0x80) { // 1-byte characters: 0xxxxxxx (ASCII) result.append(1, static_cast(codepoint)); } else if (codepoint <= 0x7ff) { // 2-byte characters: 110xxxxx 10xxxxxx result.append(1, static_cast(0xC0 | ((codepoint >> 6) & 0x1F))); result.append(1, static_cast(0x80 | (codepoint & 0x3F))); } else if (codepoint <= 0xffff) { // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx result.append(1, static_cast(0xE0 | ((codepoint >> 12) & 0x0F))); result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); result.append(1, static_cast(0x80 | (codepoint & 0x3F))); } else if (codepoint <= 0x10ffff) { // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx result.append(1, static_cast(0xF0 | ((codepoint >> 18) & 0x07))); result.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); result.append(1, static_cast(0x80 | (codepoint & 0x3F))); } else { throw std::out_of_range("code points above 0x10FFFF are invalid"); } return result; } /// return name of values of type token_type (only used for errors) static std::string token_type_name(const token_type t) { switch (t) { case token_type::uninitialized: return ""; case token_type::literal_true: return "true literal"; case token_type::literal_false: return "false literal"; case token_type::literal_null: return "null literal"; case token_type::value_string: return "string literal"; case token_type::value_number: return "number literal"; case token_type::begin_array: return "'['"; case token_type::begin_object: return "'{'"; case token_type::end_array: return "']'"; case token_type::end_object: return "'}'"; case token_type::name_separator: return "':'"; case token_type::value_separator: return "','"; case token_type::parse_error: return ""; case token_type::end_of_input: return "end of input"; default: { // catch non-enum values return "unknown token"; // LCOV_EXCL_LINE } } } /*! This function implements a scanner for JSON. It is specified using regular expressions that try to follow RFC 7159 as close as possible. These regular expressions are then translated into a minimized deterministic finite automaton (DFA) by the tool [re2c](http://re2c.org). As a result, the translated code for this function consists of a large block of code with `goto` jumps. @return the class of the next token read from the buffer @complexity Linear in the length of the input.\n Proposition: The loop below will always terminate for finite input.\n Proof (by contradiction): Assume a finite input. To loop forever, the loop must never hit code with a `break` statement. The only code snippets without a `break` statement are the continue statements for whitespace and byte-order-marks. To loop forever, the input must be an infinite sequence of whitespace or byte-order-marks. This contradicts the assumption of finite input, q.e.d. */ token_type scan() noexcept { while (true) { // pointer for backtracking information m_marker = nullptr; // remember the begin of the token m_start = m_cursor; assert(m_start != nullptr); { lexer_char_t yych; unsigned int yyaccept = 0; static const unsigned char yybm[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 128, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, }; if ((m_limit - m_cursor) < 5) { yyfill(); } yych = *m_cursor; if (yybm[0 + yych] & 32) { goto basic_json_parser_6; } if (yych <= '\\') { if (yych <= '-') { if (yych <= '"') { if (yych <= 0x00) { goto basic_json_parser_2; } if (yych <= '!') { goto basic_json_parser_4; } goto basic_json_parser_9; } else { if (yych <= '+') { goto basic_json_parser_4; } if (yych <= ',') { goto basic_json_parser_10; } goto basic_json_parser_12; } } else { if (yych <= '9') { if (yych <= '/') { goto basic_json_parser_4; } if (yych <= '0') { goto basic_json_parser_13; } goto basic_json_parser_15; } else { if (yych <= ':') { goto basic_json_parser_17; } if (yych == '[') { goto basic_json_parser_19; } goto basic_json_parser_4; } } } else { if (yych <= 't') { if (yych <= 'f') { if (yych <= ']') { goto basic_json_parser_21; } if (yych <= 'e') { goto basic_json_parser_4; } goto basic_json_parser_23; } else { if (yych == 'n') { goto basic_json_parser_24; } if (yych <= 's') { goto basic_json_parser_4; } goto basic_json_parser_25; } } else { if (yych <= '|') { if (yych == '{') { goto basic_json_parser_26; } goto basic_json_parser_4; } else { if (yych <= '}') { goto basic_json_parser_28; } if (yych == 0xEF) { goto basic_json_parser_30; } goto basic_json_parser_4; } } } basic_json_parser_2: ++m_cursor; { last_token_type = token_type::end_of_input; break; } basic_json_parser_4: ++m_cursor; basic_json_parser_5: { last_token_type = token_type::parse_error; break; } basic_json_parser_6: ++m_cursor; if (m_limit <= m_cursor) { yyfill(); } yych = *m_cursor; if (yybm[0 + yych] & 32) { goto basic_json_parser_6; } { continue; } basic_json_parser_9: yyaccept = 0; yych = *(m_marker = ++m_cursor); if (yych <= 0x1F) { goto basic_json_parser_5; } goto basic_json_parser_32; basic_json_parser_10: ++m_cursor; { last_token_type = token_type::value_separator; break; } basic_json_parser_12: yych = *++m_cursor; if (yych <= '/') { goto basic_json_parser_5; } if (yych <= '0') { goto basic_json_parser_13; } if (yych <= '9') { goto basic_json_parser_15; } goto basic_json_parser_5; basic_json_parser_13: yyaccept = 1; yych = *(m_marker = ++m_cursor); if (yych <= 'D') { if (yych == '.') { goto basic_json_parser_37; } } else { if (yych <= 'E') { goto basic_json_parser_38; } if (yych == 'e') { goto basic_json_parser_38; } } basic_json_parser_14: { last_token_type = token_type::value_number; break; } basic_json_parser_15: yyaccept = 1; m_marker = ++m_cursor; if ((m_limit - m_cursor) < 3) { yyfill(); } yych = *m_cursor; if (yybm[0 + yych] & 64) { goto basic_json_parser_15; } if (yych <= 'D') { if (yych == '.') { goto basic_json_parser_37; } goto basic_json_parser_14; } else { if (yych <= 'E') { goto basic_json_parser_38; } if (yych == 'e') { goto basic_json_parser_38; } goto basic_json_parser_14; } basic_json_parser_17: ++m_cursor; { last_token_type = token_type::name_separator; break; } basic_json_parser_19: ++m_cursor; { last_token_type = token_type::begin_array; break; } basic_json_parser_21: ++m_cursor; { last_token_type = token_type::end_array; break; } basic_json_parser_23: yyaccept = 0; yych = *(m_marker = ++m_cursor); if (yych == 'a') { goto basic_json_parser_39; } goto basic_json_parser_5; basic_json_parser_24: yyaccept = 0; yych = *(m_marker = ++m_cursor); if (yych == 'u') { goto basic_json_parser_40; } goto basic_json_parser_5; basic_json_parser_25: yyaccept = 0; yych = *(m_marker = ++m_cursor); if (yych == 'r') { goto basic_json_parser_41; } goto basic_json_parser_5; basic_json_parser_26: ++m_cursor; { last_token_type = token_type::begin_object; break; } basic_json_parser_28: ++m_cursor; { last_token_type = token_type::end_object; break; } basic_json_parser_30: yyaccept = 0; yych = *(m_marker = ++m_cursor); if (yych == 0xBB) { goto basic_json_parser_42; } goto basic_json_parser_5; basic_json_parser_31: ++m_cursor; if (m_limit <= m_cursor) { yyfill(); } yych = *m_cursor; basic_json_parser_32: if (yybm[0 + yych] & 128) { goto basic_json_parser_31; } if (yych <= 0x1F) { goto basic_json_parser_33; } if (yych <= '"') { goto basic_json_parser_34; } goto basic_json_parser_36; basic_json_parser_33: m_cursor = m_marker; if (yyaccept == 0) { goto basic_json_parser_5; } else { goto basic_json_parser_14; } basic_json_parser_34: ++m_cursor; { last_token_type = token_type::value_string; break; } basic_json_parser_36: ++m_cursor; if (m_limit <= m_cursor) { yyfill(); } yych = *m_cursor; if (yych <= 'e') { if (yych <= '/') { if (yych == '"') { goto basic_json_parser_31; } if (yych <= '.') { goto basic_json_parser_33; } goto basic_json_parser_31; } else { if (yych <= '\\') { if (yych <= '[') { goto basic_json_parser_33; } goto basic_json_parser_31; } else { if (yych == 'b') { goto basic_json_parser_31; } goto basic_json_parser_33; } } } else { if (yych <= 'q') { if (yych <= 'f') { goto basic_json_parser_31; } if (yych == 'n') { goto basic_json_parser_31; } goto basic_json_parser_33; } else { if (yych <= 's') { if (yych <= 'r') { goto basic_json_parser_31; } goto basic_json_parser_33; } else { if (yych <= 't') { goto basic_json_parser_31; } if (yych <= 'u') { goto basic_json_parser_43; } goto basic_json_parser_33; } } } basic_json_parser_37: yych = *++m_cursor; if (yych <= '/') { goto basic_json_parser_33; } if (yych <= '9') { goto basic_json_parser_44; } goto basic_json_parser_33; basic_json_parser_38: yych = *++m_cursor; if (yych <= ',') { if (yych == '+') { goto basic_json_parser_46; } goto basic_json_parser_33; } else { if (yych <= '-') { goto basic_json_parser_46; } if (yych <= '/') { goto basic_json_parser_33; } if (yych <= '9') { goto basic_json_parser_47; } goto basic_json_parser_33; } basic_json_parser_39: yych = *++m_cursor; if (yych == 'l') { goto basic_json_parser_49; } goto basic_json_parser_33; basic_json_parser_40: yych = *++m_cursor; if (yych == 'l') { goto basic_json_parser_50; } goto basic_json_parser_33; basic_json_parser_41: yych = *++m_cursor; if (yych == 'u') { goto basic_json_parser_51; } goto basic_json_parser_33; basic_json_parser_42: yych = *++m_cursor; if (yych == 0xBF) { goto basic_json_parser_52; } goto basic_json_parser_33; basic_json_parser_43: ++m_cursor; if (m_limit <= m_cursor) { yyfill(); } yych = *m_cursor; if (yych <= '@') { if (yych <= '/') { goto basic_json_parser_33; } if (yych <= '9') { goto basic_json_parser_54; } goto basic_json_parser_33; } else { if (yych <= 'F') { goto basic_json_parser_54; } if (yych <= '`') { goto basic_json_parser_33; } if (yych <= 'f') { goto basic_json_parser_54; } goto basic_json_parser_33; } basic_json_parser_44: yyaccept = 1; m_marker = ++m_cursor; if ((m_limit - m_cursor) < 3) { yyfill(); } yych = *m_cursor; if (yych <= 'D') { if (yych <= '/') { goto basic_json_parser_14; } if (yych <= '9') { goto basic_json_parser_44; } goto basic_json_parser_14; } else { if (yych <= 'E') { goto basic_json_parser_38; } if (yych == 'e') { goto basic_json_parser_38; } goto basic_json_parser_14; } basic_json_parser_46: yych = *++m_cursor; if (yych <= '/') { goto basic_json_parser_33; } if (yych >= ':') { goto basic_json_parser_33; } basic_json_parser_47: ++m_cursor; if (m_limit <= m_cursor) { yyfill(); } yych = *m_cursor; if (yych <= '/') { goto basic_json_parser_14; } if (yych <= '9') { goto basic_json_parser_47; } goto basic_json_parser_14; basic_json_parser_49: yych = *++m_cursor; if (yych == 's') { goto basic_json_parser_55; } goto basic_json_parser_33; basic_json_parser_50: yych = *++m_cursor; if (yych == 'l') { goto basic_json_parser_56; } goto basic_json_parser_33; basic_json_parser_51: yych = *++m_cursor; if (yych == 'e') { goto basic_json_parser_58; } goto basic_json_parser_33; basic_json_parser_52: ++m_cursor; { continue; } basic_json_parser_54: ++m_cursor; if (m_limit <= m_cursor) { yyfill(); } yych = *m_cursor; if (yych <= '@') { if (yych <= '/') { goto basic_json_parser_33; } if (yych <= '9') { goto basic_json_parser_60; } goto basic_json_parser_33; } else { if (yych <= 'F') { goto basic_json_parser_60; } if (yych <= '`') { goto basic_json_parser_33; } if (yych <= 'f') { goto basic_json_parser_60; } goto basic_json_parser_33; } basic_json_parser_55: yych = *++m_cursor; if (yych == 'e') { goto basic_json_parser_61; } goto basic_json_parser_33; basic_json_parser_56: ++m_cursor; { last_token_type = token_type::literal_null; break; } basic_json_parser_58: ++m_cursor; { last_token_type = token_type::literal_true; break; } basic_json_parser_60: ++m_cursor; if (m_limit <= m_cursor) { yyfill(); } yych = *m_cursor; if (yych <= '@') { if (yych <= '/') { goto basic_json_parser_33; } if (yych <= '9') { goto basic_json_parser_63; } goto basic_json_parser_33; } else { if (yych <= 'F') { goto basic_json_parser_63; } if (yych <= '`') { goto basic_json_parser_33; } if (yych <= 'f') { goto basic_json_parser_63; } goto basic_json_parser_33; } basic_json_parser_61: ++m_cursor; { last_token_type = token_type::literal_false; break; } basic_json_parser_63: ++m_cursor; if (m_limit <= m_cursor) { yyfill(); } yych = *m_cursor; if (yych <= '@') { if (yych <= '/') { goto basic_json_parser_33; } if (yych <= '9') { goto basic_json_parser_31; } goto basic_json_parser_33; } else { if (yych <= 'F') { goto basic_json_parser_31; } if (yych <= '`') { goto basic_json_parser_33; } if (yych <= 'f') { goto basic_json_parser_31; } goto basic_json_parser_33; } } } return last_token_type; } /// append data from the stream to the internal buffer void yyfill() noexcept { if (m_stream == nullptr or not * m_stream) { return; } const auto offset_start = m_start - m_content; const auto offset_marker = m_marker - m_start; const auto offset_cursor = m_cursor - m_start; m_buffer.erase(0, static_cast(offset_start)); std::string line; assert(m_stream != nullptr); std::getline(*m_stream, line); m_buffer += "\n" + line; // add line with newline symbol m_content = reinterpret_cast(m_buffer.c_str()); assert(m_content != nullptr); m_start = m_content; m_marker = m_start + offset_marker; m_cursor = m_start + offset_cursor; m_limit = m_start + m_buffer.size() - 1; } /// return string representation of last read token string_t get_token_string() const { assert(m_start != nullptr); return string_t(reinterpret_cast(m_start), static_cast(m_cursor - m_start)); } /*! @brief return string value for string tokens The function iterates the characters between the opening and closing quotes of the string value. The complete string is the range [m_start,m_cursor). Consequently, we iterate from m_start+1 to m_cursor-1. We differentiate two cases: 1. Escaped characters. In this case, a new character is constructed according to the nature of the escape. Some escapes create new characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape `"\\uxxxx"` need special care. In this case, to_unicode takes care of the construction of the values. 2. Unescaped characters are copied as is. @pre `m_cursor - m_start >= 2`, meaning the length of the last token is at least 2 bytes which is trivially true for any string (which consists of at least two quotes). " c1 c2 c3 ... " ^ ^ m_start m_cursor @complexity Linear in the length of the string.\n Lemma: The loop body will always terminate.\n Proof (by contradiction): Assume the loop body does not terminate. As the loop body does not contain another loop, one of the called functions must never return. The called functions are `std::strtoul` and to_unicode. Neither function can loop forever, so the loop body will never loop forever which contradicts the assumption that the loop body does not terminate, q.e.d.\n Lemma: The loop condition for the for loop is eventually false.\n Proof (by contradiction): Assume the loop does not terminate. Due to the above lemma, this can only be due to a tautological loop condition; that is, the loop condition i < m_cursor - 1 must always be true. Let x be the change of i for any loop iteration. Then m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This can be rephrased to m_cursor - m_start - 2 > x. With the precondition, we x <= 0, meaning that the loop condition holds indefinitly if i is always decreased. However, observe that the value of i is strictly increasing with each iteration, as it is incremented by 1 in the iteration expression and never decremented inside the loop body. Hence, the loop condition will eventually be false which contradicts the assumption that the loop condition is a tautology, q.e.d. @return string value of current token without opening and closing quotes @throw std::out_of_range if to_unicode fails */ string_t get_string() const { assert(m_cursor - m_start >= 2); string_t result; result.reserve(static_cast(m_cursor - m_start - 2)); // iterate the result between the quotes for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) { // process escaped characters if (*i == '\\') { // read next character ++i; switch (*i) { // the default escapes case 't': { result += "\t"; break; } case 'b': { result += "\b"; break; } case 'f': { result += "\f"; break; } case 'n': { result += "\n"; break; } case 'r': { result += "\r"; break; } case '\\': { result += "\\"; break; } case '/': { result += "/"; break; } case '"': { result += "\""; break; } // unicode case 'u': { // get code xxxx from uxxxx auto codepoint = std::strtoul(std::string(reinterpret_cast(i + 1), 4).c_str(), nullptr, 16); // check if codepoint is a high surrogate if (codepoint >= 0xD800 and codepoint <= 0xDBFF) { // make sure there is a subsequent unicode if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') { throw std::invalid_argument("missing low surrogate"); } // get code yyyy from uxxxx\uyyyy auto codepoint2 = std::strtoul(std::string(reinterpret_cast (i + 7), 4).c_str(), nullptr, 16); result += to_unicode(codepoint, codepoint2); // skip the next 10 characters (xxxx\uyyyy) i += 10; } else { // add unicode character(s) result += to_unicode(codepoint); // skip the next four characters (xxxx) i += 4; } break; } } } else { // all other characters are just copied to the end of the // string result.append(1, static_cast(*i)); } } return result; } /*! @brief parse floating point number This function (and its overloads) serves to select the most approprate standard floating point number parsing function based on the type supplied via the first parameter. Set this to @a static_cast(nullptr). @param[in] type the @ref number_float_t in use @param[in,out] endptr recieves a pointer to the first character after the number @return the floating point number */ long double str_to_float_t(long double* /* type */, char** endptr) const { return std::strtold(reinterpret_cast(m_start), endptr); } /*! @brief parse floating point number This function (and its overloads) serves to select the most approprate standard floating point number parsing function based on the type supplied via the first parameter. Set this to @a static_cast(nullptr). @param[in] type the @ref number_float_t in use @param[in,out] endptr recieves a pointer to the first character after the number @return the floating point number */ double str_to_float_t(double* /* type */, char** endptr) const { return std::strtod(reinterpret_cast(m_start), endptr); } /*! @brief parse floating point number This function (and its overloads) serves to select the most approprate standard floating point number parsing function based on the type supplied via the first parameter. Set this to @a static_cast(nullptr). @param[in] type the @ref number_float_t in use @param[in,out] endptr recieves a pointer to the first character after the number @return the floating point number */ float str_to_float_t(float* /* type */, char** endptr) const { return std::strtof(reinterpret_cast(m_start), endptr); } /*! @brief return number value for number tokens This function translates the last token into the most appropriate number type (either integer, unsigned integer or floating point), which is passed back to the caller via the result parameter. This function parses the integer component up to the radix point or exponent while collecting information about the 'floating point representation', which it stores in the result parameter. If there is no radix point or exponent, and the number can fit into a @ref number_integer_t or @ref number_unsigned_t then it sets the result parameter accordingly. If the number is a floating point number the number is then parsed using @a std:strtod (or @a std:strtof or @a std::strtold). @param[out] result @ref basic_json object to receive the number, or NAN if the conversion read past the current token. The latter case needs to be treated by the caller function. */ void get_number(basic_json& result) const { assert(m_start != nullptr); const lexer::lexer_char_t* curptr = m_start; // accumulate the integer conversion result (unsigned for now) number_unsigned_t value = 0; // maximum absolute value of the relevant integer type number_unsigned_t max; // temporarily store the type to avoid unecessary bitfield access value_t type; // look for sign if (*curptr == '-') { type = value_t::number_integer; max = static_cast((std::numeric_limits::max)()) + 1; curptr++; } else { type = value_t::number_unsigned; max = static_cast((std::numeric_limits::max)()); } // count the significant figures for (; curptr < m_cursor; curptr++) { // quickly skip tests if a digit if (*curptr < '0' || *curptr > '9') { if (*curptr == '.') { // don't count '.' but change to float type = value_t::number_float; continue; } // assume exponent (if not then will fail parse): change to // float, stop counting and record exponent details type = value_t::number_float; break; } // skip if definitely not an integer if (type != value_t::number_float) { // multiply last value by ten and add the new digit auto temp = value * 10 + *curptr - '0'; // test for overflow if (temp < value || temp > max) { // overflow type = value_t::number_float; } else { // no overflow - save it value = temp; } } } // save the value (if not a float) if (type == value_t::number_unsigned) { result.m_value.number_unsigned = value; } else if (type == value_t::number_integer) { result.m_value.number_integer = -static_cast(value); } else { // parse with strtod result.m_value.number_float = str_to_float_t(static_cast(nullptr), NULL); } // save the type result.m_type = type; } private: /// optional input stream std::istream* m_stream = nullptr; /// the buffer string_t m_buffer; /// the buffer pointer const lexer_char_t* m_content = nullptr; /// pointer to the beginning of the current symbol const lexer_char_t* m_start = nullptr; /// pointer for backtracking information const lexer_char_t* m_marker = nullptr; /// pointer to the current symbol const lexer_char_t* m_cursor = nullptr; /// pointer to the end of the buffer const lexer_char_t* m_limit = nullptr; /// the last token type token_type last_token_type = token_type::end_of_input; }; /*! @brief syntax analysis This class implements a recursive decent parser. */ class parser { public: /// constructor for strings parser(const string_t& s, const parser_callback_t cb = nullptr) noexcept : callback(cb), m_lexer(s) { // read first token get_token(); } /// a parser reading from an input stream parser(std::istream& _is, const parser_callback_t cb = nullptr) noexcept : callback(cb), m_lexer(&_is) { // read first token get_token(); } /// public parser interface basic_json parse() { basic_json result = parse_internal(true); result.assert_invariant(); expect(lexer::token_type::end_of_input); // return parser result and replace it with null in case the // top-level value was discarded by the callback function return result.is_discarded() ? basic_json() : std::move(result); } private: /// the actual parser basic_json parse_internal(bool keep) { auto result = basic_json(value_t::discarded); switch (last_token) { case lexer::token_type::begin_object: { if (keep and (not callback or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0))) { // explicitly set result to object to cope with {} result.m_type = value_t::object; result.m_value = value_t::object; } // read next token get_token(); // closing } -> we are done if (last_token == lexer::token_type::end_object) { get_token(); if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) { result = basic_json(value_t::discarded); } return result; } // no comma is expected here unexpect(lexer::token_type::value_separator); // otherwise: parse key-value pairs do { // ugly, but could be fixed with loop reorganization if (last_token == lexer::token_type::value_separator) { get_token(); } // store key expect(lexer::token_type::value_string); const auto key = m_lexer.get_string(); bool keep_tag = false; if (keep) { if (callback) { basic_json k(key); keep_tag = callback(depth, parse_event_t::key, k); } else { keep_tag = true; } } // parse separator (:) get_token(); expect(lexer::token_type::name_separator); // parse and add value get_token(); auto value = parse_internal(keep); if (keep and keep_tag and not value.is_discarded()) { result[key] = std::move(value); } } while (last_token == lexer::token_type::value_separator); // closing } expect(lexer::token_type::end_object); get_token(); if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) { result = basic_json(value_t::discarded); } return result; } case lexer::token_type::begin_array: { if (keep and (not callback or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0))) { // explicitly set result to object to cope with [] result.m_type = value_t::array; result.m_value = value_t::array; } // read next token get_token(); // closing ] -> we are done if (last_token == lexer::token_type::end_array) { get_token(); if (callback and not callback(--depth, parse_event_t::array_end, result)) { result = basic_json(value_t::discarded); } return result; } // no comma is expected here unexpect(lexer::token_type::value_separator); // otherwise: parse values do { // ugly, but could be fixed with loop reorganization if (last_token == lexer::token_type::value_separator) { get_token(); } // parse value auto value = parse_internal(keep); if (keep and not value.is_discarded()) { result.push_back(std::move(value)); } } while (last_token == lexer::token_type::value_separator); // closing ] expect(lexer::token_type::end_array); get_token(); if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) { result = basic_json(value_t::discarded); } return result; } case lexer::token_type::literal_null: { get_token(); result.m_type = value_t::null; break; } case lexer::token_type::value_string: { const auto s = m_lexer.get_string(); get_token(); result = basic_json(s); break; } case lexer::token_type::literal_true: { get_token(); result.m_type = value_t::boolean; result.m_value = true; break; } case lexer::token_type::literal_false: { get_token(); result.m_type = value_t::boolean; result.m_value = false; break; } case lexer::token_type::value_number: { m_lexer.get_number(result); get_token(); break; } default: { // the last token was unexpected unexpect(last_token); } } if (keep and callback and not callback(depth, parse_event_t::value, result)) { result = basic_json(value_t::discarded); } return result; } /// get next token from lexer typename lexer::token_type get_token() noexcept { last_token = m_lexer.scan(); return last_token; } void expect(typename lexer::token_type t) const { if (t != last_token) { std::string error_msg = "parse error - unexpected "; error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + "'") : lexer::token_type_name(last_token)); error_msg += "; expected " + lexer::token_type_name(t); throw std::invalid_argument(error_msg); } } void unexpect(typename lexer::token_type t) const { if (t == last_token) { std::string error_msg = "parse error - unexpected "; error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + "'") : lexer::token_type_name(last_token)); throw std::invalid_argument(error_msg); } } private: /// current level of recursion int depth = 0; /// callback function const parser_callback_t callback = nullptr; /// the type of the last read token typename lexer::token_type last_token = lexer::token_type::uninitialized; /// the lexer lexer m_lexer; }; public: /*! @brief JSON Pointer A JSON pointer defines a string syntax for identifying a specific value within a JSON document. It can be used with functions `at` and `operator[]`. Furthermore, JSON pointers are the base for JSON patches. @sa [RFC 6901](https://tools.ietf.org/html/rfc6901) @since version 2.0.0 */ class json_pointer { /// allow basic_json to access private members friend class basic_json; public: /*! @brief create JSON pointer Create a JSON pointer according to the syntax described in [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). @param[in] s string representing the JSON pointer; if omitted, the empty string is assumed which references the whole JSON value @throw std::domain_error if reference token is nonempty and does not begin with a slash (`/`); example: `"JSON pointer must be empty or begin with /"` @throw std::domain_error if a tilde (`~`) is not followed by `0` (representing `~`) or `1` (representing `/`); example: `"escape error: ~ must be followed with 0 or 1"` @liveexample{The example shows the construction several valid JSON pointers as well as the exceptional behavior.,json_pointer} @since version 2.0.0 */ explicit json_pointer(const std::string& s = "") : reference_tokens(split(s)) {} /*! @brief return a string representation of the JSON pointer @invariant For each JSON pointer `ptr`, it holds: @code {.cpp} ptr == json_pointer(ptr.to_string()); @endcode @return a string representation of the JSON pointer @liveexample{The example shows the result of `to_string`., json_pointer__to_string} @since version 2.0.0 */ std::string to_string() const noexcept { return std::accumulate(reference_tokens.begin(), reference_tokens.end(), std::string{}, [](const std::string & a, const std::string & b) { return a + "/" + escape(b); }); } /// @copydoc to_string() operator std::string() const { return to_string(); } private: /// remove and return last reference pointer std::string pop_back() { if (is_root()) { throw std::domain_error("JSON pointer has no parent"); } auto last = reference_tokens.back(); reference_tokens.pop_back(); return last; } /// return whether pointer points to the root document bool is_root() const { return reference_tokens.empty(); } json_pointer top() const { if (is_root()) { throw std::domain_error("JSON pointer has no parent"); } json_pointer result = *this; result.reference_tokens = {reference_tokens[0]}; return result; } /*! @brief create and return a reference to the pointed to value @complexity Linear in the number of reference tokens. */ reference get_and_create(reference j) const { pointer result = &j; // in case no reference tokens exist, return a reference to the // JSON value j which will be overwritten by a primitive value for (const auto& reference_token : reference_tokens) { switch (result->m_type) { case value_t::null: { if (reference_token == "0") { // start a new array if reference token is 0 result = &result->operator[](0); } else { // start a new object otherwise result = &result->operator[](reference_token); } break; } case value_t::object: { // create an entry in the object result = &result->operator[](reference_token); break; } case value_t::array: { // create an entry in the array result = &result->operator[](static_cast(std::stoi(reference_token))); break; } /* The following code is only reached if there exists a reference token _and_ the current value is primitive. In this case, we have an error situation, because primitive values may only occur as single value; that is, with an empty list of reference tokens. */ default: { throw std::domain_error("invalid value to unflatten"); } } } return *result; } /*! @brief return a reference to the pointed to value @param[in] ptr a JSON value @return reference to the JSON value pointed to by the JSON pointer @complexity Linear in the length of the JSON pointer. @throw std::out_of_range if the JSON pointer can not be resolved @throw std::domain_error if an array index begins with '0' @throw std::invalid_argument if an array index was not a number */ reference get_unchecked(pointer ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->m_type) { case value_t::object: { // use unchecked object access ptr = &ptr->operator[](reference_token); break; } case value_t::array: { // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { throw std::domain_error("array index must not begin with '0'"); } if (reference_token == "-") { // explicityly treat "-" as index beyond the end ptr = &ptr->operator[](ptr->m_value.array->size()); } else { // convert array index to number; unchecked access ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); } break; } default: { throw std::out_of_range("unresolved reference token '" + reference_token + "'"); } } } return *ptr; } reference get_checked(pointer ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->m_type) { case value_t::object: { // note: at performs range check ptr = &ptr->at(reference_token); break; } case value_t::array: { if (reference_token == "-") { // "-" always fails the range check throw std::out_of_range("array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range"); } // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { throw std::domain_error("array index must not begin with '0'"); } // note: at performs range check ptr = &ptr->at(static_cast(std::stoi(reference_token))); break; } default: { throw std::out_of_range("unresolved reference token '" + reference_token + "'"); } } } return *ptr; } /*! @brief return a const reference to the pointed to value @param[in] ptr a JSON value @return const reference to the JSON value pointed to by the JSON pointer */ const_reference get_unchecked(const_pointer ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->m_type) { case value_t::object: { // use unchecked object access ptr = &ptr->operator[](reference_token); break; } case value_t::array: { if (reference_token == "-") { // "-" cannot be used for const access throw std::out_of_range("array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range"); } // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { throw std::domain_error("array index must not begin with '0'"); } // use unchecked array access ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); break; } default: { throw std::out_of_range("unresolved reference token '" + reference_token + "'"); } } } return *ptr; } const_reference get_checked(const_pointer ptr) const { for (const auto& reference_token : reference_tokens) { switch (ptr->m_type) { case value_t::object: { // note: at performs range check ptr = &ptr->at(reference_token); break; } case value_t::array: { if (reference_token == "-") { // "-" always fails the range check throw std::out_of_range("array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range"); } // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { throw std::domain_error("array index must not begin with '0'"); } // note: at performs range check ptr = &ptr->at(static_cast(std::stoi(reference_token))); break; } default: { throw std::out_of_range("unresolved reference token '" + reference_token + "'"); } } } return *ptr; } /// split the string input to reference tokens static std::vector split(const std::string& reference_string) { std::vector result; // special case: empty reference string -> no reference tokens if (reference_string.empty()) { return result; } // check if nonempty reference string begins with slash if (reference_string[0] != '/') { throw std::domain_error("JSON pointer must be empty or begin with '/'"); } // extract the reference tokens: // - slash: position of the last read slash (or end of string) // - start: position after the previous slash for ( // search for the first slash after the first character size_t slash = reference_string.find_first_of("/", 1), // set the beginning of the first reference token start = 1; // we can stop if start == string::npos+1 = 0 start != 0; // set the beginning of the next reference token // (will eventually be 0 if slash == std::string::npos) start = slash + 1, // find next slash slash = reference_string.find_first_of("/", start)) { // use the text between the beginning of the reference token // (start) and the last slash (slash). auto reference_token = reference_string.substr(start, slash - start); // check reference tokens are properly escaped for (size_t pos = reference_token.find_first_of("~"); pos != std::string::npos; pos = reference_token.find_first_of("~", pos + 1)) { assert(reference_token[pos] == '~'); // ~ must be followed by 0 or 1 if (pos == reference_token.size() - 1 or (reference_token[pos + 1] != '0' and reference_token[pos + 1] != '1')) { throw std::domain_error("escape error: '~' must be followed with '0' or '1'"); } } // finally, store the reference token unescape(reference_token); result.push_back(reference_token); } return result; } private: /*! @brief replace all occurrences of a substring by another string @param[in,out] s the string to manipulate @param[in] f the substring to replace with @a t @param[in] t the string to replace @a f @return The string @a s where all occurrences of @a f are replaced with @a t. @pre The search string @a f must not be empty. @since version 2.0.0 */ static void replace_substring(std::string& s, const std::string& f, const std::string& t) { assert(not f.empty()); for ( size_t pos = s.find(f); // find first occurrence of f pos != std::string::npos; // make sure f was found s.replace(pos, f.size(), t), // replace with t pos = s.find(f, pos + t.size()) // find next occurrence of f ); } /// escape tilde and slash static std::string escape(std::string s) { // escape "~"" to "~0" and "/" to "~1" replace_substring(s, "~", "~0"); replace_substring(s, "/", "~1"); return s; } /// unescape tilde and slash static void unescape(std::string& s) { // first transform any occurrence of the sequence '~1' to '/' replace_substring(s, "~1", "/"); // then transform any occurrence of the sequence '~0' to '~' replace_substring(s, "~0", "~"); } /*! @param[in] reference_string the reference string to the current value @param[in] value the value to consider @param[in,out] result the result object to insert values to @note Empty objects or arrays are flattened to `null`. */ static void flatten(const std::string& reference_string, const basic_json& value, basic_json& result) { switch (value.m_type) { case value_t::array: { if (value.m_value.array->empty()) { // flatten empty array as null result[reference_string] = nullptr; } else { // iterate array and use index as reference string for (size_t i = 0; i < value.m_value.array->size(); ++i) { flatten(reference_string + "/" + std::to_string(i), value.m_value.array->operator[](i), result); } } break; } case value_t::object: { if (value.m_value.object->empty()) { // flatten empty object as null result[reference_string] = nullptr; } else { // iterate object and use keys as reference string for (const auto& element : *value.m_value.object) { flatten(reference_string + "/" + escape(element.first), element.second, result); } } break; } default: { // add primitive value with its reference string result[reference_string] = value; break; } } } /*! @param[in] value flattened JSON @return unflattened JSON */ static basic_json unflatten(const basic_json& value) { if (not value.is_object()) { throw std::domain_error("only objects can be unflattened"); } basic_json result; // iterate the JSON object values for (const auto& element : *value.m_value.object) { if (not element.second.is_primitive()) { throw std::domain_error("values in object must be primitive"); } // assign value to reference pointed to by JSON pointer; Note // that if the JSON pointer is "" (i.e., points to the whole // value), function get_and_create returns a reference to // result itself. An assignment will then create a primitive // value. json_pointer(element.first).get_and_create(result) = element.second; } return result; } private: /// the reference tokens std::vector reference_tokens {}; }; ////////////////////////// // JSON Pointer support // ////////////////////////// /// @name JSON Pointer functions /// @{ /*! @brief access specified element via JSON Pointer Uses a JSON pointer to retrieve a reference to the respective JSON value. No bound checking is performed. Similar to @ref operator[](const typename object_t::key_type&), `null` values are created in arrays and objects if necessary. In particular: - If the JSON pointer points to an object key that does not exist, it is created an filled with a `null` value before a reference to it is returned. - If the JSON pointer points to an array index that does not exist, it is created an filled with a `null` value before a reference to it is returned. All indices between the current maximum and the given index are also filled with `null`. - The special value `-` is treated as a synonym for the index past the end. @param[in] ptr a JSON pointer @return reference to the element pointed to by @a ptr @complexity Constant. @throw std::out_of_range if the JSON pointer can not be resolved @throw std::domain_error if an array index begins with '0' @throw std::invalid_argument if an array index was not a number @liveexample{The behavior is shown in the example.,operatorjson_pointer} @since version 2.0.0 */ reference operator[](const json_pointer& ptr) { return ptr.get_unchecked(this); } /*! @brief access specified element via JSON Pointer Uses a JSON pointer to retrieve a reference to the respective JSON value. No bound checking is performed. The function does not change the JSON value; no `null` values are created. In particular, the the special value `-` yields an exception. @param[in] ptr JSON pointer to the desired element @return const reference to the element pointed to by @a ptr @complexity Constant. @throw std::out_of_range if the JSON pointer can not be resolved @throw std::domain_error if an array index begins with '0' @throw std::invalid_argument if an array index was not a number @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} @since version 2.0.0 */ const_reference operator[](const json_pointer& ptr) const { return ptr.get_unchecked(this); } /*! @brief access specified element via JSON Pointer Returns a reference to the element at with specified JSON pointer @a ptr, with bounds checking. @param[in] ptr JSON pointer to the desired element @return reference to the element pointed to by @a ptr @complexity Constant. @throw std::out_of_range if the JSON pointer can not be resolved @throw std::domain_error if an array index begins with '0' @throw std::invalid_argument if an array index was not a number @liveexample{The behavior is shown in the example.,at_json_pointer} @since version 2.0.0 */ reference at(const json_pointer& ptr) { return ptr.get_checked(this); } /*! @brief access specified element via JSON Pointer Returns a const reference to the element at with specified JSON pointer @a ptr, with bounds checking. @param[in] ptr JSON pointer to the desired element @return reference to the element pointed to by @a ptr @complexity Constant. @throw std::out_of_range if the JSON pointer can not be resolved @throw std::domain_error if an array index begins with '0' @throw std::invalid_argument if an array index was not a number @liveexample{The behavior is shown in the example.,at_json_pointer_const} @since version 2.0.0 */ const_reference at(const json_pointer& ptr) const { return ptr.get_checked(this); } /*! @brief return flattened JSON value The function creates a JSON object whose keys are JSON pointers (see [RFC 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all primitive. The original JSON value can be restored using the @ref unflatten() function. @return an object that maps JSON pointers to primitve values @note Empty objects and arrays are flattened to `null` and will not be reconstructed correctly by the @ref unflatten() function. @complexity Linear in the size the JSON value. @liveexample{The following code shows how a JSON object is flattened to an object whose keys consist of JSON pointers.,flatten} @sa @ref unflatten() for the reverse function @since version 2.0.0 */ basic_json flatten() const { basic_json result(value_t::object); json_pointer::flatten("", *this, result); return result; } /*! @brief unflatten a previously flattened JSON value The function restores the arbitrary nesting of a JSON value that has been flattened before using the @ref flatten() function. The JSON value must meet certain constraints: 1. The value must be an object. 2. The keys must be JSON pointers (see [RFC 6901](https://tools.ietf.org/html/rfc6901)) 3. The mapped values must be primitive JSON types. @return the original JSON from a flattened version @note Empty objects and arrays are flattened by @ref flatten() to `null` values and can not unflattened to their original type. Apart from this example, for a JSON value `j`, the following is always true: `j == j.flatten().unflatten()`. @complexity Linear in the size the JSON value. @liveexample{The following code shows how a flattened JSON object is unflattened into the original nested JSON object.,unflatten} @sa @ref flatten() for the reverse function @since version 2.0.0 */ basic_json unflatten() const { return json_pointer::unflatten(*this); } /// @} ////////////////////////// // JSON Patch functions // ////////////////////////// /// @name JSON Patch functions /// @{ /*! @brief applies a JSON patch [JSON Patch](http://jsonpatch.com) defines a JSON document structure for expressing a sequence of operations to apply to a JSON) document. With this funcion, a JSON Patch is applied to the current JSON value by executing all operations from the patch. @param[in] json_patch JSON patch document @return patched document @note The application of a patch is atomic: Either all operations succeed and the patched document is returned or an exception is thrown. In any case, the original value is not changed: the patch is applied to a copy of the value. @throw std::out_of_range if a JSON pointer inside the patch could not be resolved successfully in the current JSON value; example: `"key baz not found"` @throw invalid_argument if the JSON patch is malformed (e.g., mandatory attributes are missing); example: `"operation add must have member path"` @complexity Linear in the size of the JSON value and the length of the JSON patch. As usually only a fraction of the JSON value is affected by the patch, the complexity can usually be neglected. @liveexample{The following code shows how a JSON patch is applied to a value.,patch} @sa @ref diff -- create a JSON patch by comparing two JSON values @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) @since version 2.0.0 */ basic_json patch(const basic_json& json_patch) const { // make a working copy to apply the patch to basic_json result = *this; // the valid JSON Patch operations enum class patch_operations {add, remove, replace, move, copy, test, invalid}; const auto get_op = [](const std::string op) { if (op == "add") { return patch_operations::add; } if (op == "remove") { return patch_operations::remove; } if (op == "replace") { return patch_operations::replace; } if (op == "move") { return patch_operations::move; } if (op == "copy") { return patch_operations::copy; } if (op == "test") { return patch_operations::test; } return patch_operations::invalid; }; // wrapper for "add" operation; add value at ptr const auto operation_add = [&result](json_pointer & ptr, basic_json val) { // adding to the root of the target document means replacing it if (ptr.is_root()) { result = val; } else { // make sure the top element of the pointer exists json_pointer top_pointer = ptr.top(); if (top_pointer != ptr) { basic_json& x = result.at(top_pointer); } // get reference to parent of JSON pointer ptr const auto last_path = ptr.pop_back(); basic_json& parent = result[ptr]; switch (parent.m_type) { case value_t::null: case value_t::object: { // use operator[] to add value parent[last_path] = val; break; } case value_t::array: { if (last_path == "-") { // special case: append to back parent.push_back(val); } else { const auto idx = std::stoi(last_path); if (static_cast(idx) > parent.size()) { // avoid undefined behavior throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); } else { // default case: insert add offset parent.insert(parent.begin() + static_cast(idx), val); } } break; } default: { // if there exists a parent it cannot be primitive assert(false); // LCOV_EXCL_LINE } } } }; // wrapper for "remove" operation; remove value at ptr const auto operation_remove = [&result](json_pointer & ptr) { // get reference to parent of JSON pointer ptr const auto last_path = ptr.pop_back(); basic_json& parent = result.at(ptr); // remove child if (parent.is_object()) { // perform range check auto it = parent.find(last_path); if (it != parent.end()) { parent.erase(it); } else { throw std::out_of_range("key '" + last_path + "' not found"); } } else if (parent.is_array()) { // note erase performs range check parent.erase(static_cast(std::stoi(last_path))); } }; // type check if (not json_patch.is_array()) { // a JSON patch must be an array of objects throw std::invalid_argument("JSON patch must be an array of objects"); } // iterate and apply th eoperations for (const auto& val : json_patch) { // wrapper to get a value for an operation const auto get_value = [&val](const std::string & op, const std::string & member, bool string_type) -> basic_json& { // find value auto it = val.m_value.object->find(member); // context-sensitive error message const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; // check if desired value is present if (it == val.m_value.object->end()) { throw std::invalid_argument(error_msg + " must have member '" + member + "'"); } // check if result is of type string if (string_type and not it->second.is_string()) { throw std::invalid_argument(error_msg + " must have string member '" + member + "'"); } // no error: return value return it->second; }; // type check if (not val.is_object()) { throw std::invalid_argument("JSON patch must be an array of objects"); } // collect mandatory members const std::string op = get_value("op", "op", true); const std::string path = get_value(op, "path", true); json_pointer ptr(path); switch (get_op(op)) { case patch_operations::add: { operation_add(ptr, get_value("add", "value", false)); break; } case patch_operations::remove: { operation_remove(ptr); break; } case patch_operations::replace: { // the "path" location must exist - use at() result.at(ptr) = get_value("replace", "value", false); break; } case patch_operations::move: { const std::string from_path = get_value("move", "from", true); json_pointer from_ptr(from_path); // the "from" location must exist - use at() basic_json v = result.at(from_ptr); // The move operation is functionally identical to a // "remove" operation on the "from" location, followed // immediately by an "add" operation at the target // location with the value that was just removed. operation_remove(from_ptr); operation_add(ptr, v); break; } case patch_operations::copy: { const std::string from_path = get_value("copy", "from", true);; const json_pointer from_ptr(from_path); // the "from" location must exist - use at() result[ptr] = result.at(from_ptr); break; } case patch_operations::test: { bool success = false; try { // check if "value" matches the one at "path" // the "path" location must exist - use at() success = (result.at(ptr) == get_value("test", "value", false)); } catch (std::out_of_range&) { // ignore out of range errors: success remains false } // throw an exception if test fails if (not success) { throw std::domain_error("unsuccessful: " + val.dump()); } break; } case patch_operations::invalid: { // op must be "add", "remove", "replace", "move", "copy", or // "test" throw std::invalid_argument("operation value '" + op + "' is invalid"); } } } return result; } /*! @brief creates a diff as a JSON patch Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can be changed into the value @a target by calling @ref patch function. @invariant For two JSON values @a source and @a target, the following code yields always `true`: @code {.cpp} source.patch(diff(source, target)) == target; @endcode @note Currently, only `remove`, `add`, and `replace` operations are generated. @param[in] source JSON value to copare from @param[in] target JSON value to copare against @param[in] path helper value to create JSON pointers @return a JSON patch to convert the @a source to @a target @complexity Linear in the lengths of @a source and @a target. @liveexample{The following code shows how a JSON patch is created as a diff for two JSON values.,diff} @sa @ref patch -- apply a JSON patch @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) @since version 2.0.0 */ static basic_json diff(const basic_json& source, const basic_json& target, const std::string& path = "") { // the patch basic_json result(value_t::array); // if the values are the same, return empty patch if (source == target) { return result; } if (source.type() != target.type()) { // different types: replace value result.push_back( { {"op", "replace"}, {"path", path}, {"value", target} }); } else { switch (source.type()) { case value_t::array: { // first pass: traverse common elements size_t i = 0; while (i < source.size() and i < target.size()) { // recursive call to compare array values at index i auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); result.insert(result.end(), temp_diff.begin(), temp_diff.end()); ++i; } // i now reached the end of at least one array // in a second pass, traverse the remaining elements // remove my remaining elements const auto end_index = static_cast(result.size()); while (i < source.size()) { // add operations in reverse order to avoid invalid // indices result.insert(result.begin() + end_index, object( { {"op", "remove"}, {"path", path + "/" + std::to_string(i)} })); ++i; } // add other remaining elements while (i < target.size()) { result.push_back( { {"op", "add"}, {"path", path + "/" + std::to_string(i)}, {"value", target[i]} }); ++i; } break; } case value_t::object: { // first pass: traverse this object's elements for (auto it = source.begin(); it != source.end(); ++it) { // escape the key name to be used in a JSON patch const auto key = json_pointer::escape(it.key()); if (target.find(it.key()) != target.end()) { // recursive call to compare object values at key it auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); result.insert(result.end(), temp_diff.begin(), temp_diff.end()); } else { // found a key that is not in o -> remove it result.push_back(object( { {"op", "remove"}, {"path", path + "/" + key} })); } } // second pass: traverse other object's elements for (auto it = target.begin(); it != target.end(); ++it) { if (source.find(it.key()) == source.end()) { // found a key that is not in this -> add it const auto key = json_pointer::escape(it.key()); result.push_back( { {"op", "add"}, {"path", path + "/" + key}, {"value", it.value()} }); } } break; } default: { // both primitive type: replace value result.push_back( { {"op", "replace"}, {"path", path}, {"value", target} }); break; } } } return result; } /// @} }; ///////////// // presets // ///////////// /*! @brief default JSON class This type is the default specialization of the @ref basic_json class which uses the standard template types. @since version 1.0.0 */ using json = basic_json<>; } /////////////////////// // nonmember support // /////////////////////// // specialization of std::swap, and std::hash namespace std { /*! @brief exchanges the values of two JSON objects @since version 1.0.0 */ template <> inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( is_nothrow_move_constructible::value and is_nothrow_move_assignable::value ) { j1.swap(j2); } /// hash value for JSON objects template <> struct hash { /*! @brief return a hash value for a JSON object @since version 1.0.0 */ std::size_t operator()(const nlohmann::json& j) const { // a naive hashing via the string representation const auto& h = hash(); return h(j.dump()); } }; } /*! @brief user-defined string literal for JSON values This operator implements a user-defined string literal for JSON objects. It can be used by adding `"_json"` to a string literal and returns a JSON object if no parse error occurred. @param[in] s a string representation of a JSON object @return a JSON object @since version 1.0.0 */ inline nlohmann::json operator "" _json(const char* s, std::size_t) { return nlohmann::json::parse(reinterpret_cast(s)); } /*! @brief user-defined string literal for JSON pointer This operator implements a user-defined string literal for JSON Pointers. It can be used by adding `"_json"` to a string literal and returns a JSON pointer object if no parse error occurred. @param[in] s a string representation of a JSON Pointer @return a JSON pointer object @since version 2.0.0 */ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t) { return nlohmann::json::json_pointer(s); } // restore GCC/clang diagnostic settings #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) #pragma GCC diagnostic pop #endif #endif ================================================ FILE: rsyn/src/rsyn/core/Rsyn.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_H #define RSYN_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RSYN_KERNEL #define RSYN_LIST_CHUNCK_SIZE 1000 #define RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION \ template \ friend class GenericListCollection; namespace Rsyn { class ObjectData; class NetData; class PinData; class ArcData; class InstanceData; class CellData; class PortData; class ModuleData; class LibraryPinData; class LibraryArcData; class LibraryCellData; class LibraryModuleData; class DesignData; class LibraryData; class NetTagData; class InstanceTagData; class LibraryCellTagData; class Net; class Pin; class Arc; class Instance; class Cell; class Port; class Module; class LibraryPin; class LibraryArc; class LibraryCell; class LibraryModule; class Design; class Library; class AttributeInitializer; template class AttributeInitializerWithDefaultValue; class DesignObserver; template class GenericListCollection; template class GenericReferenceListCollection; template using ListCollection = GenericListCollection; template using ReferenceListCollection = GenericReferenceListCollection; class CollectionOfLibraryPinsFilteredByDirection; class CollectionOfLibraryPins; class CollectionOfLibraryArcs; class CollectionOfLibraryArcsToLibraryPin; class CollectionOfLibraryArcsFromLibraryPin; template class CollectionOfGenericPinsFilteredByDirection; template class CollectionOfGenericPins; template class CollectionOfGenericArcs; template class CollectionOfGenericPredecessorPins; template class CollectionOfGenericSuccessorPins; typedef CollectionOfGenericPinsFilteredByDirection CollectionOfPinsFilteredByDirection; typedef CollectionOfGenericPins CollectionOfPins; typedef CollectionOfGenericArcs CollectionOfArcs; typedef CollectionOfGenericPredecessorPins CollectionOfPredecessorPins; typedef CollectionOfGenericSuccessorPins CollectionOfSuccessorPins; typedef std::uint32_t Index; typedef int TopologicalIndex; // ============================================================================= // Tags // ============================================================================= class TagNotSpecifiedException : public std::runtime_error { public: TagNotSpecifiedException(const std::string &tagName) : std::runtime_error("Trying to use the value of the tag '" + tagName + "', which was not set.") {} }; // end class enum LogicTypeTag { LOGIC_TYPE_TAG_NOT_SPECIFIED, LOGIC_TYPE_TAG_NONE, LOGIC_TYPE_TAG_COMBINATIONAL, LOGIC_TYPE_TAG_SEQUENTIAL }; // end enum enum BufferTypeTag { BUFFER_TYPE_TAG_NOT_SPECIFIED, BUFFER_TYPE_TAG_NONE, BUFFER_TYPE_TAG_NON_INVERTING, BUFFER_TYPE_TAG_INVERTING }; // end enum enum TieTypeTag { TIE_TYPE_TAG_NOT_SPECIFIED, TIE_TYPE_TAG_NONE, TIE_TYPE_TAG_LOW, TIE_TYPE_TAG_HIGH }; // end enum enum NetTypeTag { NET_TYPE_TAG_NOT_SPECIFIED, NET_TYPE_TAG_NONE, NET_TYPE_TAG_DATA, NET_TYPE_TAG_CLOCK, NET_TYPE_TAG_SCAN, NET_TYPE_TAG_RESET }; // end enum // ============================================================================= // Events // ============================================================================= enum SessionEventType { EVENT_DESIGN_LOADED, EVENT_SERVICE_STARTED, NUM_SESSION_EVENTS }; // end enum enum DesignEventType { EVENT_DESTRUCTION, EVENT_POST_INSTANCE_CREATE, EVENT_PRE_INSTANCE_REMOVE, EVENT_POST_NET_CREATE, EVENT_PRE_NET_REMOVE, EVENT_POST_CELL_REMAP, EVENT_POST_PIN_CONNECT, EVENT_PRE_PIN_DISCONNECT, EVENT_POST_INSTANCE_MOVE, NUM_DESIGN_EVENTS }; // end enum // ============================================================================= // Exception // ============================================================================= class SafeModeException : public Exception { public: SafeModeException(const std::string &msg) : Exception(msg) {} }; // end class // ============================================================================= // Constants // ============================================================================= // Some constants... enum { TOPOLOGICAL_SORTING_SMALL_GAP = 10, TOPOLOGICAL_SORTING_LARGE_GAP = 1000 }; // end enum static const std::string NullName = ""; static const TopologicalIndex MIN_TOPOLOGICAL_INDEX = -std::numeric_limits::infinity(); } // end namespace // ============================================================================= // Descriptors // ============================================================================= #include "rsyn/core/dscp/LibraryCell.h" #include "rsyn/core/dscp/LibraryModule.h" // ============================================================================= // Global // ============================================================================= namespace Rsyn { // ----------------------------------------------------------------------------- class Global { public: static const std::string & getDirectionName(const Direction direction) { static const std::array NAMES = { "UNKNOWN", "INPUT", "OUTPUT", "BIDIRECTIONAL" }; return NAMES[direction]; } // end method static const std::string & getDirectionShortName(const Direction direction) { static const std::array NAMES = { "UNKNOWN", "IN", "OUT", "BIDI" }; return NAMES[direction]; } // end method static const std::string & getDirectionSingleCharName(const Direction direction) { static const std::array NAMES = { "?", "I", "O", "B" }; return NAMES[direction]; } // end method static const Direction getReverseDirection(const Direction direction) { static const Direction DIRECTION_REVERSED[NUM_SIGNAL_DIRECTIONS] = { UNKNOWN_DIRECTION, OUT, IN, BIDIRECTIONAL }; return DIRECTION_REVERSED[direction]; } // end method }; // end class } // end namespace // ============================================================================= // Objects // ============================================================================= // Object's Declarations (Proxies) #include "rsyn/core/obj/decl/Object.h" #include "rsyn/core/obj/decl/Net.h" #include "rsyn/core/obj/decl/Pin.h" #include "rsyn/core/obj/decl/Arc.h" #include "rsyn/core/obj/decl/Instance.h" #include "rsyn/core/obj/decl/Cell.h" #include "rsyn/core/obj/decl/Port.h" #include "rsyn/core/obj/decl/Module.h" #include "rsyn/core/obj/decl/LibraryPin.h" #include "rsyn/core/obj/decl/LibraryArc.h" #include "rsyn/core/obj/decl/LibraryCell.h" #include "rsyn/core/obj/decl/LibraryModule.h" #include "rsyn/core/obj/decl/Design.h" #include "rsyn/core/obj/decl/Library.h" // Object's Data #include "rsyn/core/obj/data/Object.h" #include "rsyn/core/obj/data/Net.h" #include "rsyn/core/obj/data/Pin.h" #include "rsyn/core/obj/data/Arc.h" #include "rsyn/core/obj/data/Instance.h" #include "rsyn/core/obj/data/Cell.h" #include "rsyn/core/obj/data/Port.h" #include "rsyn/core/obj/data/Module.h" #include "rsyn/core/obj/data/LibraryPin.h" #include "rsyn/core/obj/data/LibraryArc.h" #include "rsyn/core/obj/data/LibraryCell.h" #include "rsyn/core/obj/data/LibraryModule.h" #include "rsyn/core/obj/data/Design.h" #include "rsyn/core/obj/data/Library.h" // Hashes namespace std { #define RSYN_CREATE_HASH(OBJ) \ template <> \ struct hash { \ size_t operator()(const OBJ &obj) const { \ return hash>()(obj); \ } \ }; RSYN_CREATE_HASH(Rsyn::Net); RSYN_CREATE_HASH(Rsyn::Pin); RSYN_CREATE_HASH(Rsyn::Arc); RSYN_CREATE_HASH(Rsyn::Instance); RSYN_CREATE_HASH(Rsyn::LibraryPin); RSYN_CREATE_HASH(Rsyn::LibraryArc); RSYN_CREATE_HASH(Rsyn::LibraryCell); } // end namespace // Infra #include "rsyn/core/infra/Attribute.h" #include "rsyn/core/infra/Observer.h" // Object's Implementations #include "rsyn/core/obj/impl/Object.h" #include "rsyn/core/obj/impl/Net.h" #include "rsyn/core/obj/impl/Pin.h" #include "rsyn/core/obj/impl/Arc.h" #include "rsyn/core/obj/impl/Instance.h" #include "rsyn/core/obj/impl/Cell.h" #include "rsyn/core/obj/impl/Port.h" #include "rsyn/core/obj/impl/Module.h" #include "rsyn/core/obj/impl/LibraryPin.h" #include "rsyn/core/obj/impl/LibraryArc.h" #include "rsyn/core/obj/impl/LibraryCell.h" #include "rsyn/core/obj/impl/LibraryModule.h" #include "rsyn/core/obj/impl/Design.h" #include "rsyn/core/obj/impl/Library.h" #endif ================================================ FILE: rsyn/src/rsyn/core/RsynTypes.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_TYPES_H #define RSYN_TYPES_H #include namespace Rsyn { enum ObjectType { OBJECT_TYPE_INVALID = -1, OBJECT_TYPE_NET, OBJECT_TYPE_PIN, OBJECT_TYPE_ARC, OBJECT_TYPE_INSTANCE, OBJECT_TYPE_CELL, OBJECT_TYPE_PORT, OBJECT_TYPE_MODULE, OBJECT_TYPE_LIBRARY_PIN, OBJECT_TYPE_LIBRARY_ARC, OBJECT_TYPE_LIBRARY_CELL, NUM_OBJECT_TYPES }; // end enum enum InstanceType { UNKNOWN_INSTANCE_TYPE = 0, // used in bit fields (needs to start at zero) CELL, PORT, MODULE, NUM_INSTANCE_TYPES }; // end enum enum ArcType { UNKNOWN_ARC_TYPE = 0, // used in bit fields (needs to start at zero) INSTANCE_ARC, NET_ARC, NUM_ARC_TYPES }; // end enum enum TraverseType { INVALID_TRAVERSE_TYPE = -1, FORWARD, // from inputs to outputs (topological order) BACKWARD, // from outputs to inputs (reverse topological order) NUM_TRAVERSE_TYPES }; // end enum enum Direction { // TODO: Many rename to SignalDirection UNKNOWN_DIRECTION = 0, // used in bit fields (needs to start at zero) IN = 1, SINK = 1, OUT = 2, DRIVER = 2, BIDIRECTIONAL = 3, NUM_SIGNAL_DIRECTIONS }; // end enum //! @brief Orientation based on compass rose. //! @details The default orientation is "vertically and face up" - N (North). //! Rotate by 90deg clockwise to get E, S and W, flip to get FN, FE, //! FS and FW. (think of a dial). //! Source: http://vlsicad.ucsd.edu/GSRC/bookshelf/Slots/Placement/plFormats.html //! @note This orientations are compatible with LEF/DEF and OpenAccess. enum PhysicalOrientation : std::int8_t { /*! \brief Only used for Rsyn internal control.*/ ORIENTATION_INVALID = -1, //! @brief North Orientation (R0) ORIENTATION_N = 0, //! @brief South orientation (R180) ORIENTATION_S = 1, //! @brief West orientation (R90) ORIENTATION_W = 2, //! @brief East orientation (R270) ORIENTATION_E = 3, //! @brief Flipped-North orientation (MY) ORIENTATION_FN = 4, //! @brief Flipped-South orientation (MX) ORIENTATION_FS = 5, //! @brief Flipped-West orientation (MX90) ORIENTATION_FW = 6, //! @brief Flipped-East orientation (MY90) ORIENTATION_FE = 7, //! @brief Number of orientations NUM_PHY_ORIENTATION = 8 }; // end enum enum BufferType { NON_INVERTING, INVERTING, ANY_BUFFER_TYPE }; // end enum enum TieType { TIE_LOW, TIE_HIGH, ANY_TIE_TYPE }; // end enum // Mateus @ 20190204: Refatoring Use //! @brief Describes the usage of a pin or a net //! @note Compatible with LEF/DEF standard 5.8 enum Use { UNKNOWN_USE = -1, SIGNAL, POWER, GROUND, CLOCK, TIEOFF, ANALOG, SCAN, RESET }; } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/core/dscp/LibraryCell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_LIBRARY_CELL_DESCRIPTOR_H #define RSYN_LIBRARY_CELL_DESCRIPTOR_H #include #include #include #include #include #include #include "lef5.8/lefiMacro.hpp" namespace Rsyn { class CellDescriptor { friend class Design; // TODO: destroy this friendship... private: // macro lefiMacro* macro; // Mateus @ 20180917: Adding PinUse // pin name, pin direction std::vector> pins; // from -> to std::vector> arcs; public: void setMacro(lefiMacro* macro) { this->macro = macro; // TODO: ugly } // end method // Mateus @ 20180917: Adding PinUse void addPin(const std::string &name, const Direction &direction, const Use& pinUse = UNKNOWN_USE) { pins.push_back(std::make_tuple(name, direction, pinUse)); } // end method void addArc(const std::string &from, const std::string &to) { arcs.push_back(std::make_tuple(from, to)); } // end method const std::string getName() const { return macro->name(); } // end method Rsyn::Direction getPinDirection(const std::string &name) const { const int numPins = pins.size(); for (int i = 0; i < numPins; i++) { if (std::get<0>(pins[i]) == name) { return std::get<1>(pins[i]); } // end if } // end for return Rsyn::UNKNOWN_DIRECTION; } // end if void checkConsistency() const { const int numArcs = arcs.size(); const int numPins = pins.size(); std::map mapPinToDirection; for (int i = 0; i < numPins; i++) { if ((std::get<1>(pins[i]) != Rsyn::IN) && (std::get<1>(pins[i]) != Rsyn::OUT)) { throw Exception("Only in and out direction are supported right now."); } // end if if (std::get<0>(pins[i]) == "") { throw Exception("Invalid pin name."); } // end if mapPinToDirection[std::get<0>(pins[i])] = std::get<1>(pins[i]); } // end for for (int i = 0; i < numArcs; i++) { const std::string &from = std::get<0>(arcs[i]); const std::string &to = std::get<1>(arcs[i]); if (from == to) { throw Exception("From and to pins are equal."); } // end if if (!mapPinToDirection.count(from)) { throw Exception("From pin not found."); } // end if if (!mapPinToDirection.count(to)) { throw Exception("To pin not found."); } // end if if (mapPinToDirection[from] != Rsyn::IN) { throw Exception("From pin is not an input pin."); } // end if if (mapPinToDirection[to] != Rsyn::OUT) { throw Exception("To pin is not an output pin."); } // end if } // end for } // end method }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/core/dscp/LibraryModule.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_LIBRARY_MODULE_DESCRIPTOR_H #define RSYN_LIBRARY_MODULE_DESCRIPTOR_H #include #include #include #include #include #include namespace Rsyn { class ModuleDescriptor { private: // port names std::vector> ports; // instance name, instance type (library cell, module) std::vector> instances; // instance, pin, net std::vector> connections; public: void addPort(const std::string &name, const Direction &direction) { ports.push_back(std::make_tuple(name, direction)); } // end method void addInstance(const std::string &name, const std::string &type) { instances.push_back(std::make_tuple(name, type)); } // end method void addConnection(const std::string &instance, const std::string &pin, const std::string &net) { connections.push_back(std::make_tuple(instance, pin, net)); } // end method }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/core/infra/Attribute.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_ATTRIBUTE_H #define RSYN_ATTRIBUTE_H #include namespace Rsyn { class AttributeInitializer { friend class Design; private: Design design; AttributeInitializer(Design design): design(design) {}; public: Design getDesign() { return design; } }; // end class // ----------------------------------------------------------------------------- template class AttributeInitializerWithDefaultValue { friend class Design; private: Design design; DefaultValueType defaultValue; AttributeInitializerWithDefaultValue(Design design, DefaultValueType defaultValue) : design(design), defaultValue(defaultValue) {}; public: Design getDesign() { return design; } DefaultValueType &getDefaultValue() { return defaultValue; } }; // end class // ----------------------------------------------------------------------------- template class AttributeImplementation; // ----------------------------------------------------------------------------- template class Attribute : public std::shared_ptr> { public: Attribute() {} Attribute(AttributeInitializer initializer) { operator=(initializer); } void operator=(AttributeInitializer initializer); template Attribute(AttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(AttributeInitializerWithDefaultValue initializer); RsynObjectExtension &operator[](RsynObject obj); const RsynObjectExtension &operator[](RsynObject obj) const; }; // end class // ----------------------------------------------------------------------------- template class AttributeBase { private: // [TODO] Make design and list const. Design clsDesign; List<_Object> *clsListPtr; _ObjectExtension clsDefaultValue; typename List<_Object>::CreateElementCallbackHandler clsHandlerOnCreate; typename List<_Object>::DestructorCallbackHandler clsListDestructorCallbackHandler; std::deque<_ObjectExtension> clsData; void accommodate(const Index index) { if (index >= clsData.size()) { clsData.resize(index + 1, clsDefaultValue); } // end if } // end method protected: void setupCallbacks() { clsHandlerOnCreate = clsListPtr->addCreateCallback([&](const int index) { accommodate(clsListPtr->largestId()); }); // end method clsListDestructorCallbackHandler = clsListPtr->addDestructorEventCallback([&]() { clsListPtr = nullptr; }); // end method } // end method void load(Design design, List<_Object> &list, _ObjectExtension defaultValue = _ObjectExtension()) { clsDesign = design; clsListPtr = &list; clsDefaultValue = defaultValue; accommodate(clsListPtr->largestId()); setupCallbacks(); } // end method public: AttributeBase() : clsDesign(nullptr), clsListPtr(nullptr) { } // end constructor AttributeBase(const AttributeBase<_Object, _ObjectReference, _ObjectExtension> &other) { operator=(other); } // end constructor AttributeBase(Design design, List<_Object> &list) { load(design, list); } // end constructor AttributeBase<_Object, _ObjectReference, _ObjectExtension> & operator=(const AttributeBase<_Object, _ObjectReference, _ObjectExtension> &other) { unload(); clsDesign = other.clsDesign; clsListPtr = other.clsListPtr; clsData = other.clsData; // When a layer gets copied, we need to setup new callbacks. setupCallbacks(); return *this; } // end method ~AttributeBase() { unload(); } // end constructor void unload() { if (clsDesign) { clsDesign = nullptr; } // end if if (clsListPtr) { clsListPtr->deleteCreateCallback(clsHandlerOnCreate); clsListPtr->deleteDestructorCallback(clsListDestructorCallbackHandler); clsListPtr = nullptr; } // end if clsData.clear(); clsData.shrink_to_fit(); } // end method inline _ObjectExtension &operator[](_ObjectReference obj) { return clsData[clsDesign.getId(obj)]; } inline const _ObjectExtension &operator[](_ObjectReference obj) const { return clsData[clsDesign.getId(obj)]; } }; // end class //////////////////////////////////////////////////////////////////////////////// // Attribute Layer: (Generic) - Internal Use Only //////////////////////////////////////////////////////////////////////////////// template class AttributeImplementation { }; // end class //////////////////////////////////////////////////////////////////////////////// // Attribute Layer: Net //////////////////////////////////////////////////////////////////////////////// template class AttributeImplementation : public Rsyn::AttributeBase { public: AttributeImplementation() {} AttributeImplementation(AttributeInitializer initializer) { operator=(initializer); } void operator=(AttributeInitializer initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->nets); } // end operator template AttributeImplementation(AttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(AttributeInitializerWithDefaultValue initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->nets, initializer.getDefaultValue()); } // end operator }; // end class //////////////////////////////////////////////////////////////////////////////// // Attribute Layer: Instance //////////////////////////////////////////////////////////////////////////////// template class AttributeImplementation : public Rsyn::AttributeBase { public: AttributeImplementation() {} AttributeImplementation(AttributeInitializer initializer) { operator=(initializer); } void operator=(AttributeInitializer initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->instances); } // end operator template AttributeImplementation(AttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(AttributeInitializerWithDefaultValue initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->instances, initializer.getDefaultValue()); } // end operator }; // end class //////////////////////////////////////////////////////////////////////////////// // Attribute Layer: Pin //////////////////////////////////////////////////////////////////////////////// template class AttributeImplementation : public Rsyn::AttributeBase { public: AttributeImplementation() {} AttributeImplementation(AttributeInitializer initializer) { operator=(initializer); } void operator=(AttributeInitializer initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->pins); } // end operator template AttributeImplementation(AttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(AttributeInitializerWithDefaultValue initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->pins, initializer.getDefaultValue()); } // end operator }; // end class //////////////////////////////////////////////////////////////////////////////// // Attribute Layer: Arc //////////////////////////////////////////////////////////////////////////////// template class AttributeImplementation : public Rsyn::AttributeBase { public: AttributeImplementation() {} AttributeImplementation(AttributeInitializer initializer) { operator=(initializer); } void operator=(AttributeInitializer initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->arcs); } // end operator template AttributeImplementation(AttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(AttributeInitializerWithDefaultValue initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->arcs, initializer.getDefaultValue()); } // end operator }; // end class //////////////////////////////////////////////////////////////////////////////// // Attribute Layer: LibraryCell //////////////////////////////////////////////////////////////////////////////// template class AttributeImplementation : public Rsyn::AttributeBase { public: AttributeImplementation() {} AttributeImplementation(AttributeInitializer initializer) { operator=(initializer); } void operator=(AttributeInitializer initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->libraryCells); } // end operator template AttributeImplementation(AttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(AttributeInitializerWithDefaultValue initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->libraryCells, initializer.getDefaultValue()); } // end operator }; // end class //////////////////////////////////////////////////////////////////////////////// // Attribute Layer: LibraryPin //////////////////////////////////////////////////////////////////////////////// template class AttributeImplementation : public Rsyn::AttributeBase { public: AttributeImplementation() {} AttributeImplementation(AttributeInitializer initializer) { operator=(initializer); } void operator=(AttributeInitializer initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->libraryPins); } // end operator template AttributeImplementation(AttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(AttributeInitializerWithDefaultValue initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->libraryPins, initializer.getDefaultValue()); } // end operator }; // end class //////////////////////////////////////////////////////////////////////////////// // Attribute Layer: LibraryArc //////////////////////////////////////////////////////////////////////////////// template class AttributeImplementation : public Rsyn::AttributeBase { public: AttributeImplementation() {} AttributeImplementation(AttributeInitializer initializer) { operator=(initializer); } void operator=(AttributeInitializer initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->libraryArcs); } // end operator template AttributeImplementation(AttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(AttributeInitializerWithDefaultValue initializer) { Design design = initializer.getDesign(); AttributeBase::load(design, design.data->libraryArcs, initializer.getDefaultValue()); } // end operator }; // end class //////////////////////////////////////////////////////////////////////////////// // Attribute //////////////////////////////////////////////////////////////////////////////// template inline void Attribute::operator=(AttributeInitializer initializer) { this->reset(new AttributeImplementation(initializer)); } // end method template template inline void Attribute::operator=(AttributeInitializerWithDefaultValue initializer) { this->reset(new AttributeImplementation(initializer)); } // end method template inline RsynObjectExtension &Attribute::operator[](RsynObject obj) { return (*this)->operator[](obj); } // end method template inline const RsynObjectExtension &Attribute::operator[](RsynObject obj) const { return (*this)->operator[](obj); } // end method } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/core/infra/Exception.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_EXCEPTION_H #define RSYN_EXCEPTION_H #include #include namespace Rsyn { class Exception : public std::exception { public: Exception(const std::string &msg) : std::exception(), msg(msg) {} virtual const char* what() const throw() { return msg.c_str(); }; private: std::string msg; }; // end class // ----------------------------------------------------------------------------- class CellAlreadyExistsException : public Exception { public: CellAlreadyExistsException(const std::string &name) : Exception("Cell '" + name + "' already exists.") {} }; // end class // ----------------------------------------------------------------------------- class CellNotFoundException : public Exception { public: CellNotFoundException(const std::string &name) : Exception("Cell '" + name + "' not found.") {} }; // end class // ----------------------------------------------------------------------------- class LibraryCellAlreadyExistsException : public Exception { public: LibraryCellAlreadyExistsException(const std::string &name) : Exception("Library cell '" + name + "' already exists.") {} }; // end class // ----------------------------------------------------------------------------- class LibraryCellNotFoundException : public Exception { public: LibraryCellNotFoundException(const std::string &libCellName) : Exception("Library cell '" + libCellName + "' not found.") {} }; // end class // ----------------------------------------------------------------------------- class LibraryPinNotFoundException : public Exception { public: LibraryPinNotFoundException(const std::string &libCellName, const std::string &libPinName) : Exception("Library pin '" + libPinName + "' not found in library cell '" + libCellName + "'.") {} }; // end class // ----------------------------------------------------------------------------- class NetAlreadyExistsException : public Exception { public: NetAlreadyExistsException(const std::string &name) : Exception("Net '" + name + "' already exists.") {} }; // end class // ----------------------------------------------------------------------------- class PinNotFoundException : public Exception { public: PinNotFoundException(const std::string &libCellName, const std::string &cellName, const std::string &pinName) : Exception("Pin '" + pinName + "' not found in cell '" + cellName + "'(" + libCellName + ").") {} }; // end class // ----------------------------------------------------------------------------- class IncompatibleLibraryCellForRemapping : public Exception { public: IncompatibleLibraryCellForRemapping(const std::string &oldLibraryCell, const std::string &newLibraryCell) : Exception("Library cell '" + newLibraryCell + "' is not compatible to library cell '" + oldLibraryCell + "'.") {} }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/core/infra/List.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_LIST_H #define RSYN_LIST_H #include #include #include #include #include #include namespace Rsyn { template struct Element { T value; bool deleted; Element() : deleted(true) {}; Element(T value) : value(value), deleted(false) {}; }; // end struct //-------------------------------------------------------------------------- template struct ElementPointer { private: // For some reason the compiler allows ElementPointer to be silently casted // to int, which led to hard to find bugs. Now we explicitly tell the // compiler to not allow such conversion by making the cast operator // private. operator int() const { return 0; } protected: Element *e; public: T &getValue() { return e->value; } Element *getPointer() { return e; } ElementPointer() : e( nullptr ) {}; ElementPointer(Element *e) : e(e) {}; T * operator->() { return &(e->value); }; const T * operator->() const { return &(e->value); }; bool operator!() const { return e == nullptr; }; bool operator==(const ElementPointer &p) const { return e == p.e; }; bool operator!=(const ElementPointer &p) const { return e != p.e; }; operator bool() const { return e; } // Used in map-like data structures. friend bool operator<(const ElementPointer &left, const ElementPointer &right) { // [IMPORTANT] We don't use the pointer (e) directly to avoid // non-determinism behavior. Note that the pointer address may change // from execution to execution and hence the mapping function may return // elements in different order leading to different results. return left.e->value.getId() < right.e->value.getId(); } // end method }; // end struct //-------------------------------------------------------------------------- template struct Chunk { Element elements[DEFAULT_CHUNK_SIZE]; }; // end struct //-------------------------------------------------------------------------- // // DEFAULT CHUNCK SIZE // // Date: 2016-03-02 // // superblu18 // 10 runtime: 126.876 s memory: +2804 MB // 100 runtime: 113.372 s memory: +2790 MB // 1000 runtime: 112.172 s memory: +2786 MB // 10000 runtime: 114.887 s memory: +2790 MB // // superblue10 // 10 runtime: 331.377 s memory: +6293 MB // 100 runtime: 326.238 s memory: +6258 MB // 1000 runtime: 324.864 s memory: +6258 MB // 10000 runtime: 324.034 s memory: +6259 MB // template class List { public: typedef std::function CreateElementCallback; typedef std::function RemoveElementCallback; typedef std::function DestructorCallback; typedef std::list::iterator CreateElementCallbackHandler; typedef std::list::iterator RemoveElementCallbackHandler; typedef std::list::iterator DestructorCallbackHandler; private: // Iterator validity (std::deque) // ------------------------------ // In case the container shrinks, all iterators, pointers and references to // elements that have not been removed remain valid after the resize and refer // to the same elements they were referring to before the call. // If the container expands, all iterators are invalidated, but existing // pointers and references remain valid, referring to the same elements they // were referring to before. std::deque> chunks; std::list available; std::list callbackOnCreate; std::list callbackOnRemove; std::list callbackOnDestructor; int numElements; int lastInsertedElementId; int currentChunk; int currentChunkFreeSpace; Element *create_internal() { Element *e = nullptr; const int recycle = recycleId(); if (recycle != -1) { // Recycle a previously removed element... e = get(recycle); available.pop_back(); // Clean-up the recycled element. *e = T(); lastInsertedElementId = recycle; } else { if (currentChunkFreeSpace == 0) { // Move to the next chunk or creates a new chunk to store the new // element. currentChunk++; if (currentChunk >= chunks.size()) { chunks.resize(chunks.size()+1); } // end if currentChunkFreeSpace = DEFAULT_CHUNK_SIZE; } // end else auto &c = chunks[currentChunk]; e = &(c.elements[DEFAULT_CHUNK_SIZE - currentChunkFreeSpace]); lastInsertedElementId = (currentChunk+1)*DEFAULT_CHUNK_SIZE - currentChunkFreeSpace; currentChunkFreeSpace--; } // end else e->deleted = false; numElements++; return e; } // end method public: List() : numElements(0), lastInsertedElementId(-1), currentChunk(-1), currentChunkFreeSpace(0) { }; // end constructor ~List() { for (DestructorCallback &callback : callbackOnDestructor) { callback(); } // end for } // end destructor bool isEmpty() const { return !numElements; }; int size() const { return numElements; }; int lastId() const { return lastInsertedElementId; } int largestId() const { return (currentChunk+1)*DEFAULT_CHUNK_SIZE - currentChunkFreeSpace; } int recycleId() const { return available.empty()? -1 : available.front(); } // end method int capacity() const { // It can be optimized, but for now its just for debug purpose. int capacity = 0; for (auto &c : chunks ) capacity += DEFAULT_CHUNK_SIZE; return capacity; } // end method void reserve(const int n) { const int numChunks = (int) std::ceil(n / double(DEFAULT_CHUNK_SIZE)); if (numChunks > chunks.size()) { chunks.resize(numChunks); } // end if }; // end method Element *create() { Element *e = create_internal(); for (CreateElementCallback &callback : callbackOnCreate) { callback(lastId()); } // end for return e; } // end method Element *add(const T &value) { Element *e = create_internal(); e->value = value; for (CreateElementCallback &callback : callbackOnCreate) { callback(lastId()); } // end for return e; } // end method Element *get(const int index) { return &chunks[index/DEFAULT_CHUNK_SIZE].elements[index%DEFAULT_CHUNK_SIZE]; } // end method const Element *get(const int index) const { return &chunks[index/DEFAULT_CHUNK_SIZE].elements[index%DEFAULT_CHUNK_SIZE]; } // end method void remove(const int index) { Element *e = get(index); e->deleted = true; available.push_back(index); numElements--; for (RemoveElementCallback &callback : callbackOnRemove) { callback(index); } // end for } // end method DestructorCallbackHandler addDestructorEventCallback(DestructorCallback callback) { callbackOnDestructor.push_back(callback); return --callbackOnDestructor.end(); } // end method CreateElementCallbackHandler addCreateCallback(CreateElementCallback callback) { callbackOnCreate.push_back(callback); return --callbackOnCreate.end(); } // end method RemoveElementCallbackHandler addRemoveCallback(CreateElementCallback callback) { callbackOnRemove.push_back(callback); return --callbackOnRemove.end(); } // end method void deleteDestructorCallback(DestructorCallbackHandler handler) { callbackOnDestructor.erase(handler); } // end method void deleteCreateCallback(CreateElementCallbackHandler handler) { callbackOnCreate.erase(handler); } // end method void deleteRemoveCallback(RemoveElementCallbackHandler handler) { callbackOnRemove.erase(handler); } // end method class Iterator { friend class List; private: List *l; Element *e; int currChunk; int currElementInChunk; int size; bool stop; Element *nextElement() { do { currElementInChunk++; if (currElementInChunk == DEFAULT_CHUNK_SIZE) { currElementInChunk = 0; currChunk++; if (currChunk == l->chunks.size()) { stop = true; break; } // end if auto &chunk = l->chunks[currChunk]; e = &(chunk.elements[0]); } else { e++; } // end else } while (e->deleted); return e; } // end method public: Iterator() : l(NULL), e(NULL), currChunk(0), currElementInChunk(0) {}; Iterator( List *l ) : l(l), currChunk(0), currElementInChunk(0) { if (!l->isEmpty()) { e = l->get(0); if (e->deleted) { // Skip deleted elements at the beginning of the list. e = nextElement(); } // end if stop = false; } else { stop = true; } // end else } // end constructor void operator++ () { e = nextElement(); } // end method ElementPointer operator*() { return e; } friend bool operator != ( Iterator it1, Iterator it2 ) { return !it1.stop; } // end operator bool stopFlag() { return stop; } }; // end structure Iterator begin() { return Iterator( this ); } Iterator end() { Iterator end; end.l = this; end.currChunk = chunks.size() - 1; end.currElementInChunk = DEFAULT_CHUNK_SIZE - 1; end.e = &(chunks[ end.currChunk ].elements[ end.currElementInChunk ]); return end; } /* Method for debug purposes */ void printState() { std::cout << " --- List state---" << std::endl; std::cout << "> Number of elements: " << numElements << std::endl; std::cout << "> Current chunk free elements: " << currentChunkFreeSpace << std::endl; std::cout << "> Number of chunks: " << chunks.size() << std::endl; for( auto c: chunks ) std::cout << ">> Chunk size: " << c.size << std:: endl; std::cout << " -----------------" << std::endl; } // end method }; // end class // ----------------------------------------------------------------------------- template class ConstList { private: List *l; ConstList() {} public: typedef typename List::Iterator Iterator; ConstList(const List &list) { l = const_cast *>(&list); } // end constructor Element *get(const int index) { return l->get(index); } Iterator begin() { return l->begin(); } Iterator end() { return l->end(); } }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/core/infra/Observer.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_DESIGN_OBSERVER_H #define RSYN_DESIGN_OBSERVER_H namespace Rsyn { class DesignObserver { friend class Rsyn::Design; private: Design observedDesign; public: // Note: The observer will not be registered to receive notifications for // methods that it does not overwrite. Therefore, no runtime overhead for // handling undesired notifications. virtual void onDesignDestruction() {} virtual void onPostInstanceCreate(Rsyn::Instance instance) {} virtual void onPreInstanceRemove(Rsyn::Instance instance) {} virtual void onPostNetCreate(Rsyn::Net net) {} virtual void onPreNetRemove(Rsyn::Net net) {} virtual void onPostCellRemap(Rsyn::Cell cell, Rsyn::LibraryCell oldLibraryCell) {} virtual void onPostPinConnect(Rsyn::Pin pin) {} virtual void onPrePinDisconnect(Rsyn::Pin pin) {} virtual void onPreInstanceMove(Rsyn::Instance) {} virtual void onPostInstanceMove(Rsyn::Instance) {} virtual ~DesignObserver() { if (observedDesign) observedDesign.unregisterObserver(this); } // end destructor }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/core/infra/RangeBasedLoop.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef UTIL_RANGEBASEDLOOP_H #define UTIL_RANGEBASEDLOOP_H //////////////////////////////////////////////////////////////////////////////// // Author: Guilherme Flach // Date: 2015-02-17 // // Description // ----------- // This class makes it easier to create range-based loops. // // How To Use It // ------------- // Create a class/struct with the following methods: // 1) Object current() {...} // 2) void next() {...} // 3) bool filter() {...} // 4) bool stop() {...} // // which the following meaning // // 1) returns the current object in the collection; // 2) moves to the next object in the collection; // 3) indicates if the current object should be filtered (i.e. not // processed), this class will call next() until filter() returns true // or the end of collection is reached; // 4) indicates if we reached the end of the collection. // // Example // ------- // Traverse only non-zero elements of a vector (i.e. filter out zeros): // // // This is the class the user (you) needs to provide to create a // // ranged-based loop. // class NonZeroElementsCollection { // private: // const std::vector &v; // std::size_t index; // public: // NonZeroElementsCollection(const std::vector &v) // : v(v), index(0) {} // // int current() {return v[index];} // void next() {index++;} // bool filter() {return current() == 0;} // bool stop() {return index >= v.size();} // }; // end class // // // Give it a nice name... // typedef Range allNonZeroElements; // // // Testing... // int main() { // std::vector v = {0, 1, 0, 2, 0, 3, 4, 0, 0, 0, 5}; // // for (int value : allNonZeroElements(v)) { // std::cout << value << " "; // } // end for // std::cout << "\n"; // // return 1; // } // end function // //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // According to the C++11 standard, the following range-loop statement // // for ( declaration : expression ) statement // // is equivalent to the the following statament // // { // auto&& __range = expression; // for (auto __begin = begin-expression, // __end = end-expression; // __begin != __end; // ++__begin // ) { // declaration = *__begin; // statement // } // } // // So that, we can override the operator != of an iterator to make it // return false whenever the stop condition was reached in the begin // iterator in code above. // // Source: http://en.cppreference.com/w/cpp/language/range-for //////////////////////////////////////////////////////////////////////////////// template class Range { private: Collection collection; struct RangeIterator { Collection *collection; RangeIterator() : collection(nullptr) {} RangeIterator(Collection &collection_) : collection(&collection_) { while (!collection->stop() && collection->filter()) { // stop must be first collection->next(); } // end while } // end constructor void operator++() { do { collection->next(); } while (!collection->stop() && collection->filter()); // stop must be first } // end method bool operator!=(const RangeIterator &) { return !collection->stop(); } // end method auto operator*() -> decltype(collection->current()) { return collection->current(); } // end method }; // end class public: Range(Collection &&collection) : collection(collection) {} RangeIterator begin() { return RangeIterator(collection); } RangeIterator end() { return RangeIterator(); /*dummy, not used */} }; // end class //////////////////////////////////////////////////////////////////////////////// // Traverse a collection backwards. //////////////////////////////////////////////////////////////////////////////// template class BackwardsCollection { private: const Collection &collection; public: explicit BackwardsCollection(const Collection &t) : collection(t) {} typename Collection::const_reverse_iterator begin() const { return collection.rbegin(); } typename Collection::const_reverse_iterator end() const { return collection.rend(); } }; // end class //////////////////////////////////////////////////////////////////////////////// // Returns an specific element of a tuple collection. //////////////////////////////////////////////////////////////////////////////// template class TupleElement : public std::tuple<_Elements...> { public: typedef typename std::tuple_element>::type T; TupleElement() {} TupleElement(const std::tuple<_Elements...> &t) : std::tuple<_Elements...>(t) {} void operator=(const std::tuple<_Elements...> &t) { std::tuple<_Elements...>::operator=(t); } operator T() { return std::get(*this);} }; // end class #endif ================================================ FILE: rsyn/src/rsyn/core/infra/RawPointer.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_RAW_POINTER_H #define RSYN_RAW_POINTER_H #include #include "rsyn/core/Rsyn.h" namespace Rsyn { //! @brief Allows Rsyn objects to be casted as raw pointer (i.e. void *). class RawPointer { private: void * pointer = nullptr; public: RawPointer(void * data) : pointer(data) {} RawPointer(Rsyn::Net obj) : pointer(static_cast(obj.getData())) {} RawPointer(Rsyn::Pin obj) : pointer(static_cast(obj.getData())) {} RawPointer(Rsyn::Arc obj) : pointer(static_cast(obj.getData())) {} RawPointer(Rsyn::Instance obj) : pointer(static_cast(obj.getData())) {} RawPointer(Rsyn::LibraryPin obj) : pointer(static_cast(obj.getData())) {} RawPointer(Rsyn::LibraryArc obj) : pointer(static_cast(obj.getData())) {} RawPointer(Rsyn::LibraryCell obj) : pointer(static_cast(obj.getData())) {} Rsyn::Net asNet () { return static_cast(pointer); } Rsyn::Pin asPin () { return static_cast(pointer); } Rsyn::Arc asArc () { return static_cast(pointer); } Rsyn::Instance asInstance () { return static_cast(pointer); } Rsyn::LibraryPin asLibraryPin () { return static_cast(pointer); } Rsyn::LibraryArc asLibraryArc () { return static_cast(pointer); } Rsyn::LibraryCell asLibraryCell() { return static_cast(pointer); } operator void *() { return pointer; } operator const void *() const { return pointer; } }; // end class } // end namespace #endif /* RAWPOINTER_H */ ================================================ FILE: rsyn/src/rsyn/core/obj/data/Arc.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct ArcData : ObjectData { ArcType type : 3; Pin from; Pin to; union { // Place holder for initialization... void * extra; // Meaningful only when this is arc belongs to a cell. LibraryArcData * libraryArcData; // Meaningful only when this is arc belongs to a net. NetData * netData; }; // end union ArcData() : type(UNKNOWN_ARC_TYPE), extra(nullptr), from(nullptr), to(nullptr) { } // end constructor }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/Cell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct CellData { }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/Design.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct DesignData { std::string name; Rsyn::Module topModule; List instances; List pins; List arcs; List nets; List cells; List libraryCells; List libraryPins; List libraryArcs; std::vector instanceNames; std::vector netNames; int anonymousInstanceId; int anonymousNetId; std::unordered_map instanceMapping; std::unordered_map netMapping; std::unordered_map libraryCellMapping; std::array portLibraryCells; std::set ports[NUM_SIGNAL_DIRECTIONS]; std::array instanceCount; std::vector structuralStartpoints; std::vector structuralEndpoints; std::vector netsInTopologicalOrder; bool dirty; bool initialized; // Used for some netlist traversing (e.g. update topological ordering)... int sign; // Observers std::array, NUM_DESIGN_EVENTS> observers; // Constructor DesignData() : initialized(false), dirty(false), anonymousInstanceId(0), anonymousNetId(0), instanceCount({0, 0, 0}), sign(0) { } // end constructor }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/Instance.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct InstanceTagData { TristateFlag fixed; TristateFlag block; }; // end struct // ----------------------------------------------------------------------------- struct InstanceData : ObjectData { InstanceType type; std::vector pins; std::vector arcs; // Design (Cached) // @todo Remove. Design design; // The module where this instance is instantiated. If only null for the top // module. Module parent; // Local index inside it's parent module. Index mid; // Extra data for different types of instances. union { void * extra; ModuleData * moduleData; PinData * outerPin; LibraryCellData * lcell; }; // end union // User tag InstanceTagData tag; // Physical information. Bounds clsBounds; PhysicalOrientation clsOrientation; DBUxy clsPortPos; // only for port to define position. (@todo remove, use bounds instead). // Constructor InstanceData() : design(nullptr), type(UNKNOWN_INSTANCE_TYPE), parent(nullptr), extra(nullptr), mid(-1), clsBounds(0, 0, 0, 0), clsOrientation(ORIENTATION_N), // @todo set to R0 by default clsPortPos(0, 0) { } // end constructor }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/Library.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct LibraryData : ObjectData { DesignData *designData = nullptr; }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/LibraryArc.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct LibraryArcData : ObjectData { Design design; int index; // TODO: index may be confusing as objects have a field called id LibraryCell lcell; LibraryPin from; LibraryPin to; LibraryArcData() : design(nullptr), index(-1), lcell(nullptr), from(nullptr), to(nullptr) { } // end class }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/LibraryCell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct LibraryCellTagData { LogicTypeTag logicType : 2; BufferTypeTag bufferType : 2; TieTypeTag tieType : 2; LibraryCellTagData() : logicType(LOGIC_TYPE_TAG_NOT_SPECIFIED), bufferType(BUFFER_TYPE_TAG_NOT_SPECIFIED), tieType(TIE_TYPE_TAG_NOT_SPECIFIED) { } // end constructor }; // end struct // ----------------------------------------------------------------------------- struct LibraryCellData : ObjectData { Design design; std::string name; std::vector pins; std::vector arcs; DBUxy size; // User flags. LibraryCellTagData tag; // TODO: use array int numInputPins; int numOutputPins; int numInOutPins; LibraryCellData() : design(nullptr), numInputPins(0), numOutputPins(0), numInOutPins(0), size(0, 0) { } // constructor }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/LibraryModule.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct LibraryModuleData : ObjectData { Design design; LibraryModuleData() : design(nullptr) { } // end constructor }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/LibraryPin.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct LibraryPinData : ObjectData { Design design; LibraryCell lcell; std::string name; Direction direction; // Mateus @ 20180917: Adding PinUse Use pinUse; int index; LibraryPinData() : design(nullptr), lcell(nullptr), direction(UNKNOWN_DIRECTION), pinUse(UNKNOWN_USE), index(-1) { } // end constructor }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/Module.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct ModuleData { Design design; // Pointers to instances and nets in this hierarchy level (objects above and // below this hierarchy level are not stored). We don't need to store // pin and arc pointers as they can be deduced from cell pointers. Nets // on the other may exist without connecting any cell (pin) so can not be // completely deduced from cells. // // TODO: Find a better way to store module-specific data. It seems we are // spending too much memory to keep this. List instances; List nets; // Ports. // Redundant with instances, but allow faster access to ports. List ports; std::set portsByDirection[Rsyn::NUM_SIGNAL_DIRECTIONS]; // TODO: unify these too // Used for some netlist traversing... mutable int sign; ModuleData() : sign(0) {} }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/Net.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct NetTagData { TristateFlag ideal; NetTypeTag type; NetTagData() : type(NET_TYPE_TAG_NOT_SPECIFIED) { } // end constructor }; // end struct // ----------------------------------------------------------------------------- struct NetData : ObjectData { // Index in parent module. Index mid; // User tags. NetTagData tag; // Using a vector for fast traverse, but slow insertion and removal. std::vector pins; // Driver. If multiple-drivers, store one of them without any assumptions. Pin driver; // Parent Module parent; std::array numPinsOfType; // Helper used for netlist traversals. int sign; // Mateus @ 20190204: Adding net use; Use netUse; NetData() : mid(-1), sign(-1), driver(nullptr), numPinsOfType({0, 0, 0, 0}), parent(nullptr), netUse(UNKNOWN_USE) { } // end constructor }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/Object.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct ObjectData { Index id; }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/Pin.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct PinData : ObjectData { // #> bit pack int index : 20; // index of this pin in the library cell. Direction direction : 3; // direction of this pin InstanceType type : 3; // the type of instance that this pin belongs to bool boundary : 1; // Is this pin a port? Pins belonging to both // Rsyn::PORT and Rsyn::MODULE are marked as boundary // pins. // <# int sign; Instance instance; Net net; std::vector arcs[NUM_TRAVERSE_TYPES]; TopologicalIndex order; // topological ordering PinData() : index(-1), direction(UNKNOWN_DIRECTION), type(UNKNOWN_INSTANCE_TYPE), boundary(false), sign(0), instance(nullptr), net(nullptr), order(std::numeric_limits::quiet_NaN()) { } // end constructor }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/data/Port.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { struct PortData { }; // end struct } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/Arc.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a netlist arc. class Arc : public Proxy { RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; friend class RawPointer; friend class Design; private: Arc(ArcData * data) : Proxy(data) {} public: //! @brief Default constructor. Arc() {} //! @brief Assignment constructor to allow null values. Arc(std::nullptr_t) {} //! @brief Returns the name of the arc (e.g. a -> o). std::string getName() const; //! @brief Returns the full name of the arc (e.g. u1:a -> u1:o). std::string getFullName() const; //! @brief Returns the name of the "from" pin. const std::string getFromName() const; //! @brief Returns the name of the "to" pin. const std::string getToName() const; //! @brief Returns the design in which this arc is instantiated. Design getDesign(); //! @brief Returns the design in which this arc is instantiated. const Design getDesign() const; //! @brief Returns the type of this arc (i.e. cell or net arc). ArcType getType() const; //! @brief Returns the instance to which this arc is associated if any. If //! this is a net arc, returns null. Instance getInstance() const; //! @brief Returns the net to which this arc is associated if any. If //! this is a cell arc, returns null. Net getNet() const; //! @brief Returns the library arc related to this arc if any. If this is a //! net arc, returns null. LibraryArc getLibraryArc() const; //! @brief Returns the library cell related to this arc if any. If this is a //! net arc or belong to an instance without library cell, returns //! null. LibraryCell getLibraryCell() const; //! @brief Returns the "from" pin of this arc. //! @note For cell arcs, the "from" pin is always an input pin. For net //! arcs, the "from" pin is always an output (driver) pin. //! Bidirectional pins are not handled yet. Pin getFromPin() const; //! @brief Returns the "to" pin of this arc. //! @note For cell arcs, the "to" pin is always an output pin. For net //! arcs, the "to" pin is always an input (sink) pin. //! Bidirectional pins are not handled yet. Pin getToPin() const; //! @brief Returns the net to which the "from" pin connects to if any. Net getFromNet() const; //! @brief Returns the net to which the "to" pin connects to if any. Net getToNet() const; //! @brief Returns the index of this arc relative to its instance and //! library cell. If this arc does not belong to an instance (i.e. net arc), //! returns -1. int getIndex() const; }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/Cell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a netlist cell. class Cell : public Instance { friend class RawPointer; friend class Design; friend class Instance; private: Cell(InstanceData * data) : Instance(data) {} public: //! @brief Default constructor. Cell() : Instance(nullptr) {} //! @brief Assignment constructor to allow null values. Cell(std::nullptr_t) : Instance(nullptr) {} //! @brief Returns the name of the library cell associated to this cell. const std::string &getLibraryCellName() const; //! @brief Returns the library cell associated to this cell. LibraryCell getLibraryCell() const; //! @brief Returns the respective pin in this cell associated to a library //! pin if any. Pin getPinByLibraryPin(LibraryPin lpin) const; //! @brief Changes the library cell of this cell. The new library cell must //! have the same interface (i.e. pin names and directions) as the //! old one. void remap(LibraryCell libraryCell); //! @brief Changes the library cell of this cell. The new library cell must //! have the same interface (i.e. pin names and directions) as the //! old one. void remap(const std::string &libraryCellName); }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/Design.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { // ----------------------------------------------------------------------------- //! @brief A proxy class representing the design netlist. class Design : public Proxy { friend class RawPointer; friend class Session; friend class Library; friend class Net; friend class Cell; friend class Pin; friend class Instance; friend class Module; friend class Sandbox; friend class SandboxNet; friend class SandboxInstance; template friend class AttributeBase; template friend class AttributeImplementation; private: Design(DesignData * data) : Proxy(data) {} //! @brief Create a new empty design. void create(const std::string &name); public: //! @brief Default constructor. Design() {} //! @brief Assignment constructor to allow null values. Design(std::nullptr_t) {} //! @brief Creates a new designs. Design(const std::string &name); //! @brief Copy operator. //! @note Not sure if this is actually necessary. I don't remember why it //! was created. Design &operator=(const Design &other) { data = other.data; return *this; } // end method //! @brief Returns the top module of the design. Module getTopModule(); //! @brief Returns the name of the design. const std::string &getName() const; //! @brief Changes the name of the design. void updateName(std::string name); private: //! @brief A default string to represent the name of null objects. static const std::string NULL_NAME; //! @brief Generates an unique name for a new instance. std::string generateUniqueInstanceName(const std::string &prefix); //! @brief Generates an unique name for a new net. std::string generateUniqueNetName(const std::string &prefix); //! @brief Generates the next sign to be used in some traversal algorithms //! as topological sorting. int generateNextSign(); //! @brief Gets the current sign to be used in some traversal algorithms as //! topological sorting. int getSign() const; //////////////////////////////////////////////////////////////////////////// // Unique Identifiers for Rsyn Objects //-------------------------------------------------------------------------- // Currently Rsyn uses unique identifiers (indexes) internally to manage // layers. // // Indexes should not be exposed to users as they are merely an internal // way to support layers and this scheme may be changed in the future. // // Layers allow users to associate data to the several Rsyn objects. // Moreover layers are aware to incremental changes in the netlist. //////////////////////////////////////////////////////////////////////////// private: //! @brief Gets the internal id of a net. Index getId(Net net) const; //! @brief Gets the internal id of an instance. Index getId(Instance instance) const; //! @brief Gets the internal id of a pin. Index getId(Pin pin) const; //! @brief Gets the internal id of an arc. Index getId(Arc arc) const; //! @brief Gets the internal id of a library cell. Index getId(LibraryCell lcell) const; //! @brief Gets the internal id of a library pin. Index getId(LibraryPin lpin) const; //! @brief Gets the internal id of a library arc. Index getId(LibraryArc larc) const; //////////////////////////////////////////////////////////////////////////// // Library //////////////////////////////////////////////////////////////////////////// public: //! @brief Creates a new library cell. LibraryCell createLibraryCell(const CellDescriptor &dscp, const bool ignoreDuplicated = false); //////////////////////////////////////////////////////////////////////////// // Netlist //////////////////////////////////////////////////////////////////////////// private: //! @brief Instantiates a new cell inside a module. Cell createCell(const Module parent, const LibraryCell lcell, const std::string &name); //! @brief Instantiates a new port inside a module. Port createPort(Module parent, const Direction direction, const std::string &name); //! @brief Creates a new module. Module createModule(const LibraryModule lmoudle, const std::string &name); //! @brief Instantiates a new net inside a module. Net createNet(Module parent, const std::string &name); //! @brief Connects a pin to a net. void connectPin(Pin pin, Net net); //! @brief Disconnect a pin. void disconnectPin(Pin pin); //! @brief Changes the library cell of a cell. The new library cell must //! have the same interface (i.e. pin names and directions) as the //! old one. void remap(Cell cell, LibraryCell newLibraryCell); //! @brief Changes the library cell of a cell. The new library cell must //! have the same interface (i.e. pin names and directions) as the //! old one. void remap(Cell cell, const std::string &newLibraryCellName); public: //! @brief Gets the current number of instances in the design. int getNumInstances() const; //! @brief Gets the current number of instances of a given type in the //! design. int getNumInstances(const InstanceType type) const; //! @brief Gets the current number of nets in the design. int getNumNets() const; //! @brief Gets the current number of pins in the design. int getNumPins() const; Range> getAllCells() const; //////////////////////////////////////////////////////////////////////////// // Topological Ordering //////////////////////////////////////////////////////////////////////////// private: //! @brief Updates incrementally the topological ordering given a change in //! a pin (e.g. pin gets connected). void updateTopologicalIndex(Pin pin); //////////////////////////////////////////////////////////////////////////// // Events //////////////////////////////////////////////////////////////////////////// public: //! @brief Registers an observer to be notified about changes in the //! netlist. template void registerObserver(T *observer); //! @brief Unregisters an observer so it will no longer receives //! notifications about changes in the netlist. void unregisterObserver(DesignObserver *observer); //! @brief Notifies about a change in an instance placement. Usually this //! does not need to be done manually, but notification can be turned off //! and then observer must be manually notified. //! @todo Return also the old position. void notifyInstancePlaced(Rsyn::Instance instance, Rsyn::DesignObserver *ignoreObserver = nullptr); //////////////////////////////////////////////////////////////////////////// // Searching //////////////////////////////////////////////////////////////////////////// public: //! @brief Finds an instance by name. If the instance is not found, returns //! null. Instance findInstanceByName(const std::string &name) const; //! @brief Finds a cell by name. If the cell is not found, returns null. Cell findCellByName(const std::string &name) const; //! @brief Finds a port by name. If the port is not found, returns null. Port findPortByName(const std::string &name) const; //! @brief Finds a module by name. If the module is not found, returns //! null. Module findModuleByName(const std::string &name) const; //! @brief Finds a library cell by name. If the library cell is not found, //! returns null. LibraryCell findLibraryCellByName(const std::string &name) const; //! @brief Finds a net by name. If the net is not found, returns null. Net findNetByName(const std::string &name) const; //! @brief Finds a pin by name. If the pin is not found, returns null. //! @note A pin name is in the form :. Pin findPinByName(const std::string &cellName, const std::string &pinName) const; //! @brief Finds a pin by name. If the pin is not found, returns null. //! @note A pin name is in the form :. Pin findPinByName(const std::string &name, const std::string::value_type separator = ':') const; //////////////////////////////////////////////////////////////////////////// // Attributes //////////////////////////////////////////////////////////////////////////// public: //! @brief Creates an object attribute. AttributeInitializer createAttribute(); //! @brief Creates an object attribute with a default value. template AttributeInitializerWithDefaultValue createAttribute(const DefaultValueType &defaultValue); //////////////////////////////////////////////////////////////////////////// // User Flags //////////////////////////////////////////////////////////////////////////// public: //! @brief Gets the tag information associate to a net. NetTag getTag(Rsyn::Net net); //! @brief Gets the tag information associate to an instance. InstanceTag getTag(Rsyn::Instance instance); //! @brief Gets the tag information associate to a library cell. LibraryCellTag getTag(Rsyn::LibraryCell libraryCell); //////////////////////////////////////////////////////////////////////////// // Range-Based Loops //////////////////////////////////////////////////////////////////////////// //! @brief Returns an iterable collection of all library cells in the //! design. //! @todo This should be removed once we concentrate everything library //! related in Rsyn::Library. Range> allLibraryCells(const bool showDeprecatedMessage = true); }; // end class //////////////////////////////////////////////////////////////////////////////// // Range-Based Loop Collections //////////////////////////////////////////////////////////////////////////////// //! @brief TODO template class GenericListCollection { protected: ConstList list; typename ConstList::Iterator it; public: GenericListCollection(const List &pins) : list(pins), it(list.begin()) {} bool filter() { return false; } bool stop() { return it.stopFlag(); } void next() { ++it; } Reference current() { return &((*it).getPointer()->value); } // TODO: awful }; // end class // ------------------------------------------------------------------------- //! @brief TODO template class GenericReferenceListCollection { protected: ConstList list; typename ConstList::Iterator it; public: GenericReferenceListCollection(const List &pins) : list(pins), it(list.begin()) {} bool filter() { return false; } bool stop() { return it.stopFlag(); } void next() { ++it; } Reference current() { return (*it).getPointer()->value; } // TODO: awful }; // end class // ------------------------------------------------------------------------- //! @brief TODO template class CollectionOfGenericPinsFilteredByDirection { protected: std::vector &pins; Direction direction; int index; bool filterPG; public: CollectionOfGenericPinsFilteredByDirection(std::vector &pins, Direction direction, bool filterPG = true) : pins(pins), direction(direction), index(0), filterPG(filterPG) {} bool filter() { return current().getDirection() != direction || (filterPG && current().isPowerOrGround()); } bool stop() { return index >= pins.size(); } void next() { ++index; } PinType current() { return pins[index]; } }; // end class // ------------------------------------------------------------------------- //! @brief TODO template class CollectionOfGenericPins { protected: std::vector &pins; int index; bool filterPG; public: CollectionOfGenericPins(std::vector &pins, bool filterPG = true) : pins(pins), index(0), filterPG(filterPG) {} bool filter() { return filterPG && current().isPowerOrGround(); } bool stop() { return index >= pins.size(); } void next() { ++index; } PinType current() { return pins[index]; } }; // end class // ------------------------------------------------------------------------- //! @brief TODO class CollectionOfLibraryPinsFilteredByDirection { protected: std::vector &pins; Direction direction; int index; public: CollectionOfLibraryPinsFilteredByDirection( std::vector &pins, Direction direction) : pins(pins), direction(direction), index(0) {} bool filter() { return current().getDirection() != direction; } bool stop() { return index >= pins.size(); } void next() { ++index; } LibraryPin current() { return pins[index]; } }; // end class // ------------------------------------------------------------------------- //! @brief TODO class CollectionOfLibraryPins { protected: std::vector &pins; int index; public: CollectionOfLibraryPins(std::vector &pins) : pins(pins), index(0) {} bool filter() { return false; } bool stop() { return index >= pins.size(); } void next() { ++index; } LibraryPin current() { return pins[index]; } }; // end class // ------------------------------------------------------------------------- //! @brief TODO template class CollectionOfGenericArcs { protected: std::vector &arcs; int index; public: CollectionOfGenericArcs(std::vector &arcs) : arcs(arcs), index(0) {} bool filter() { return false; } bool stop() { return index >= arcs.size(); } void next() { ++index; } ArcType current() { return arcs[index]; } }; // end class // ------------------------------------------------------------------------- //! @brief TODO class CollectionOfLibraryArcs { protected: std::vector &arcs; int index; public: CollectionOfLibraryArcs(std::vector &arcs) : arcs(arcs), index(0) {} bool filter() { return false; } bool stop() { return index >= arcs.size(); } void next() { ++index; } LibraryArc current() { return arcs[index]; } }; // end class // ------------------------------------------------------------------------- //! @brief TODO class CollectionOfLibraryArcsToLibraryPin { protected: const std::vector &arcs; LibraryPin to; size_t index; public: CollectionOfLibraryArcsToLibraryPin(const std::vector &arcs, LibraryPin to) : arcs(arcs), to(to) { index = 0; } // end constructor bool filter() { return arcs[index].getToLibraryPin() != to; } bool stop() { return index >= arcs.size(); } void next() { index++; } LibraryArc current() { return arcs[index]; } }; // end class // ------------------------------------------------------------------------- //! @brief TODO class CollectionOfLibraryArcsFromLibraryPin { protected: const std::vector &arcs; LibraryPin from; size_t index; public: CollectionOfLibraryArcsFromLibraryPin(const std::vector &arcs, LibraryPin from) : arcs(arcs), from(from) { index = 0; } // end constructor bool filter() { return arcs[index].getFromLibraryPin() != from; } bool stop() { return index >= arcs.size(); } void next() { index++; } LibraryArc current() { return arcs[index]; } }; // end class // ------------------------------------------------------------------------- //! @brief TODO //! @todo Update this when net arcs are implemented. template class CollectionOfGenericPredecessorPins { protected: std::vector pins; int index; public: CollectionOfGenericPredecessorPins(PinType pin, const bool crossBoundary) { switch (pin.getDirection()) { case IN: { NetType net = pin.getNet(); if (net) { pins.reserve(net.getNumDrivers()); for (PinType predecessor : net.allPins(DRIVER)) { pins.push_back(predecessor); } // end for } // end if break; } // end case case OUT: { if (pin.isPort()) { // An output pin means an input port. if (crossBoundary) { PinType related = pin.getPort().getOtherPin(pin); if (related) { pins.push_back(related); } // end if } // end if } else { for (ArcType arc : pin.allIncomingArcs()) { pins.push_back(arc.getFromPin()); } // end for } break; } // end case default: std::cout << "[ERROR] 1e1673fccd9b42d225b502a273cb3a20\n"; std::exit(1); } // end switch index = 0; } // end constructor bool filter() { return false; } bool stop() { return index >= pins.size(); } void next() { ++index; } PinType current() { return pins[index]; } }; // end class // ------------------------------------------------------------------------- //! @brief TODO //! @todo Update this when net arcs are implemented. template class CollectionOfGenericSuccessorPins { protected: std::vector pins; int index; public: CollectionOfGenericSuccessorPins(PinType pin, const bool crossBoundary) { switch (pin.getDirection()) { case IN: { if (pin.isPort()) { // An input pin means an output port. if (crossBoundary) { PinType related = pin.getPort().getOtherPin(pin); if (related) { pins.push_back(related); } // end if } // end if } else { for (ArcType arc : pin.allOutgoingArcs()) { pins.push_back(arc.getToPin()); } // end for } // end else break; } // end case case OUT: { NetType net = pin.getNet(); if (net) { pins.reserve(net.getNumSinks()); for (PinType successor : net.allPins(SINK)) { pins.push_back(successor); } // end for } // end if break; } // end case default: std::cout << "[ERROR] 44167c065ebd3a23a553fdd96301831e\n"; std::exit(1); } // end switch index = 0; } // end constructor bool filter() { return false; } bool stop() { return index >= pins.size(); } void next() { ++index; } PinType current() { return pins[index]; } }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/Instance.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a netlist instance (i.e. cell, port or //! module). class Instance : public Proxy { RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; friend class RawPointer; friend class Design; friend class Pin; friend class Cell; friend class Port; friend class Module; // Temporary while we merge some physical data into the netlist (2018/01/17). friend class PhysicalDesign; friend class PhysicalService; private: Instance(InstanceData * data) : Proxy(data) {} DesignData * _getDesignData() const; Design _getDesign() const; Module _getParent() const; // TODO: remove, use -> instead DesignData * getDesignData(); const DesignData * getDesignData() const; public: //! @brief Default constructor. Instance() {} //! @brief Assignment constructor to allow null values. Instance(std::nullptr_t) {} //! @brief Converts this instance to a cell. Cell asCell() const; //! @brief Converts this instance to a port. Port asPort() const; //! @brief Converts this instance to a module. Module asModule() const; //! @brief Returns the design in which this instance is instantiated. Design getDesign(); //! @brief Returns the design in which this instance is instantiated. const Design getDesign() const; //! @brief Returns the parent module in which this instance is instantiated. Module getParent(); //! @brief Returns the parent module in which this instance is instantiated. const Module getParent() const; //! @brief Returns the type of this instance. InstanceType getType() const; //! @brief Returns the name of this instance. const std::string &getName() const; //! @brief Returns the hierarchical name of this instance. std::string getHierarchicalName() const; //! @brief Returns the number of interface pin. int getNumPins() const; //! @brief Returns the number of interface pin of a given direction. int getNumPins(const Direction direction) const; //! @brief Returns the number of interface input pin. int getNumInputPins() const; //! @brief Returns the number of interface output pin. int getNumOutputPins() const; //! @brief Returns the number of interface bidirectional pin. int getNumBidirectionalPins() const; //! @brief Returns the number of arcs. int getNumArcs() const; //! @brief Returns a pin by its index. Pin getPinByIndex(const int index) const; //! @brief Returns a pin by its name. If no pin matches, null is returned. Pin getPinByName(const std::string &name) const; //! @brief Returns any input pin. Useful when handling buffers/inverters, //! which have only one input pin. Pin getAnyInputPin() const; //! @brief Returns any output pin. Useful when handling buffers/inverters, //! which have only one output pin. Pin getAnyOutputPin() const; //! @brief Returns the arc from the "from" pin to the "to" pin. Returns null //! if the pins do not belong to this instance or if no such arc is //! found. Arc getArc(const Pin from, const Pin to); //! @brief Returns the arc from the "from" pin to the "to" pin. Returns null //! if either pin is not found or if no such arc exist between the //! pins. Arc getArcByPinNames(const std::string &from, const std::string &to); //! @brief Returns any arc. Useful when handling buffers/inverters, which //! have only one arc. Arc getAnyArc(); //! @brief Returns the library cell associated to this instance if any. LibraryCell getLibraryCell() const; //! @brief Returns the topological index of this instance. //! @note Since the topological index of an instance may be ambiguous (e.g. //! for register), some choice needed to be made here. Currently, //! the topological index of an instance is the maximum topological //! index of the "from" pins of its arcs. If no arcs, the topological //! index is set to the maximum topological index of all pins. //! In this way, the topological index of registers is given by their //! clock pin rather than by their data pin. TopologicalIndex getTopologicalIndex() const; //! @brief Returns true if this instance represents a port. bool isPort() const; //! @brief Returns true if this instance represents a port and the port //! matches the given direction. bool isPort(const Direction direction); //! @brief Returns an iterable collection of all interface pins of a given //! direction. //! @note The name of this method may be confusing for modules where one //! may expect the collection of all pins inside the module. However //! to be consistent, only the interface pins are returned that is //! the outer pins of the module's ports. Range allPins(const Direction direction, bool filterPG = true) const; //! @brief Returns an iterable collection of all interface pins. //! @see allPins(const Direction direction) Range allPins(bool filterPG = true) const; //! @brief Returns an iterable collection of all arcs. Range allArcs() const; //! @brief Returns true if this instance represents a sequential cell and //! false otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isSequential() const; //! @brief Returns true if this instance represents a tie cell and false //! otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isTie(const TieType type) const; //! @brief Returns true if this instance represents a buffer cell of a given //! type and false otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isBuffer(const BufferType type) const; //! @brief Returns true if this instance represents a buffer cell of a given //! type, which is driven by a clock network and false otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isClockBuffer(const BufferType type = ANY_BUFFER_TYPE, const bool local = false) const; //! @brief Returns true if this instance represents a local clock buffer of //! a given type and false otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isLCB(const BufferType type = ANY_BUFFER_TYPE) const; //! @brief Returns true if this instance cannot be moved (i.e. has its //! position fixed) and false otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isFixed() const; //! @brief Returns true if this instance can be moved and false otherwise. //! @see isFixed() //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isMovable() const; //! @brief Returns true if this instance represents a non-standard-cell and //! false otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isMacroBlock() const; //! @brief Returns true if this instance orientation is flipped. //! @see isFlipped() bool isFlipped() const; //! @brief Returns the x position (lower-left) of the instance. DBU getX() const; //! @brief Returns the y position (lower-left) of the instance. DBU getY() const; //! @brief Returns the height of this instance. DBU getHeight() const; //! @brief Returns the width of this instance. DBU getWidth() const; //! @brief Returns the size of this instance. //! @note X is the length for abscissa (width) while in Y is the length for //! ordinate (height). DBUxy getSize() const; //! @brief Returns the size of this instance. //! @todo Rename to getSize(). DBU getSize(const Dimension dimension) const; //! @brief Returns the area of this instance. DBU getArea() const; //! @brief Returns the lower-left position of this instance. DBUxy getPosition() const; //! @brief Returns the lower-left position of this instance. //! that is defined as its position. DBU getPosition(const Dimension dim) const; //! @brief Returns the lower-left/upper-right position of this instance. //! @todo remove DBUxy getCoordinate(const Boundary bound) const; //! @brief Returns the lower-left/upper-right position of this instance. //! @todo remove DBU getCoordinate(const Boundary bound, const Dimension dim) const; //! @brief Returns the central point of the PhysicalInstance boundaries. DBUxy getCenter() const; //! @brief Returns the center position in a given dimension. DBU getCenter(const Dimension dim) const; //! @brief Returns the orientation of the cell. PhysicalOrientation getOrientation() const; //! @brief Returns a transformation that allows one to transform the //! coordinates from the library cell space to the cell space. The //! transformation accounts for translation and the orientation of the cell. //! @param origin If set to true, the transform is created w.r.t (0, 0) and //! not the current cell position. PhysicalTransform getTransform(const bool origin = false) const; //! @brief Returns the bound box Bounds that defines the limits of PhysicalInstance. const Bounds &getBounds() const; }; // end class // ============================================================================= // Tag // ============================================================================= //! @brief TODO class InstanceTag : public Proxy { friend class Design; private: InstanceTag(InstanceTagData * data) : Proxy(data) {} public: InstanceTag() {} InstanceTag(std::nullptr_t) {} TristateFlag getFixed() const; TristateFlag getMacroBlock() const; void setFixed(const bool value); void setMacroBlock(const bool value); }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/Library.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { // ----------------------------------------------------------------------------- //! @brief A proxy class representing the library (or set of libraries). //! @note For now this class is kinda dummy and uses the design to do //! everything. It should gain importance when we separate more clearly design //! and library data. class Library : public Proxy { friend class Session; public: Library() {} //! @brief Returns an iterable collection of all library cells in the //! design. //! @todo This should be removed once we concentrate everything library //! related in Rsyn::Library. Range> allLibraryCells(); private: Library(LibraryData * data) : Proxy(data) {} }; // end class // ----------------------------------------------------------------------------- } // end method ================================================ FILE: rsyn/src/rsyn/core/obj/decl/LibraryArc.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a library arc. class LibraryArc : public Proxy { RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; friend class RawPointer; friend class Design; friend class Arc; friend class Sandbox; friend class SandboxArc; private: LibraryArc(LibraryArcData * data) : Proxy(data) {} public: //! @brief Default constructor. LibraryArc() {} //! @brief Assignment constructor to allow null values. LibraryArc(std::nullptr_t) {} //! @brief Returns the design in which this library arc was created. Design getDesign(); //! @brief Returns the design in which this library arc was created. const Design getDesign() const; //! @brief Returns the name of this libary arc (e.g a -> o). std::string getName() const; //! @brief Returns the full name of this libary arc (e.g nand:a -> nand:o). std::string getFullName() const; //! @brief Returns the name of the "from" library pin. std::string getFromName() const; //! @brief Returns the name of the "to" library pin. std::string getToName() const; //! @brief Returns the library cell to which this library arc belongs to. LibraryCell getLibraryCell() const; //! @brief Returns the "from" library pin. LibraryPin getFromLibraryPin() const; //! @brief Returns the "to" library pin. LibraryPin getToLibraryPin() const; //! @brief Returns the index of this arc relative to the library cell. int getIndex() const; }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/LibraryCell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a library cell. class LibraryCell : public Proxy { RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; friend class RawPointer; friend class Design; friend class Pin; friend class Cell; friend class Sandbox; friend class SandboxPin; friend class SandboxCell; friend class PhysicalDesign; private: LibraryCell(LibraryCellData * data) : Proxy(data) {} public: //! @brief Default constructor. LibraryCell() {} //! @brief Assignment constructor to allow null values. LibraryCell(std::nullptr_t) {} //! @brief Returns the design in which this library cell was created. Design getDesign(); //! @brief Returns the design in which this library cell was created. const Design getDesign() const; //! @brief Returns the name of this library cell. const std::string &getName() const; //! @brief Returns the number of interface pin. int getNumPins() const; //! @brief Returns the number of interface pin of a given direction. int getNumPins(const Direction direction) const; //! @brief Returns the number of interface input pin. int getNumInputPins() const; //! @brief Returns the number of interface output pin. int getNumOutputPins() const; //! @brief Returns the number of interface bidirectional pin. int getNumBidirectionalPins() const ; //! @brief Returns the number of arcs. int getNumArcs() const; //! @brief Returns a library pin by its index. LibraryPin getLibraryPinByIndex(const int index) const; //! @brief Returns a library pin by its name. If no pin matches, null is //! returned. LibraryPin getLibraryPinByName(const std::string &name) const; //! @brief Returns any input library pin. Useful when handling //! buffers/inverters, which have only one input pin. LibraryPin getAnyInputLibraryPin(); //! @brief Returns any output library pin. Useful when handling //! buffers/inverters, which have only one output pin. LibraryPin getAnyOutputLibraryPin(); //! @brief Returns the library arc from the "from" pin to the "to" pin. //! Returns null if the library pins do not belong to this instance //! or if no such arc is found. LibraryArc getLibraryArc(const Rsyn::LibraryPin from, const Rsyn::LibraryPin to) const; //! @brief Returns the library arc by its index. LibraryArc getLibraryArcByIndex(const int index) const; //! @brief Returns the library arc from the "from" pin to the "to" pin. //! Returns null if either pin is not found or if no such arc exist //! between the pins. LibraryArc getLibraryArcByPinNames(const std::string &from, const std::string &to) const; //! @brief Returns any arc. Useful when handling buffers/inverters, which //! have only one arc. LibraryArc getAnyLibraryArc() const; //! @brief Returns an iterable collection of all interface library pins of //! a given direction. Range allLibraryPins(const Direction direction) const; //! @brief Returns an iterable collection of all interface library pins. Range allLibraryPins() const; //! @brief Returns an iterable collection of all arcs. Range allLibraryArcs() const; //! @brief Returns true if this library cell represents a sequential cell //! and false otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isSequential() const; //! @brief Returns true if this library cell represents a combinational cell //! and false otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isCombinational() const; //! @brief Returns true if this library cell represents a tie cell and false //! otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isTie(const TieType type = ANY_TIE_TYPE) const; //! @brief Returns true if this library cell represents a buffer cell of a //! given type and false otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isBuffer(const BufferType type) const; // Physical // -------- //! @brief Returns the Instance height. DBU getHeight() const; //! @brief Returns the Instance width. DBU getWidth() const; //! @brief Returns the size of this library cell. DBUxy getSize() const; //! @brief Returns the size of the library cell in a given dimension. DBU getSize(const Dimension dimension) const; //! @brief Returns the area of this library cell. DBU getArea() const; }; // end class // ============================================================================= // Tag // ============================================================================= //! @brief TODO class LibraryCellTag : public Proxy { friend class Design; private: LibraryCellTag(LibraryCellTagData * data) : Proxy(data) {} public: LibraryCellTag() {} LibraryCellTag(std::nullptr_t) {} LogicTypeTag getLogicType() const; TieTypeTag getTieType() const; BufferTypeTag getBufferTypeTag() const; void setLogicType(const LogicTypeTag value); void setTieType(const TieTypeTag value); void setBufferType(const BufferTypeTag value); }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/LibraryModule.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a library module //! @note This is not used yet. class LibraryModule : public Proxy { RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; friend class RawPointer; friend class Design; private: LibraryModule(LibraryModuleData * data) : Proxy(data) {} public: //! @brief Default constructor. LibraryModule() {} //! @brief Assignment constructor to allow null values. LibraryModule(std::nullptr_t) {} //! @brief Returns the design in which this library module was created. Design getDesign(); //! @brief Returns the design in which this library module was created. const Design getDesign() const; }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/LibraryPin.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a library arc. class LibraryPin : public Proxy { RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; friend class RawPointer; friend class Design; friend class Cell; friend class Sandbox; friend class SandboxCell; private: LibraryPin(LibraryPinData * data) : Proxy(data) {} public: //! @brief Default constructor. LibraryPin() {} //! @brief Assignment constructor to allow null values. LibraryPin(std::nullptr_t) {} //! @brief Returns the design in which this library pin was created. Design getDesign(); //! @brief Returns the design in which this library pin was created. const Design getDesign() const; //! @brief Returns the name of this library pin. const std::string &getName() const; //! @brief Returns the names of this library cell and pin . std::string getHierarchicalName(const std::string & separator = ":") const; //! @brief Returns the direction name of this library pin. const std::string &getDirectionName() const; //! @brief Returns the library cell name associated to this library pin. const std::string &getLibraryCellName() const; //! @brief Returns the direction of this library pin. Direction getDirection() const; //! @brief Returns the library cell of this library pin. LibraryCell getLibraryCell() const; //! @brief Returns the index of this library pin inside its library cell. int getIndex() const; //! @brief Returns true if this library pin is an input and false otherwise. bool isInput() const; //! @brief Returns true if this library pin is an output and false //! otherwise. bool isOutput() const; //! @brief Returns true if this library pin is a bidirectional and false //! otherwise. bool isBidirectional() const; //! @Author Mateus //! @brief Returns the usage of the pin Use getUse() const; //! @Author Mateus //! @brief Returns true if the pin is used for power or ground or false //! otherwise. bool isPowerOrGround() const; }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/Module.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a netlist module. class Module : public Instance { RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; friend class RawPointer; friend class Design; friend class Instance; private: Module(InstanceData * data) : Instance(data) {} //! @brief Generates the next sign to be used in some traversal algorithms //! as topological sorting. int generateNextSign() const; //! @brief Gets the current sign to be used in some traversal algorithms as //! topological sorting. int getSign() const; //! @brief This method is inherited from Instance. Hide to avoid confusion //! with internal pins. See allInterfacePins() and allInternalPins(). Range allPins(const Direction direction) const; //! @brief This method is inherited from Instance. Hide to avoid confusion //! with internal pins. See allInterfacePins() and allInternalPins(). Range allPins() const; //! @brief This method is inherited from Instance. Hide to avoid confusion //! with internal pins. See allInterfaceArcs() and allInternalArcs(). Range allArcs() const; public: //! @brief Default constructor. Module() : Instance(nullptr) {} //! @brief Assignment constructor to allow null values. Module(std::nullptr_t) : Instance(nullptr) {} //! @brief Returns the design in which this module is instantiated. Design getDesign(); //! @brief Returns the design in which this module is instantiated. const Design getDesign() const; //! @brief Creates a new cell in this module. If no name is provided, an //! automatically generated name will be used. Cell createCell(const std::string &libraryCellName, const std::string &cellName = ""); //! @brief Creates a new cell in this module. If no name is provided, an //! automatically generated name will be used. Cell createCell(const LibraryCell lcell, const std::string &name = ""); //! @brief Creates a new port in this module. If no name is provided, an //! automatically generated name will be used. Port createPort(const Direction &direction, const std::string &name = ""); //! @brief Creates a new net in this module. If no name is provided, an //! automatically generated name will be used. Net createNet(const std::string &name = ""); //! @brief Returns a port by its index. Port getPortByIndex(const int index); //! @brief Constructs a vector of instances stratified by logical depth such //! that all cells with logical depth "i" will be at index "i". //! @note See Instance::getTopologicalIndex() description to check how //! the topological index of instances is defined. void getInstancesPerLogicalDepth(std::vector> &levels); //! @brief Constructs a vector of nets stratified by logical depth such //! that all nets with logical depth "i" will be at index "i". //! @note See Net::getTopologicalIndex() description to check how //! the topological index of nets is defined. void getNetsPerLogicalDepth(std::vector> &levels); //! @brief Returns the number of ports of a given directions. int getNumPorts(const Direction direction) const; //! @brief Returns an iterable collection of all instances instantiated in //! this module. Range> allInstances() const; //! @brief Returns an iterable collection of all ports instantiated in this //! module. Range> allPorts() const; //! @brief Returns an iterable collection of all ports of a given direction //! inside this module. std::set & allPorts(const Rsyn::Direction direction) const; //! @brief Returns an iterable collection of all nets instantiated in this //! module. Range> allNets() const; //! @brief Returns an iterable collection of all interface pins of a given //! direction. Range allInterfacePins(const Direction direction) const; //! @brief Returns an iterable collection of all interface pins (i.e. outer //! pin of ports. //! @see allInterfacePins(const Direction direction) Range allInterfacePins() const; //! @brief Returns an iterable collection of all arcs. Range allInterfaceArcs() const; //! @brief Returns an iterable collection of all pins of instances that are //! directly child of this module. Range allInternalPins(const Direction direction) const; //! @brief Returns an iterable collection of all pins of instances that are //! directly child of this module. Range allInternalPins() const; //! @brief Returns an iterable collection of all arcs of instances that are //! directly child of this module. Range allInternalArcs() const; //! @brief Returns an iterable collection of all pins instantiated in this //! module in topological order (from inputs to outputs). std::vector> allPinsInTopologicalOrder() const; //! @brief Returns an iterable collection of all pins instantiated in this //! module in reverse topological order (from outputs to inputs). std::vector> allPinsInReverseTopologicalOrder() const; //! @brief Returns an iterable collection of all nets instantiated in this //! module in topological order (from inputs to outputs). //! @note See Net::getTopologicalIndex() description to check how //! the topological index of nets is defined. std::vector> allNetsInTopologicalOrder() const; //! @brief Returns an iterable collection of all nets instantiated in this //! module in reverse topological order (from outputs to inputs). //! @note See Net::getTopologicalIndex() description to check how //! the topological index of nets is defined. std::vector> allNetsInReverseTopologicalOrder() const; //! @brief Returns an iterable collection of all instances instantiated in //! this module in topological order (from inputs to outputs). //! @note See Instance::getTopologicalIndex() description to check how //! the topological index of instances is defined. std::vector> allInstancesInTopologicalOrder() const; //! @brief Returns a vector with the nets in the fanout cone of a pin. The //! nets are sorted in breadth-first order (which is not the same as //! topological order). Breadth-first order is typically faster than //! topological order. If not null, the first net is always the net //! to which the seed pins is connected to. std::vector getFanoutConeNetsInBreadthFirstOrder(Rsyn::Pin seed) const; //! @brief Returns a vector with the nets in the fan-in cone of a pin. The //! nets are sorted in breadth-first order (which is not the same as //! topological order). Breadth-first order is typically faster than //! topological order. If not null, the first net is always the net //! to which the seed pins is connected to. std::vector getFaninConeNetsInBreadthFirstOrder(Rsyn::Pin seed) const; }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/Net.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a netlist net. class Net : public Proxy { RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; friend class RawPointer; friend class Design; friend class Module; friend class Pin; friend class Arc; private: Net(NetData * data) : Proxy(data) {} Design _getDesign() const; Module _getParent() const; public: //! @brief Default constructor. Net() {} //! @brief Assignment constructor to allow null values. Net(std::nullptr_t) {} //! @brief Returns the design in which this net was instantiated. Design getDesign(); //! @brief Returns the design in which this net was instantiated. const Design getDesign() const; //! @brief Returns the parent module in which this net was instantiated. Module getParent(); //! @brief Returns the parent module in which this net was instantiated. const Module getParent() const; //! @brief Returns the name of this net. const std::string &getName() const; //! @brief Returns the number of pins connected to this net. int getNumPins() const; //! @brief Returns the number of sinks (input) pins connected to this net. int getNumSinks() const; //! @brief Returns the number of drivers (output) pins connected to this //! net. int getNumDrivers() const; //! @brief Returns any driver pin if any. Useful when there's an assumption //! that nets have a single driver (most common case). Pin getAnyDriver() const; //! @brief Returns the arc connecting the "from" pin to the "to" pin if any. //! @note Net arcs only exist from driver to sink pins. Arc getArc(const Pin from, const Pin to); //! @brief Returns the topological index of this net. //! @note The topological index of a net is the maximum topological index //! of its drivers. If no drivers, it's the maximum topological index //! of its sinks. If this is a floating net (no pins), returns the //! constant value Rsyn::MIN_TOPOLOGICAL_INDEX. TopologicalIndex getTopologicalIndex() const; //! @brief Returns true if this net has more than one driver pin and false //! otherwise. bool hasMultipleDrivers() const; //! @brief Returns true if this net has only and only one driver and false //! otherwise. bool hasSingleDriver() const; //! @brief Returns true if this net has at least one driver and false //! otherwise. bool hasDriver() const; //! @brief Returns true if this net has at least one sink and false //! otherwise. bool hasSink() const; //! @brief Returns an iterable collection of the pins connected to this //! net. Range allPins(bool filterPG = true) const; //! @brief Returns an iterable collection of the pins of a given direction //! connected to this net. Range allPins(const Direction direction) const; //! @brief Returns an iterable collection of the arcs spanned by this net. Range allArcs() const; //! @brief Returns true if this net should be considered as ideal and false //! otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isIdeal() const; //! @brief Returns true if this net represents a clock network. //! @note A clock network net does not need to be directly connected to the //! clock port. Internal nets of a clock buffer tree should also be //! considered as clock networks. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isClockNetwork() const; //! @brief Returns the type ot this net. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. NetTypeTag getNetTypeTag() const; //! @Author Mateus //! @brief Returns the usage of the net Use getUse() const; //! @Author Mateus //! @brief Returns the usage of the net void setUse(const Use use); }; // end class // ============================================================================= // Tag // ============================================================================= //! @brief TODO class NetTag : public Proxy { friend class Design; private: NetTag(NetTagData * data) : Proxy(data) {} public: NetTag() {} NetTag(std::nullptr_t) {} NetTypeTag getType() const; TristateFlag getIdeal() const; void setType(const NetTypeTag value); void setIdeal(const bool value); }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/Object.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { // TODO create a base class for everyone... } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/Pin.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a netlist pin. class Pin : public Proxy { RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; friend class RawPointer; friend class Design; friend class Port; friend class Net; private: Pin(PinData * data) : Proxy(data) {} public: //! @brief Default constructor. Pin() {} //! @brief Assignment constructor to allow null values. Pin(std::nullptr_t) {} //! @brief Returns the design in which this pin is instantiated. Design getDesign(); //! @brief Returns the design in which this pin is instantiated. const Design getDesign() const; //! @brief Returns the direction of this pin. Direction getDirection() const; //! @brief Returns the index of this pin relative to its instance and //! library cell. int getIndex() const; //! @brief Returns the name of this pin. const std::string getName() const; //! @brief Returns the full name of this pin (e.g. nand:a). const std::string getFullName(const std::string::value_type separator = ':') const; //! @brief Returns the name of the instance which this pin belongs to. const std::string getInstanceName() const; //! @brief Returns the name of the net which this pin connects to if any. const std::string &getNetName() const; //! @brief Returns the direction name of this pin. const std::string &getDirectionName() const; //! @brief Returns the net which this pin connects to if any. Net getNet() const; //! @brief Returns the instance which this pin belongs to. Instance getInstance() const; //! @brief Returns the type of the instance which this pin belongs to. InstanceType getInstanceType() const; //! @brief Returns the library pin associate to this pin if any. //! @note Only pins from cells are associated to library pins. LibraryPin getLibraryPin() const; //! @brief Returns the library cell associate to this pin if any. //! @note Only pins from cells are associated to library cells. LibraryCell getLibraryCell() const; //! @brief If this pin belongs to a port instance, returns the port and //! null otherwise. Port getPort() const; //! @brief Returns the topological index of this pin. TopologicalIndex getTopologicalIndex() const; //! @brief Returns true if this pin belongs to a port instance. bool isPort() const; //! @brief Returns true if this pin belongs to a port instance of a given //! direction. bool isPort(const Direction direction) const; //! @brief Returns true if this pin belongs to a port that connects to an //! up-level hierarchy and false otherwise. bool isPortToUpLevelHierarchy() const; //! @brief Returns true if this pin belongs to a port that connects to an //! down-level hierarchy and false otherwise. bool isPortToDownLevelHierarchy() const; //! @brief Returns true if this pin is connected to a net and false //! otherwise. bool isConnected() const; //! @brief Returns true if this pin is not connected to a net and false //! otherwise. bool isDisconnected() const; //! @brief Returns true if this pin is an input pin and false otherwise. bool isInput() const; //! @brief Returns true if this pin is an output pin and false otherwise. bool isOutput() const; //! @brief Returns true if this pin is a bidirectional pin and false //! otherwise. bool isBidirectional() const; //! @brief Returns true if this pin is a driver (output) pin and false //! otherwise. bool isDriver() const; //! @brief Returns true if this pin is a sink (input) pin and false //! otherwise. bool isSink() const; //! @brief Returns the arc from this pin to the "to" pin if any. Arc getArcTo(Pin to); //! @brief Returns the arc from the "from" pin to this pin if any. Arc getArcFrom(Pin from); //! @brief Returns the number of arcs that have this pin as the "to" pin. int getNumIncomingArcs() const; //! @brief Returns the number of arcs that have this pin as the "from" pin. int getNumOutgomingArcs() const; //! @brief Returns an iterable collection of all pins that are directly //! connected to this pin via incoming arcs (i.e. all "from" pins //! of the arcs that have this pin as the "to" pin). Range allPredecessorPins(const bool crossBoundaries = false) const; //! @brief Returns an iterable collection of all pins that are directly //! connected to this pin via outgoing arcs (i.e. all "to" pins //! of the arcs that have this pin as the "from" pin). Range allSucessorPins(const bool crossBoundaries = false) const; //! @brief Returns an iterable collection of all arcs that have this pin as //! the "to" pin. const std::vector & allIncomingArcs() const; //! @brief Returns an iterable collection of all arcs that have this pin as //! the "from" pin. const std::vector & allOutgoingArcs() const; //! @brief Returns an iterable collection of all arcs given a traverse //! direction. const std::vector & allArcs(const TraverseType direction) const; //! @brief Connects this pin to a net. If the pin is currently connected, //! it will be first disconnected. void connect(Net net); //! @brief Disconnect this pin. void disconnect(); //! @brief Returns true if this pin belongs to a non-standard-cell and false //! otherwise. //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isMacroBlockPin() const; //! @brief Returns true if this pin is connected to a clock network and //! false otherwise. //! @note This should be true even if the pin is indirectly connected to //! the clock (i.e. via buffers). //! @note This is a user-defined flag. If the flag was not set, an exception //! is raised. bool isConnectedToClockNetwork() const; //! @Author Mateus //! @brief Returns the usage of the pins Use getUse() const; //! @Author Mateus //! @brief Returns true if the pin is used for power or ground or false //! otherwise. bool isPowerOrGround() const; }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/decl/Port.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { //! @brief A proxy class representing a netlist port. class Port : public Instance { RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; friend class RawPointer; friend class Design; friend class Instance; private: Port(InstanceData * data) : Instance(data) {} public: //! @brief Default constructor. Port() : Instance(nullptr) {} //! @brief Assignment constructor to allow null values. Port(std::nullptr_t) : Instance(nullptr) {} //! @brief Returns the pin inside the current level of hierarchy (module). //! @note This pin belongs to the port instance. Pin getInnerPin() const; //! @brief Returns the pin in the parent hierarchy (module). //! @note This pin does not belongs to the port instance. It belongs to the //! parent module instance. That is the outer pin is only virtually //! associated to a port. Pin getOuterPin() const; //! @brief Returns the inner/outer pin related to an outer/inner pin. //! If the outer pin is passed, returns the inner pin. //! If the inner pin is passed, returns the outer pin. //! If the pin does not match both inner and outer pins, returns //! null. //! @note The outer pin may be null if the inner pin belongs to //! a port in the top level hierarchy. Pin getOtherPin(Rsyn::Pin pin) const; //! @brief Returns the direction of this port. //! @note The direction of a port matches the direction of its inner pin. Direction getDirection() const; }; // end class } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/Arc.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline Design Arc::getDesign() { return getFromPin().getDesign(); } // end method // ----------------------------------------------------------------------------- inline const Design Arc::getDesign() const { return getFromPin().getDesign(); } // end method // ----------------------------------------------------------------------------- inline ArcType Arc::getType() const { return data->type; } // end method // ----------------------------------------------------------------------------- inline Instance Arc::getInstance() const { return data->type == INSTANCE_ARC? data->from.getInstance() : nullptr; } // end method // ----------------------------------------------------------------------------- inline Net Arc::getNet() const { return data->type == NET_ARC? data->netData : nullptr; } // end method // ----------------------------------------------------------------------------- inline LibraryArc Arc::getLibraryArc() const { return getType() == INSTANCE_ARC? data->libraryArcData : nullptr; } // end method // ----------------------------------------------------------------------------- inline LibraryCell Arc::getLibraryCell() const { Rsyn::LibraryArc larc = getLibraryArc(); return larc? larc.getLibraryCell() : nullptr; } // end method // ----------------------------------------------------------------------------- inline Pin Arc::getFromPin() const { return data->from; } // end method // ----------------------------------------------------------------------------- inline Pin Arc::getToPin() const { return data->to; } // end method // ----------------------------------------------------------------------------- inline std::string Arc::getName() const { return getFromName() + "->" + getToName(); } // end method // ----------------------------------------------------------------------------- inline std::string Arc::getFullName() const { return getType() == NET_ARC? (getFromPin().getFullName() + "->" + getToPin().getFullName()) : (getInstance().getName() + ":" + getName()); } // end method // ----------------------------------------------------------------------------- inline const std::string Arc::getFromName() const { return getFromPin().getName(); } // end method // ----------------------------------------------------------------------------- inline const std::string Arc::getToName() const { return getToPin().getName(); } // end method // ----------------------------------------------------------------------------- inline Net Arc::getFromNet() const { return getFromPin().getNet(); } // end method // ----------------------------------------------------------------------------- inline Net Arc::getToNet() const { return getToPin().getNet(); } // end method // ----------------------------------------------------------------------------- inline int Arc::getIndex() const { return getLibraryArc()? getLibraryArc().getIndex() : -1; } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/Cell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline const std::string & Cell::getLibraryCellName() const { return data->lcell->name; } // end method // ----------------------------------------------------------------------------- inline LibraryCell Cell::getLibraryCell() const { return data->lcell; } // end method // ----------------------------------------------------------------------------- inline Pin Cell::getPinByLibraryPin(const LibraryPin lpin) const { return data->pins[lpin.data->index]; } // end method // ----------------------------------------------------------------------------- inline void Cell::remap(LibraryCell libraryCell) { getDesign().remap(*this, libraryCell); } // end method // ----------------------------------------------------------------------------- inline void Cell::remap(const std::string &libraryCellName) { getDesign().remap(*this, libraryCellName); } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/Design.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline Design::Design(const std::string &name) { create(name); } // end constructor // ----------------------------------------------------------------------------- inline void Design::create(const std::string &name) { // Allocate memory for the new design. //data = std::make_shared(); data = new DesignData; data->name = name; // If no top is specified, just create an empty top for the design. data->topModule = createModule(nullptr, "__root"); } // end method // ----------------------------------------------------------------------------- inline Module Design::getTopModule() { return data->topModule; } // end method // ----------------------------------------------------------------------------- inline const std::string & Design::getName() const { return data->name; } // end method // ----------------------------------------------------------------------------- inline void Design::updateName(std::string name) { data->name = name; } // end method // ----------------------------------------------------------------------------- inline std::string Design::generateUniqueInstanceName(const std::string &prefix) { std::ostringstream oss; oss << prefix << data->anonymousInstanceId; data->anonymousInstanceId++; return oss.str(); } // end method // ----------------------------------------------------------------------------- inline std::string Design::generateUniqueNetName(const std::string &prefix) { std::ostringstream oss; oss << prefix << data->anonymousNetId; data->anonymousNetId++; return oss.str(); } // end method // ----------------------------------------------------------------------------- inline int Design::generateNextSign() { return ++data->sign; /*must be pre-increment*/ } // end method // ----------------------------------------------------------------------------- inline int Design::getSign() const { return data->sign; } // end method // ----------------------------------------------------------------------------- inline Instance Design::findInstanceByName(const std::string &name) const { auto it = data->instanceMapping.find(name); return it != data->instanceMapping.end()? it->second : nullptr; } // end method // ----------------------------------------------------------------------------- inline Cell Design::findCellByName(const std::string &name) const { Rsyn::Instance instance = findInstanceByName(name); if (instance) { return instance.getType() == Rsyn::CELL? instance.asCell() : nullptr; } else { return nullptr; } // end else } // end method // ----------------------------------------------------------------------------- inline Port Design::findPortByName(const std::string &name) const { Rsyn::Instance instance = findInstanceByName(name); if (instance) { return instance.getType() == Rsyn::PORT? instance.asPort() : nullptr; } else { return nullptr; } // end else } // end method // ----------------------------------------------------------------------------- inline Module Design::findModuleByName(const std::string &name) const { Rsyn::Instance instance = findInstanceByName(name); if (instance) { return instance.getType() == Rsyn::MODULE? instance.asModule() : nullptr; } else { return nullptr; } // end else } // end method // ----------------------------------------------------------------------------- inline LibraryCell Design::findLibraryCellByName(const std::string &name) const { auto it = data->libraryCellMapping.find(name); return it != data->libraryCellMapping.end()? it->second : nullptr; } // end method // ----------------------------------------------------------------------------- inline Net Design::findNetByName(const std::string &name) const { auto it = data->netMapping.find(name); return it != data->netMapping.end()? it->second : nullptr; } // end method // ----------------------------------------------------------------------------- inline Pin Design::findPinByName(const std::string &cellName, const std::string &pinName) const { Cell cell = findCellByName(cellName); if (cell) { return cell.getPinByName(pinName); } else { return nullptr; } // end else } // end method // ----------------------------------------------------------------------------- inline Pin Design::findPinByName(const std::string &name, const std::string::value_type separator) const { std::size_t split = name.find_first_of(separator); if (split == std::string::npos) return nullptr; const std::string cellName = name.substr(0, split); const std::string pinName = name.substr(split + 1, std::string::npos); return findPinByName(cellName, pinName); } // end method // ----------------------------------------------------------------------------- inline LibraryCell Design::createLibraryCell(const CellDescriptor &dscp, const bool ignoreDuplicated) { if (findLibraryCellByName(dscp.getName())) { if (!ignoreDuplicated) { throw LibraryCellAlreadyExistsException(dscp.getName()); } else { return nullptr; } // end if } // end if const int numPins = (int) dscp.pins.size(); const int numArcs = (int) dscp.arcs.size(); // Check if it's valid descriptor. dscp.checkConsistency(); // Creates a new cell in the data structure. LibraryCellData * lcell = &(data->libraryCells.create()->value); // TODO: awful LibraryCell libraryCell(lcell); // Initializes cell. lcell->id = data->libraryCells.lastId(); lcell->design = *this; lcell->name = dscp.getName(); // Stores library cell name. data->libraryCellMapping[lcell->name] = libraryCell; // Sort pin by names to ensure same indexes among different cells with // the same footprint. std::map mapping; for (int i = 0; i < numPins; i++) { const std::tuple &t = dscp.pins[i]; mapping[std::get<0>(t)] = i; } // end for // Initializes library cell's pins. lcell->pins.resize(numPins); for (auto element : mapping) { const int index = element.second; const std::tuple &t = dscp.pins[index]; LibraryPinData * lpin = &(data->libraryPins.create()->value); // TODO: awful lpin->id = data->libraryPins.lastId(); lpin->design = *this; lpin->index = index; lpin->lcell = libraryCell; lpin->name = std::get<0>(t); lpin->direction = std::get<1>(t); // Mateus @ 20180917: Adding PinUse lpin->pinUse = std::get<2>(t); lcell->pins[index] = LibraryPin(lpin); switch (std::get<1>(t)){ case IN : lcell->numInputPins++; break; case OUT: lcell->numOutputPins++; break; case BIDIRECTIONAL: lcell->numInOutPins++; break; } // end switch } // end for // Initializes library cell's pins. lcell->arcs.resize(numArcs); for (int i = 0; i < numArcs; i++) { LibraryArcData * larc = &(data->libraryArcs.create()->value); // TODO: awful larc->id = data->libraryArcs.lastId(); larc->design = *this; larc->lcell = libraryCell; larc->index = i; larc->from = libraryCell.getLibraryPinByName(std::get<0>(dscp.arcs[i])); larc->to = libraryCell.getLibraryPinByName(std::get<1>(dscp.arcs[i])); lcell->arcs[i] = larc; } // end for return libraryCell; } // end method // ----------------------------------------------------------------------------- inline Cell Design::createCell(const Module parent, const LibraryCell libraryCell, const std::string &name) { const LibraryCellData * lcell = libraryCell.data; const std::string &cellName = name == ""? generateUniqueInstanceName("__cell") : name; const int numPins = lcell->pins.size(); const int numArcs = lcell->arcs.size(); // Creates a new cell in the data structure. InstanceData * instance = &(data->instances.create()->value); // TODO: awful Cell cell(instance); // Initializes instance. instance->id = data->instances.lastId(); instance->design = *this; instance->parent = parent; instance->lcell = const_cast(lcell); instance->type = CELL; instance->pins.resize(numPins); instance->arcs.resize(numArcs); // Initializes instance's pins. for (int i = 0; i < numPins; i++) { PinData * pin = &(data->pins.create()->value); // TODO: awful LibraryPin lpin = lcell->pins[i]; pin->id = data->pins.lastId(); pin->instance = cell; pin->direction = lpin.data->direction; pin->type = Rsyn::CELL; pin->index = lpin.data->index; instance->pins[i] = pin; switch (pin->direction) { case Rsyn::IN: pin->order = 0; break; case Rsyn::OUT: pin->order = TOPOLOGICAL_SORTING_SMALL_GAP; break; case Rsyn::BIDIRECTIONAL: throw Exception("Rsyn does not support bidirectional pins yet.\n"); default: throw Exception("Unknown pin direction.\n"); } // end switch } // end for // Initializes cell's arcs. for (int i = 0; i < numArcs; i++) { ArcData * arc = &(data->arcs.create()->value); // TODO: awful LibraryArc larc = lcell->arcs[i]; arc->id = data->arcs.lastId(); arc->type = INSTANCE_ARC; arc->libraryArcData = larc.data; arc->from = cell.getPinByLibraryPin(larc.data->from); arc->to = cell.getPinByLibraryPin(larc.data->to); arc->from.data->arcs[FORWARD].push_back(Arc(arc)); arc->to.data->arcs[BACKWARD].push_back(Arc(arc)); instance->arcs[i] = arc; } // end for // Stores cell name. if (data->instanceNames.size() <= instance->id) { data->instanceNames.resize(instance->id+1); } // end if data->instanceNames[instance->id] = cellName; data->instanceMapping[cellName] = Instance(instance); // Records this cell in it's parent module. parent->moduleData->instances.add(cell); cell->mid = parent->moduleData->instances.lastId(); // Trace the number of instances. data->instanceCount[Rsyn::CELL]++; // Mark as dirty. data->dirty = true; // Notify observers. for (auto f : data->observers[EVENT_POST_INSTANCE_CREATE]) f->onPostInstanceCreate(cell); // Return return cell; } // end method // ----------------------------------------------------------------------------- inline Port Design::createPort(Module parent, const Direction direction, const std::string &name) { const std::string &portName = name == ""? generateUniqueInstanceName("__cell") : name; const int numPins = 1; const int numArcs = 0; // Creates a new cell in the data structure. Port port = &(data->instances.create()->value); // TODO: awful // Creates the outer pin which will be added to the parent module. PinData * outer = &(data->pins.create()->value); // TODO: awful outer->id = data->pins.lastId(); outer->instance = parent; outer->direction = direction; outer->type = Rsyn::MODULE; outer->boundary = true; outer->index = parent->pins.size(); parent->pins.push_back(outer); // Initializes port data. port->id = data->instances.lastId(); port->design = *this; port->parent = parent; port->type = PORT; port->outerPin = outer; port->lcell = nullptr; port->pins.resize(numPins); port->arcs.resize(numArcs); // Creates the inner pin which will be added to the port. PinData * inner = &(data->pins.create()->value); // TODO: awful inner->id = data->pins.lastId(); inner->instance = port; inner->direction = Global::getReverseDirection(direction); inner->type = Rsyn::PORT; inner->boundary = true; inner->index = 0; port->pins[0] = inner; // Topological index. switch (direction) { case Rsyn::IN: outer->order = 0; inner->order = TOPOLOGICAL_SORTING_SMALL_GAP; break; case Rsyn::OUT: inner->order = 1; outer->order = 2; break; default: throw Exception("Port direction not supported."); } // ens switch // Stores port (instance) name. if (data->instanceNames.size() <= port->id) { data->instanceNames.resize(port->id+1); } // end if data->instanceNames[port->id] = portName; data->instanceMapping[portName] = Instance(port); // Records this cell in it's parent module. parent->moduleData->instances.add(port); port->mid = parent->moduleData->instances.lastId(); parent->moduleData->ports.add(port); parent->moduleData->portsByDirection[direction].insert(port); // Trace the number of instances. data->instanceCount[Rsyn::PORT]++; // Mark as dirty. data->dirty = true; // Notify observers. for (auto f : data->observers[EVENT_POST_INSTANCE_CREATE]) f->onPostInstanceCreate(port); // Return return port; } // end method // ----------------------------------------------------------------------------- inline Module Design::createModule(const LibraryModule lmoudle, const std::string &name) { // Creates a new cell in the data structure. InstanceData * instance = &(data->instances.create()->value); // TODO: awful // Initializes cell. instance->id = data->instances.lastId(); instance->type = Rsyn::MODULE; instance->design = *this; instance->lcell = nullptr; instance->moduleData = new ModuleData; instance->moduleData->design = *this; // Stores instance name. if (data->instanceNames.size() <= instance->id) { data->instanceNames.resize(instance->id+1); } // end if data->instanceNames[instance->id] = name; data->instanceMapping[name] = Instance(instance); // Trace the number of instances. data->instanceCount[Rsyn::MODULE]++; // Mark as dirty. data->dirty = true; // Notify observers. for (auto f : data->observers[EVENT_POST_INSTANCE_CREATE]) f->onPostInstanceCreate(instance); // Return return Module(instance); } // end method // ----------------------------------------------------------------------------- inline Net Design::createNet(const Module parent, const std::string &name) { // Creates a new net in the data structure. NetData * net = &(data->nets.create()->value); // TODO: awful // Gets the net name. const std::string &netName = name == ""? generateUniqueNetName("__net") : name; // Initializes net. net->id = data->nets.lastId(); net->parent = parent; // Stores net name. if (data->netNames.size() <= net->id) { data->netNames.resize(net->id+1); } // end if data->netNames[net->id] = netName; data->netMapping[netName] = net; // Records this cell in it's parent module. parent->moduleData->nets.add(net); net->mid = parent->moduleData->nets.lastId(); // Notify observers. for (auto f : data->observers[EVENT_POST_NET_CREATE]) f->onPostNetCreate(net); // Mark as dirty. data->dirty = true; // Return. return net; } // end method // ----------------------------------------------------------------------------- inline void Design::connectPin(Pin pin, Net net) { if (pin->net) { disconnectPin(pin); } // end if net->pins.push_back(pin); pin->net = net; net->numPinsOfType[pin.getDirection()]++; if (pin.getDirection() == DRIVER) { net->driver = pin; // cache the driver } // end if // Create net arcs as necessary. switch (pin.getDirection()) { case Rsyn::DRIVER: { for (Rsyn::Pin sink : net.allPins(Rsyn::SINK)) { Arc arc = &(data->arcs.create()->value); // TODO: awful arc->id = data->arcs.lastId(); arc->type = NET_ARC; arc->netData = net.data; arc->from = pin; arc->to = sink; pin->arcs[FORWARD].push_back(arc); sink->arcs[BACKWARD].push_back(arc); } // end for break; } // end case case Rsyn::SINK: { for (Rsyn::Pin driver : net.allPins(Rsyn::DRIVER)) { Arc arc = &(data->arcs.create()->value); // TODO: awful arc->id = data->arcs.lastId(); arc->type = NET_ARC; arc->netData = net.data; arc->from = driver; arc->to = pin; driver->arcs[FORWARD].push_back(arc); pin->arcs[BACKWARD].push_back(arc); } // end for break; } // end case default: throw Exception("Unsupported direction."); } // end switch // Mark as dirty. data->dirty = true; // Update topological sorting. updateTopologicalIndex(pin); // Notify observers. for (auto f : data->observers[EVENT_POST_PIN_CONNECT]) f->onPostPinConnect(pin); } // end method // ----------------------------------------------------------------------------- inline void Design::disconnectPin(Pin pin) { // Notify observers. for (auto f : data->observers[EVENT_PRE_PIN_DISCONNECT]) f->onPrePinDisconnect(pin); if (pin->net) { // Remove the pin from the net. Net net = pin->net; const int numPins = net->pins.size(); for (int i = 0; i < numPins; i++) { if (net->pins[i] == pin) { // Swap the element to be delete with the last one and then shrink // the vector. Note that is affect the pin ordering inside the net. std::swap(net->pins[i], net->pins.back()); net->pins.resize(net->pins.size() - 1); break; } // end if } // end for // Remove arcs from the pin. switch (pin.getDirection()) { case Rsyn::DRIVER: pin->arcs[FORWARD].clear(); break; case Rsyn::SINK: pin->arcs[BACKWARD].clear(); break; default: throw Exception("Unsupported direction."); } // end switch // Disconnect the pin. pin->net = nullptr; // Adjust pins count. net->numPinsOfType[pin.getDirection()]--; // Update the cached driver if necessary. if (pin.getDirection() == Rsyn::DRIVER) { for (Pin pin : net.allPins(Rsyn::OUT)) { net->driver = pin; break; } // end for } // end if // Mark as dirty. data->dirty = true; } // end if } // end method // ----------------------------------------------------------------------------- // TODO: Improve performance of remaping. The first thing to do is to cache // the remaping table. inline void Design::remap(Cell cell, LibraryCell newLibraryCell) { LibraryCell oldLibraryCell = cell.getLibraryCell(); // Check if the cells have the same number of arcs... // TODO: a deep comparison is necessary. if (oldLibraryCell.getNumArcs() != newLibraryCell.getNumArcs()) { throw IncompatibleLibraryCellForRemapping( oldLibraryCell.getName(), newLibraryCell.getName()); } // end if // Check if the cells have the same number of pins... if (oldLibraryCell.getNumPins() != newLibraryCell.getNumPins()) { throw IncompatibleLibraryCellForRemapping( oldLibraryCell.getName(), newLibraryCell.getName()); } // end if // Create a mapping between the old and new pins. // TODO: Cache this! std::unordered_map mapLibraryPins; for (LibraryPin oldLibraryPin : oldLibraryCell.allLibraryPins()) { LibraryPin newLibraryPin = newLibraryCell.getLibraryPinByName(oldLibraryPin.getName()); if (!newLibraryPin) { throw IncompatibleLibraryCellForRemapping( oldLibraryCell.getName(), newLibraryCell.getName()); } // end if mapLibraryPins[oldLibraryPin] = newLibraryPin; } // end method // Create a mapping between the old and new arcs. // TODO: Cache this! std::unordered_map mapLibraryArcs; for (LibraryArc oldLibraryArc : oldLibraryCell.allLibraryArcs()) { LibraryArc newLibraryArc = newLibraryCell.getLibraryArcByPinNames(oldLibraryArc.getFromName(), oldLibraryArc.getToName()); if (!newLibraryArc) { throw IncompatibleLibraryCellForRemapping( oldLibraryCell.getName(), newLibraryCell.getName()); } // end if mapLibraryArcs[oldLibraryArc] = newLibraryArc; } // end method // Update library cell. cell->lcell = newLibraryCell.data; // Update pins. for (Pin pin : cell.allPins()) { Rsyn::LibraryPin newLibraryPin = mapLibraryPins[oldLibraryCell.getLibraryPinByIndex(pin->index)]; pin->index = newLibraryPin->index; } // end for // Update arcs. for (Arc arc : cell.allArcs()) { Rsyn::LibraryArc newLibraryArc = mapLibraryArcs[arc.getLibraryArc()]; arc->libraryArcData = newLibraryArc.data; } // end for // Notify observers. for (auto f : data->observers[EVENT_POST_CELL_REMAP]) f->onPostCellRemap(cell, oldLibraryCell); } // end method // ----------------------------------------------------------------------------- inline void Design::remap(Cell cell, const std::string &newLibraryCellName) { LibraryCell newLibraryCell = findLibraryCellByName(newLibraryCellName); if (!newLibraryCell) { throw LibraryCellNotFoundException(newLibraryCellName); } // end if remap(cell, newLibraryCell); } // end method // ----------------------------------------------------------------------------- inline int Design::getNumInstances() const { return data->instances.size(); } // end method // ----------------------------------------------------------------------------- inline Range> Design::getAllCells() const { for (Instance inst : data->topModule.allInstances()){ if (inst.getType() != CELL) continue; data->cells.add(inst.asCell()); } Range> a = ReferenceListCollection(data->cells); for (Cell c : a){ std::cout << c.getName() << "\n"; break; } return ReferenceListCollection(data->cells); } // end method // ----------------------------------------------------------------------------- inline int Design::getNumInstances(const InstanceType type) const { return data->instanceCount[type]; } // end method // ----------------------------------------------------------------------------- inline int Design::getNumNets() const { return data->nets.size(); } // end method // ----------------------------------------------------------------------------- inline int Design::getNumPins() const { return data->pins.size(); } // end method //////////////////////////////////////////////////////////////////////////////// // Topological Ordering //////////////////////////////////////////////////////////////////////////////// inline void Design::updateTopologicalIndex(Pin pin) { // Some checks... static_assert(std::is_integral::value, "Integer required."); static_assert(std::is_signed::value, "Signed type required."); static_assert(TOPOLOGICAL_SORTING_SMALL_GAP > 0, "small < 0"); static_assert(TOPOLOGICAL_SORTING_LARGE_GAP > 0, "large < 0"); static_assert(TOPOLOGICAL_SORTING_SMALL_GAP <= TOPOLOGICAL_SORTING_LARGE_GAP, "small gap > large gap"); // Gets the signature for this update search. const int sign = generateNextSign(); // Gets the lower bound index. TopologicalIndex lower = -std::numeric_limits::infinity(); bool hasLower = false; for (Rsyn::Pin predecessor : pin.allPredecessorPins(true)) { lower = std::max(lower, predecessor.getTopologicalIndex()); hasLower = true; } // end for // Gets the upper bound index. TopologicalIndex upper = +std::numeric_limits::infinity(); bool hasUpper = false; for (Rsyn::Pin successor : pin.allSucessorPins(true)) { upper = std::min(upper, successor.getTopologicalIndex()); hasUpper = true; } // end for // Set pin's topological ordering. if (!hasLower && !hasUpper) { pin->order = 0; } else if (hasLower && !hasUpper) { pin->order = lower + TOPOLOGICAL_SORTING_SMALL_GAP; } else if (!hasLower && hasUpper) { pin->order = upper - TOPOLOGICAL_SORTING_SMALL_GAP; } else { // Ok, we got a lower and an upper bound... if (lower < upper && (upper - lower >= 2)) { // The easy case... // Since we use integral types, we must guarantee that there's room // for the new pin between the lower and upper bounds, that's why // we check if (upper - lower >= 2). pin->order = (lower + upper) / 2; } else { // We need to propagate the indexes... const TopologicalIndex smallGap = TOPOLOGICAL_SORTING_SMALL_GAP; const TopologicalIndex largeGap = TOPOLOGICAL_SORTING_LARGE_GAP; const TopologicalIndex left0 = upper; const TopologicalIndex left1 = lower + smallGap + 1; const TopologicalIndex right = left1 + largeGap; const TopologicalIndex w0 = (right - left0); const TopologicalIndex w1 = (right - left1); pin->order = (lower + left1) / 2; std::queue> open; for (Rsyn::Pin successor : pin.allSucessorPins(true)) { if (successor->order < right) { open.push(std::make_tuple(successor, pin->order)); } // end if } // end for while (!open.empty()) { Rsyn::Pin current = std::get<0>(open.front()); const TopologicalIndex generatorOrder = std::get<1>(open.front()); open.pop(); if (current == pin) { // loop detected; std::cout << "WARNING: Loop detected.\n"; continue; } // end if if (current->order > generatorOrder) { // no need to continue propagating... continue; } // end if TopologicalIndex order; if (current->sign != sign) { current->sign = sign; order = (TopologicalIndex) std::floor( (float((current->order - upper)*w1)/float(w0)) + left1); if (order <= generatorOrder) { order = generatorOrder + smallGap; } // end if } else { order = generatorOrder + smallGap; } // end else current->order = order; for (Rsyn::Pin successor : current.allSucessorPins(true)) { if (successor->order <= order) { open.push(std::make_tuple(successor, order)); } // end if } // end for } // end while } // end else } // end else } // end method //////////////////////////////////////////////////////////////////////////////// // Unique Identifiers for Rsyn Objects //////////////////////////////////////////////////////////////////////////////// inline Index Design::getId(Net net) const { return net->id; } inline Index Design::getId(Instance instance) const { return instance->id; } inline Index Design::getId(Pin pin) const { return pin->id; } inline Index Design::getId(Arc arc) const { return arc->id; } inline Index Design::getId(LibraryCell lcell) const { return lcell->id; } inline Index Design::getId(LibraryPin lpin) const { return lpin->id; } inline Index Design::getId(LibraryArc larc) const { return larc->id; } //////////////////////////////////////////////////////////////////////////////// // Events //////////////////////////////////////////////////////////////////////////////// template inline void Design::registerObserver(T *observer) { static_assert(std::is_base_of::value, "Unable to register class as observer. " "The observer class must inherit from Rsyn::Observer."); observer->DesignObserver::observedDesign = Design(data); // Check if the observer implements (overwrites) the event callbacks if so // register it to receive notifications of the respective event. if (typeid(&DesignObserver::onDesignDestruction) != typeid(&T::onDesignDestruction)) { data->observers[EVENT_DESTRUCTION].push_back(observer); } // end if if (typeid(&DesignObserver::onPostInstanceCreate) != typeid(&T::onPostInstanceCreate)) { data->observers[EVENT_POST_INSTANCE_CREATE].push_back(observer); } // end if if (typeid(&DesignObserver::onPreInstanceRemove) != typeid(&T::onPreInstanceRemove)) { data->observers[EVENT_PRE_INSTANCE_REMOVE].push_back(observer); } // end if if (typeid(&DesignObserver::onPostNetCreate) != typeid(&T::onPostNetCreate)) { data->observers[EVENT_POST_NET_CREATE].push_back(observer); } // end if if (typeid(&DesignObserver::onPreNetRemove) != typeid(&T::onPreNetRemove)) { data->observers[EVENT_PRE_NET_REMOVE].push_back(observer); } // end if if (typeid(&DesignObserver::onPostCellRemap) != typeid(&T::onPostCellRemap)) { data->observers[EVENT_POST_CELL_REMAP].push_back(observer); } // end if if (typeid(&DesignObserver::onPostPinConnect) != typeid(&T::onPostPinConnect)) { data->observers[EVENT_POST_PIN_CONNECT].push_back(observer); } // end if if (typeid(&DesignObserver::onPrePinDisconnect) != typeid(&T::onPrePinDisconnect)) { data->observers[EVENT_PRE_PIN_DISCONNECT].push_back(observer); } // end if if (typeid (&DesignObserver::onPostInstanceMove) != typeid (&T::onPostInstanceMove)) { data->observers[EVENT_POST_INSTANCE_MOVE].push_back(observer); } // end if } // end method // ----------------------------------------------------------------------------- inline void Design::unregisterObserver(DesignObserver *observer) { for (int i = 0; i < NUM_DESIGN_EVENTS; i++) { data->observers[i].remove(observer); } // end for observer->DesignObserver::observedDesign = nullptr; } // end method // ----------------------------------------------------------------------------- inline void Design::notifyInstancePlaced(Rsyn::Instance instance, Rsyn::DesignObserver *ignoreObserver) { for (DesignObserver * observer : data->observers[EVENT_POST_INSTANCE_MOVE]) { if (observer != ignoreObserver) { observer->onPostInstanceMove(instance); } // end if } // end for } // end method //////////////////////////////////////////////////////////////////////////////// // Attributes //////////////////////////////////////////////////////////////////////////////// inline AttributeInitializer Design::createAttribute() { return AttributeInitializer(*this); } // end method // ----------------------------------------------------------------------------- template inline AttributeInitializerWithDefaultValue Design::createAttribute(const DefaultValueType &defaultValue) { return AttributeInitializerWithDefaultValue(*this, defaultValue); } // end method //////////////////////////////////////////////////////////////////////////////// // Tags //////////////////////////////////////////////////////////////////////////////// inline NetTag Design::getTag(Rsyn::Net net) { return NetTag(&net->tag); } // end method // ----------------------------------------------------------------------------- inline InstanceTag Design::getTag(Rsyn::Instance instance) { return InstanceTag(&instance->tag); } // end method // ----------------------------------------------------------------------------- inline LibraryCellTag Design::getTag(Rsyn::LibraryCell libraryCell) { return LibraryCellTag(&libraryCell->tag); } // end method //////////////////////////////////////////////////////////////////////////////// // Range-Based Loop //////////////////////////////////////////////////////////////////////////////// inline Range> Design::allLibraryCells(const bool showDeprecatedMessage) { if (showDeprecatedMessage) { std::cout << "WARNING: Rsyn::Desing::allLibraryCells() is deprecated. " "Use Rsyn::Library::allLibraryCells() instead.\n"; } // end method return ListCollection(data->libraryCells); } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/Instance.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include namespace Rsyn { inline DesignData * Instance::_getDesignData() const { return getDesign().data; } // end method // ----------------------------------------------------------------------------- inline DesignData * Instance::getDesignData() { return _getDesignData(); } // end method // ----------------------------------------------------------------------------- inline const DesignData * Instance::getDesignData() const { return _getDesignData(); } // end method // ----------------------------------------------------------------------------- inline Design Instance::_getDesign() const { return data->design; } // end method // ----------------------------------------------------------------------------- inline Design Instance::getDesign() { return _getDesign(); } // end method // ----------------------------------------------------------------------------- inline const Design Instance::getDesign() const { return _getDesign(); } // end method // ----------------------------------------------------------------------------- inline Module Instance::_getParent() const { return data->parent; } // end method // ----------------------------------------------------------------------------- inline Module Instance::getParent() { return _getParent(); } // end method // ----------------------------------------------------------------------------- inline const Module Instance::getParent() const { return _getParent(); } // end method // ----------------------------------------------------------------------------- inline Cell Instance::asCell() const { #ifdef RSYN_SAFE_MODE if (getType() != Rsyn::CELL) throw SafeModeException("Invalid instance casting. Instance is not a cell."); #endif return Cell(data); } // end method // ----------------------------------------------------------------------------- inline Port Instance::asPort() const { #ifdef RSYN_SAFE_MODE if (getType() != Rsyn::PORT) throw SafeModeException("Invalid instance casting. Instance is not a port."); #endif return Port(data); } // end method // ----------------------------------------------------------------------------- inline Module Instance::asModule() const { #ifdef RSYN_SAFE_MODE if (getType() != Rsyn::MODULE) throw SafeModeException("Invalid instance casting. Instance is not a module."); #endif return Module(data); } // end method // ----------------------------------------------------------------------------- inline std::string Instance::getHierarchicalName() const { return (data->parent ? data->parent.getHierarchicalName() : "") + "/" + getName(); } // end method // ----------------------------------------------------------------------------- inline InstanceType Instance::getType() const { return data->type; } // end method // ----------------------------------------------------------------------------- inline Pin Instance::getPinByName(const std::string &name) const { for (Rsyn::Pin pin : allPins()) { if (pin.getName() == name) return pin; } // end method return nullptr; } // end method // ----------------------------------------------------------------------------- inline const std::string & Instance::getName() const { return data ? getDesign()->instanceNames[data->id] : NullName; } // end method // ----------------------------------------------------------------------------- inline int Instance::getNumPins() const { return (int) data->pins.size(); } // end method // ----------------------------------------------------------------------------- inline int Instance::getNumPins(const Direction direction) const { // TODO: optimize this using instance types (e.g. cell can get the number // of pins of certain direction via its library cell). int counter = 0; for (Rsyn::Pin pin : allPins()) { if (pin.getDirection() == direction) { counter++; } // end if } // end for return counter; } // end method // ----------------------------------------------------------------------------- inline int Instance::getNumInputPins() const { return getNumPins(Rsyn::IN); } // end method // ----------------------------------------------------------------------------- inline int Instance::getNumOutputPins() const { return getNumPins(Rsyn::OUT); } // end method // ----------------------------------------------------------------------------- inline int Instance::getNumBidirectionalPins() const { return getNumPins(Rsyn::BIDIRECTIONAL); } // end method // ----------------------------------------------------------------------------- inline int Instance::getNumArcs() const { return (int) data->arcs.size(); } // end method // ----------------------------------------------------------------------------- inline TopologicalIndex Instance::getTopologicalIndex() const { // TODO: The topological order of an instance my be ambiguous in some cases // as in the case of registers. There's no arc between D and Q pins and // hence D may have a larger topological index than Q. In a forward traverse // of the netlist one may expect that Q would be used as the topological // index of the register while in a backward traverse one would expect // that the D pin was used. // NOTE: In the current implementation the topological order of register // is the topological order of the clock pin. TopologicalIndex order = MIN_TOPOLOGICAL_INDEX; for (Rsyn::Arc arc : allArcs()) { order = std::max(order, arc.getFromPin().getTopologicalIndex()); } // end for // Some cells may not have arcs, so as a fall back, get the largest // topological index of its pins. if (order == MIN_TOPOLOGICAL_INDEX) { for (Rsyn::Pin pin : allPins()) { order = std::max(order, pin.getTopologicalIndex()); } // end for } // end if return order; } // end method // ----------------------------------------------------------------------------- inline bool Instance::isPort() const { return data->type == Rsyn::PORT; } // end method // ----------------------------------------------------------------------------- inline bool Instance::isPort(const Direction direction) { return isPort() && (asPort().getDirection() == direction); } // end method // ----------------------------------------------------------------------------- inline Pin Instance::getPinByIndex(const int index) const { return data->pins[index]; } // end method // ----------------------------------------------------------------------------- inline Pin Instance::getAnyInputPin() const { for (Pin pin : allPins()) { if (pin.getDirection() == Rsyn::IN) { return pin; } // end if } // end for return nullptr; } // end method // ----------------------------------------------------------------------------- inline Pin Instance::getAnyOutputPin() const { for (Pin pin : allPins()) { if (pin.getDirection() == Rsyn::OUT) { return pin; } // end if } // end for return nullptr; } // end method // ----------------------------------------------------------------------------- inline Arc Instance::getArc(const Pin from, const Pin to) { for (Arc arc : allArcs()) { if ((arc.getFromPin() == from) && (arc.getToPin() == to)) { return arc; } // end if } // end for return nullptr; } // end method // ----------------------------------------------------------------------------- inline Arc Instance::getArcByPinNames(const std::string &from, const std::string &to) { for (Arc arc : allArcs()) { if ((arc.getFromPin().getName() == from) && (arc.getToPin().getName() == to)) { return arc; } // end if } // end for return nullptr; } // end method // ----------------------------------------------------------------------------- inline Arc Instance::getAnyArc() { return !data->arcs.empty() ? data->arcs[0] : nullptr; } // end method // ----------------------------------------------------------------------------- inline LibraryCell Instance::getLibraryCell() const { return getType() == Rsyn::CELL? Cell(data).getLibraryCell() : nullptr; } // end method // ----------------------------------------------------------------------------- inline Range Instance::allPins(const Direction direction, bool filterPG) const { return CollectionOfPinsFilteredByDirection(data->pins, direction, filterPG); } // end method // ----------------------------------------------------------------------------- inline Range Instance::allPins(bool filterPG) const { return CollectionOfPins(data->pins, filterPG); } // end method // ----------------------------------------------------------------------------- inline Range Instance::allArcs() const { return CollectionOfArcs(data->arcs); } // end method // ----------------------------------------------------------------------------- inline bool Instance::isSequential() const { return getType() == Rsyn::CELL ? asCell().getLibraryCell().isSequential() : false; } // end method // ----------------------------------------------------------------------------- inline bool Instance::isTie(const TieType type) const { return getType() == Rsyn::CELL ? asCell().getLibraryCell().isTie(type) : false; } // end method // ----------------------------------------------------------------------------- inline bool Instance::isBuffer(const BufferType type) const { return getType() == Rsyn::CELL ? asCell().getLibraryCell().isBuffer(type) : false; } // end method // ----------------------------------------------------------------------------- inline bool Instance::isClockBuffer(const BufferType type, const bool local) const { // First check if this instance is a buffer. if (!isBuffer(type)) return false; // Now checks if this buffer belong to a clock network. Rsyn::Pin pin = getAnyOutputPin(); Rsyn::Net net = pin.getNet(); if (!net || !net.isClockNetwork()) return false; // Only consider a local clock buffer a clock buffer driving at least one // register. if (local) { for (Rsyn::Pin sink : net.allPins(Rsyn::SINK)) { Rsyn::Instance instance = sink.getInstance(); if (instance.isSequential()) return true; } // end for return false; } else { return true; } // end else } // end method // ----------------------------------------------------------------------------- inline bool Instance::isLCB(const BufferType type) const { return isClockBuffer(type, true); } // end method // ----------------------------------------------------------------------------- inline bool Instance::isFixed() const { if (data->tag.fixed.isNotSpecified()) throw TagNotSpecifiedException("Fixed"); return data->tag.fixed; } // end method // ----------------------------------------------------------------------------- inline bool Instance::isMovable() const { return !isFixed(); } // end method // ----------------------------------------------------------------------------- inline bool Instance::isMacroBlock() const { if (data->tag.block.isNotSpecified()) throw TagNotSpecifiedException("Block"); return data->tag.block; } // end method // ----------------------------------------------------------------------------- inline bool Instance::isFlipped() const { PhysicalOrientation orient = getOrientation(); const bool fliped = orient == ORIENTATION_FN || orient == ORIENTATION_FS || orient == ORIENTATION_FW || orient == ORIENTATION_FE; return fliped; } // end method // ----------------------------------------------------------------------------- inline DBU Instance::getX() const { return getPosition(X); } // end method // ----------------------------------------------------------------------------- inline DBU Instance::getY() const { return getPosition(Y); } // end method // ----------------------------------------------------------------------------- inline DBU Instance::getHeight() const { return data->clsBounds.computeLength(Y); } // end method // ----------------------------------------------------------------------------- inline DBU Instance::getWidth() const { return data->clsBounds.computeLength(X); } // end method // ----------------------------------------------------------------------------- inline DBUxy Instance::getSize() const { return DBUxy(getWidth(), getHeight()); } // end method // ----------------------------------------------------------------------------- inline DBU Instance::getSize(const Dimension dimension) const { return data->clsBounds.computeLength(dimension); } // end method // ----------------------------------------------------------------------------- inline DBUxy Instance::getPosition() const { if (isPort()) return data->clsPortPos; return data->clsBounds[LOWER]; } // end method // ----------------------------------------------------------------------------- inline DBU Instance::getPosition(const Dimension dim) const { if (isPort()) return data->clsPortPos[dim]; return data->clsBounds[LOWER][dim]; } // end method // ----------------------------------------------------------------------------- inline DBUxy Instance::getCoordinate(const Boundary bound) const { if (isPort()) return getPosition(); return data->clsBounds[bound]; } // end method // ----------------------------------------------------------------------------- inline DBU Instance::getCoordinate(const Boundary bound, const Dimension dim) const { if (isPort()) getPosition(dim); return data->clsBounds[bound][dim]; } // end method // ----------------------------------------------------------------------------- inline DBU Instance::getArea() const { return data->clsBounds.computeArea(); } // end method // ----------------------------------------------------------------------------- inline DBUxy Instance::getCenter() const { if (isPort()) return getPosition(); return getBounds().computeCenter(); } // end method // ----------------------------------------------------------------------------- inline DBU Instance::getCenter(const Dimension dim) const { if (isPort()) return getPosition(dim); return getBounds().computeCenter(dim); } // end method // ----------------------------------------------------------------------------- inline const Bounds &Instance::getBounds() const { return data->clsBounds; } // end method // ----------------------------------------------------------------------------- inline PhysicalOrientation Instance::getOrientation() const { return data->clsOrientation; } // end method // ----------------------------------------------------------------------------- inline PhysicalTransform Instance::getTransform(const bool origin) const { if (origin) { Bounds bounds = getBounds(); bounds.translate(-bounds.getLower()); return PhysicalTransform(bounds, getOrientation()); } else { return PhysicalTransform(getBounds(), getOrientation()); } // end else } // end method // ============================================================================= // Tag // ============================================================================= inline TristateFlag InstanceTag::getFixed() const { return data->fixed; } // end method // ----------------------------------------------------------------------------- inline void InstanceTag::setFixed(const bool value) { data->fixed = value; } // end method // ----------------------------------------------------------------------------- inline TristateFlag InstanceTag::getMacroBlock() const { return data->block; } // end method // ----------------------------------------------------------------------------- inline void InstanceTag::setMacroBlock(const bool value) { data->block = value; } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/Library.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline Range> Library::allLibraryCells() { return Rsyn::Design(data->designData).allLibraryCells(false); } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/LibraryArc.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline Design LibraryArc::getDesign() { return data->design; } // end method // ----------------------------------------------------------------------------- inline const Design LibraryArc::getDesign() const { return data->design; } // end method // ----------------------------------------------------------------------------- inline std::string LibraryArc::getName() const { return getFromName() + "->" + getToName(); } // end method // ----------------------------------------------------------------------------- inline std::string LibraryArc::getFullName() const { return getLibraryCell().getName() + ":" + getName(); } // end method // ----------------------------------------------------------------------------- inline std::string LibraryArc::getFromName() const { return getFromLibraryPin().getName(); } // end method // ----------------------------------------------------------------------------- inline std::string LibraryArc::getToName() const { return getToLibraryPin().getName(); } // end method // ----------------------------------------------------------------------------- inline LibraryCell LibraryArc::getLibraryCell() const { return data->lcell; } // end method // ----------------------------------------------------------------------------- inline LibraryPin LibraryArc::getFromLibraryPin() const { return data->from; } // end method // ----------------------------------------------------------------------------- inline LibraryPin LibraryArc::getToLibraryPin() const { return data->to; } // end method // ----------------------------------------------------------------------------- inline int LibraryArc::getIndex() const { return data->index; } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/LibraryCell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline Design LibraryCell::getDesign() { return data->design; } // end method // ----------------------------------------------------------------------------- inline const Design LibraryCell::getDesign() const { return data->design; } // end method // ----------------------------------------------------------------------------- inline LibraryPin LibraryCell::getLibraryPinByName(const std::string &name) const { for (LibraryPin lpin : data->pins) { if (lpin.getName() == name) { return lpin; } // end if } // end for return nullptr; } // end method // ----------------------------------------------------------------------------- inline const std::string & LibraryCell::getName() const { return data? data->name : NullName; } // end method // ----------------------------------------------------------------------------- inline int LibraryCell::getNumPins() const { return (int) data->pins.size(); } // end method // ----------------------------------------------------------------------------- inline int LibraryCell::getNumPins(const Direction direction) const { // TODO: use array switch(direction) { case IN : return data->numInputPins; case OUT: return data->numOutputPins; case BIDIRECTIONAL: return data->numInOutPins; default: throw std::string("invalid pin direction"); // TODO: use a proper exception class } // end switch } // end method // ----------------------------------------------------------------------------- inline int LibraryCell::getNumInputPins() const { return getNumPins(Rsyn::IN); } // end method // ----------------------------------------------------------------------------- inline int LibraryCell::getNumOutputPins() const { return getNumPins(Rsyn::OUT); } // end method // ----------------------------------------------------------------------------- inline int LibraryCell::getNumBidirectionalPins() const { return getNumPins(Rsyn::BIDIRECTIONAL); } // end method // ----------------------------------------------------------------------------- inline int LibraryCell::getNumArcs() const { return (int) data->arcs.size(); } // end method // ----------------------------------------------------------------------------- inline LibraryPin LibraryCell::getLibraryPinByIndex(const int index) const { return data->pins[index]; } // end method // ----------------------------------------------------------------------------- inline LibraryPin LibraryCell::getAnyInputLibraryPin() { for (LibraryPin lpin : allLibraryPins()) { if (lpin.getDirection() == Rsyn::IN) { return lpin; } // end if } // end for return nullptr; } // end method // ----------------------------------------------------------------------------- inline LibraryPin LibraryCell::getAnyOutputLibraryPin() { for (LibraryPin lpin : allLibraryPins()) { if (lpin.getDirection() == Rsyn::OUT) { return lpin; } // end if } // end for return nullptr; } // end method // ----------------------------------------------------------------------------- inline LibraryArc LibraryCell::getLibraryArc(const Rsyn::LibraryPin from, const Rsyn::LibraryPin to) const { for (LibraryArc larc : allLibraryArcs()) { if (larc.getFromLibraryPin() == from && larc.getToLibraryPin() == to) return larc; } // end method return nullptr; } // end method // ----------------------------------------------------------------------------- inline LibraryArc LibraryCell::getLibraryArcByIndex(const int index) const { return data->arcs[index]; } // end method // ----------------------------------------------------------------------------- inline LibraryArc LibraryCell::getLibraryArcByPinNames(const std::string &from, const std::string &to) const { for (LibraryArc larc : allLibraryArcs()) { if (larc.getFromName() == from && larc.getToName() == to) return larc; } // end method return nullptr; } // end method // ----------------------------------------------------------------------------- inline LibraryArc LibraryCell::getAnyLibraryArc() const { return getNumArcs() > 0? data->arcs.front() : nullptr; } // end method // ----------------------------------------------------------------------------- inline Range LibraryCell::allLibraryPins(const Direction direction) const { return CollectionOfLibraryPinsFilteredByDirection(data->pins, direction); } // end method // ----------------------------------------------------------------------------- inline Range LibraryCell::allLibraryPins() const { return CollectionOfLibraryPins(data->pins); } // end method // ----------------------------------------------------------------------------- inline Range LibraryCell::allLibraryArcs() const { return CollectionOfLibraryArcs(data->arcs); } // end method // ----------------------------------------------------------------------------- inline bool LibraryCell::isSequential() const { if (data->tag.logicType == LOGIC_TYPE_TAG_NOT_SPECIFIED) throw TagNotSpecifiedException("Logic Type"); return data->tag.logicType == LOGIC_TYPE_TAG_SEQUENTIAL; } // end method // ----------------------------------------------------------------------------- inline bool LibraryCell::isCombinational() const { if (data->tag.logicType == LOGIC_TYPE_TAG_NOT_SPECIFIED) throw TagNotSpecifiedException("Logic Type"); return data->tag.logicType == LOGIC_TYPE_TAG_COMBINATIONAL; } // end method // ----------------------------------------------------------------------------- inline bool LibraryCell::isTie(const TieType type) const { if (data->tag.tieType == TIE_TYPE_TAG_NOT_SPECIFIED) throw TagNotSpecifiedException("Tie Type"); const TieTypeTag &tag = data->tag.tieType; switch (type) { case TIE_LOW : return tag == TIE_TYPE_TAG_LOW; case TIE_HIGH : return tag == TIE_TYPE_TAG_HIGH; case ANY_TIE_TYPE: return tag == TIE_TYPE_TAG_LOW || tag == TIE_TYPE_TAG_HIGH; default: assert(false); return false; } // end switch } // end method // ----------------------------------------------------------------------------- inline bool LibraryCell::isBuffer(const BufferType type) const { if (data->tag.bufferType == BUFFER_TYPE_TAG_NOT_SPECIFIED) throw TagNotSpecifiedException("Buffer Type"); const BufferTypeTag &tag = data->tag.bufferType; switch (type) { case NON_INVERTING : return tag == BUFFER_TYPE_TAG_NON_INVERTING; case INVERTING : return tag == BUFFER_TYPE_TAG_INVERTING; case ANY_BUFFER_TYPE: return tag == BUFFER_TYPE_TAG_NON_INVERTING || tag == BUFFER_TYPE_TAG_INVERTING; default: assert(false); return false; } // end switch } // end method // ----------------------------------------------------------------------------- inline DBU LibraryCell::getHeight() const { return data->size[Y]; } // end method // ----------------------------------------------------------------------------- inline DBU LibraryCell::getWidth() const { return data->size[X]; } // end method // ----------------------------------------------------------------------------- inline DBUxy LibraryCell::getSize() const { return data->size; } // end method // ----------------------------------------------------------------------------- inline DBU LibraryCell::getSize(const Dimension dimension) const { return data->size[dimension]; } // end method // ----------------------------------------------------------------------------- inline DBU LibraryCell::getArea() const { return getWidth() * getHeight(); } // end method // ============================================================================= // Tag // ============================================================================= inline LogicTypeTag LibraryCellTag::getLogicType() const { return data->logicType; } // end method // ----------------------------------------------------------------------------- inline TieTypeTag LibraryCellTag::getTieType() const { return data->tieType; } // end method // ----------------------------------------------------------------------------- inline BufferTypeTag LibraryCellTag::getBufferTypeTag() const { return data->bufferType; } // end method // ----------------------------------------------------------------------------- inline void LibraryCellTag::setLogicType(const LogicTypeTag value) { data->logicType = value; } // end method // ----------------------------------------------------------------------------- inline void LibraryCellTag::setTieType(const TieTypeTag value) { data->tieType = value; } // end method // ----------------------------------------------------------------------------- inline void LibraryCellTag::setBufferType(const BufferTypeTag value) { data->bufferType = value; } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/LibraryModule.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline Design LibraryModule::getDesign() { return data->design; } // end method // ----------------------------------------------------------------------------- inline const Design LibraryModule::getDesign() const { return data->design; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/LibraryPin.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline Design LibraryPin::getDesign() { return data->design; } // end method // ----------------------------------------------------------------------------- inline const Design LibraryPin::getDesign() const { return data->design; } // end method // ----------------------------------------------------------------------------- inline const std::string & LibraryPin::getName() const { return data? data->name : NullName; } // end method // ----------------------------------------------------------------------------- inline std::string LibraryPin::getHierarchicalName(const std::string & separator) const { return data ? data->lcell.getName() + separator + data->name : NullName; } // end method // ----------------------------------------------------------------------------- inline const std::string & LibraryPin::getDirectionName() const { return Global::getDirectionName(getDirection()); } // end method // ----------------------------------------------------------------------------- inline const std::string & LibraryPin::getLibraryCellName() const { return getLibraryCell().getName(); } // end method // ----------------------------------------------------------------------------- inline Direction LibraryPin::getDirection() const { return data->direction; } // end method // ----------------------------------------------------------------------------- inline LibraryCell LibraryPin::getLibraryCell() const { return data->lcell; } // end method // ----------------------------------------------------------------------------- inline int LibraryPin::getIndex() const { return data->index; } // end method // ----------------------------------------------------------------------------- inline bool LibraryPin::isInput() const { return getDirection() == Rsyn::IN; } // end method // ----------------------------------------------------------------------------- inline bool LibraryPin::isOutput() const { return getDirection() == Rsyn::OUT; } // end method // ----------------------------------------------------------------------------- inline bool LibraryPin::isBidirectional() const { return getDirection() == Rsyn::BIDIRECTIONAL; } // end method // ----------------------------------------------------------------------------- inline Use LibraryPin::getUse() const { return data->pinUse; } // end method // ----------------------------------------------------------------------------- inline bool LibraryPin::isPowerOrGround() const { return (getUse() == POWER || getUse() == GROUND); } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/Module.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline Design Module::getDesign() { return data->moduleData->design; } // end method // ----------------------------------------------------------------------------- inline const Design Module::getDesign() const { return data->moduleData->design; } // end method // ----------------------------------------------------------------------------- inline int Module::generateNextSign() const { return ++data->moduleData->sign; /*must be pre-increment*/ } // end method // ----------------------------------------------------------------------------- inline int Module::getSign() const { return data->moduleData->sign; } // end method // ----------------------------------------------------------------------------- inline Cell Module::createCell(const std::string &libraryCellName, const std::string &name) { Design design = getDesign(); // TODO: move this test to design... LibraryCell lcell = design.findLibraryCellByName(libraryCellName); if (!lcell) { throw LibraryCellNotFoundException(libraryCellName); } // end if return design.createCell(*this, lcell, name); } // end method // ----------------------------------------------------------------------------- inline Cell Module::createCell(const LibraryCell lcell, const std::string &name) { Design design = getDesign(); return design.createCell(*this, lcell, name); } // end method // ----------------------------------------------------------------------------- inline Port Module::createPort(const Direction &direction, const std::string &name) { Design design = getDesign(); return design.createPort(*this, direction, name); } // end method // ----------------------------------------------------------------------------- inline Net Module::createNet(const std::string &name) { Design design = getDesign(); // Check net name. if (design.findNetByName(name)) { throw NetAlreadyExistsException(name); } // end of // Creates and returns a new net; return design.createNet(*this, name); } // end method // ----------------------------------------------------------------------------- inline Port Module::getPortByIndex(const int index) { return data->moduleData->ports.get(index)->value; // TODO: awful } // end method // ----------------------------------------------------------------------------- inline void Module::getInstancesPerLogicalDepth(std::vector> &levels) { // TODO: For now let's just do a simple method to levelize. When more // unit tests are create, we should revise this method to see if a more // efficient one can be devised. levels.clear(); Rsyn::Attribute depth = getDesign().createAttribute(-1); for (Rsyn::Instance instance : allInstancesInTopologicalOrder()) { // Set the depth as the largest depth of the driver cells (if any) plus // one. int lower = -1; switch (instance.getType()) { case Rsyn::CELL: { // We check the from pin of arcs instead of just checking the // input pins to handle the D pin of registers. We want that // the depth of a register is based on the depth of its CK pin. bool hasArcs = false; for (Rsyn::Arc arc : instance.allArcs()) { Rsyn::Net net = arc.getFromNet(); if (net) { for (Rsyn::Pin driver : net.allPins(Rsyn::DRIVER)) { lower = std::max(lower, depth[driver.getInstance()]); } // end for } // end if hasArcs = true; } // end for // If no arcs, as a fall back, get the depth from the input // pins. if (!hasArcs) { for (Rsyn::Pin pin : instance.allPins()) { Rsyn::Net net = pin.getNet(); if (net) { for (Rsyn::Pin driver : net.allPins(Rsyn::DRIVER)) { lower = std::max(lower, depth[driver.getInstance()]); } // end for } // end if } // end for } // end if break; } // end case case Rsyn::MODULE: { for (Rsyn::Pin pin : instance.allPins()) { Rsyn::Net net = pin.getNet(); if (net) { for (Rsyn::Pin driver : net.allPins(Rsyn::DRIVER)) { lower = std::max(lower, depth[driver.getInstance()]); } // end for } // end if } // end for break; } // end case case Rsyn::PORT: { Rsyn::Port port = instance.asPort(); switch (port.getDirection()) { case Rsyn::IN: { // Nothing to be done here... (depth = 0) break; } // end case case Rsyn::OUT: { Rsyn::Net net = port.getInnerPin().getNet(); if (net) { for (Rsyn::Pin driver : net.allPins(Rsyn::DRIVER)) { lower = std::max(lower, depth[driver.getInstance()]); } // end for } // end if break; } // end case default: throw Exception("Port direction not supported."); } // end switch break; } // end case default: throw Exception("unsupported type"); } // end switch // Increment lower to get the instance depth. lower += 1; // Stores the instance depth. depth[instance] = lower; // Add instance to the level vector. if (levels.size() <= lower) { levels.resize(lower + 1); } // end if levels[lower].push_back(instance); } // end for } // end method // ----------------------------------------------------------------------------- inline void Module::getNetsPerLogicalDepth(std::vector> &levels) { levels.clear(); std::cout << "TODO: getNetsPerLogicalDepth() not implemented\n"; } // end method // ----------------------------------------------------------------------------- inline int Module::getNumPorts(const Direction direction) const { return data->moduleData->portsByDirection[direction].size(); } // end method // ----------------------------------------------------------------------------- inline Range> Module::allInstances() const { return ReferenceListCollection(data->moduleData->instances); } // end method // ----------------------------------------------------------------------------- inline Range> Module::allPorts() const { return ReferenceListCollection(data->moduleData->ports); } // end method // ----------------------------------------------------------------------------- inline std::set & Module::allPorts(const Rsyn::Direction direction) const { return data->moduleData->portsByDirection[direction]; } // end method // ----------------------------------------------------------------------------- inline Range> Module::allNets() const { return ReferenceListCollection(data->moduleData->nets); } // end method // ----------------------------------------------------------------------------- inline Range Module::allInterfacePins(const Direction direction) const { return Instance::allPins(direction); } // end method // ----------------------------------------------------------------------------- inline Range Module::allInterfacePins() const { return Instance::allPins(); } // end method // ----------------------------------------------------------------------------- inline Range Module::allInterfaceArcs() const { return Instance::allArcs(); } // end method // ----------------------------------------------------------------------------- inline std::vector> Module::allPinsInTopologicalOrder() const { const int numNets = data->moduleData->nets.size(); std::vector> sortedPins; sortedPins.reserve(numNets*3); for (Rsyn::Instance instance : allInstances()) { for (Rsyn::Pin pin : instance.allPins()) sortedPins.push_back(std::make_tuple(pin.getTopologicalIndex(), pin)); } // end for std::sort(sortedPins.begin(), sortedPins.end()); return sortedPins; } // end method // ----------------------------------------------------------------------------- inline std::vector> Module::allPinsInReverseTopologicalOrder() const { const int numNets = data->moduleData->nets.size(); std::vector> sortedPins; sortedPins.reserve(numNets*3); for (Rsyn::Instance instance : allInstances()) { for (Rsyn::Pin pin : instance.allPins()) sortedPins.push_back(std::make_tuple(-pin.getTopologicalIndex(), pin)); } // end for std::sort(sortedPins.begin(), sortedPins.end()); return sortedPins; } // end method // ----------------------------------------------------------------------------- inline std::vector> Module::allNetsInTopologicalOrder() const { const int numNets = data->moduleData->nets.size(); std::vector> sortedNets; sortedNets.resize(numNets); int i = 0; for (Rsyn::Net net : allNets()) { sortedNets[i++] = std::make_tuple(net.getTopologicalIndex(), net); } // end for sortedNets.resize(i); std::sort(sortedNets.begin(), sortedNets.end()); return sortedNets; } // end method // ----------------------------------------------------------------------------- inline std::vector> Module::allNetsInReverseTopologicalOrder() const { const int numNets = data->moduleData->nets.size(); std::vector> sortedNets; sortedNets.resize(numNets); int i = 0; for (Rsyn::Net net : allNets()) { sortedNets[i++] = std::make_tuple(-net.getTopologicalIndex(), net); } // end for sortedNets.resize(i); std::sort(sortedNets.begin(), sortedNets.end()); return sortedNets; } // end method // ----------------------------------------------------------------------------- inline std::vector> Module::allInstancesInTopologicalOrder() const { const int numInstances = data->moduleData->instances.size(); std::vector> sortedInstances; sortedInstances.resize(numInstances); int i = 0; for (Rsyn::Instance instance : allInstances()) { sortedInstances[i++] = std::make_tuple(instance.getTopologicalIndex(), instance); } // end for sortedInstances.resize(i); std::sort(sortedInstances.begin(), sortedInstances.end()); return sortedInstances; } // end method //////////////////////////////////////////////////////////////////////////////// // Sorted Objects //////////////////////////////////////////////////////////////////////////////// inline std::vector Module::getFanoutConeNetsInBreadthFirstOrder(Rsyn::Pin seed) const { std::vector result; std::queue open; // Push seed net. Rsyn::Net net = seed.getNet(); if (net) open.push(net); // Breadth-first search. const int sign = generateNextSign(); while (!open.empty()) { Rsyn::Net currentNet = open.front(); open.pop(); if (currentNet->sign == sign) continue; currentNet->sign = sign; result.push_back(currentNet); // Add neighbors. for (Rsyn::Pin sink : currentNet.allPins(SINK)) { for (Rsyn::Arc arc : sink.allOutgoingArcs()) { Rsyn::Net net = arc.getToNet(); if (net && net->sign != sign) open.push(net); } // end for } // end for } // end while // Return. return result; } // end method // ----------------------------------------------------------------------------- inline std::vector Module::getFaninConeNetsInBreadthFirstOrder(Rsyn::Pin seed) const { std::vector result; std::queue open; // Push seed net. Rsyn::Net net = seed.getNet(); if (net) open.push(net); // Breadth-first search. const int sign = generateNextSign(); while (!open.empty()) { Rsyn::Net currentNet = open.front(); open.pop(); if (currentNet->sign == sign) continue; currentNet->sign = sign; result.push_back(currentNet); // Add neighbors. for (Rsyn::Pin driver : currentNet.allPins(DRIVER)) { for (Rsyn::Arc arc : driver.allIncomingArcs()) { Rsyn::Net net = arc.getFromNet(); if (net && net->sign != sign) open.push(net); } // end for } // end for } // end while // Return. return result; } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/Net.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline Design Net::_getDesign() const { // TODO: too slow... return _getParent().getDesign(); } // end method // ----------------------------------------------------------------------------- inline Design Net::getDesign() { return _getDesign(); } // end method // ----------------------------------------------------------------------------- inline const Design Net::getDesign() const { return _getDesign(); } // end method // ----------------------------------------------------------------------------- inline Module Net::_getParent() const { return data->parent; } // end method // ----------------------------------------------------------------------------- inline Module Net::getParent() { return _getParent(); } // end method // ----------------------------------------------------------------------------- inline const Module Net::getParent() const { return _getParent(); } // end method // ----------------------------------------------------------------------------- inline const std::string & Net::getName() const { return data? getDesign()->netNames[data->id] : NullName; } // end method // ----------------------------------------------------------------------------- inline int Net::getNumPins() const { return (int) data->pins.size(); } // end method // ----------------------------------------------------------------------------- inline int Net::getNumSinks() const { return data->numPinsOfType[SINK]; } // end method // ----------------------------------------------------------------------------- inline int Net::getNumDrivers() const { return data->numPinsOfType[DRIVER]; } // end method // ----------------------------------------------------------------------------- inline Pin Net::getAnyDriver() const { return data->driver; } // end method // ----------------------------------------------------------------------------- inline Arc Net::getArc(const Pin from, const Pin to) { for (Arc arc : allArcs()) { if ((arc.getFromPin() == from) && (arc.getToPin() == to)) { return arc; } // end if } // end for return nullptr; } // end method // ----------------------------------------------------------------------------- inline TopologicalIndex Net::getTopologicalIndex() const { TopologicalIndex order; if (hasMultipleDrivers()) { // Just to save runtime as this is not very common. for (Rsyn::Pin driver : allPins(Rsyn::DRIVER)) { order = driver.getTopologicalIndex(); } // end for } else if (hasDriver()) { order = getAnyDriver().getTopologicalIndex(); } else { // No driver... if (hasSink()) { order = +std::numeric_limits::infinity(); for (Rsyn::Pin sink : allPins(Rsyn::SINK)) { order = std::min(order, sink.getTopologicalIndex()); } // end for } else { // A floating .. order = MIN_TOPOLOGICAL_INDEX; } // end else } // end else return order; } // end method // ----------------------------------------------------------------------------- inline bool Net::hasMultipleDrivers() const { return getNumDrivers() > 1; } // end method // ----------------------------------------------------------------------------- inline bool Net::hasSingleDriver() const { return getNumDrivers() == 1; } // end method // ----------------------------------------------------------------------------- inline bool Net::hasDriver() const { return getNumDrivers() >= 1; } // end method // ----------------------------------------------------------------------------- inline bool Net::hasSink() const { return getNumSinks() >= 1; } // end method // ----------------------------------------------------------------------------- inline Range Net::allPins(bool filterPG) const { return CollectionOfPins(data->pins, filterPG); } // end method // ----------------------------------------------------------------------------- inline Range Net::allPins(const Direction direction) const { return CollectionOfPinsFilteredByDirection(data->pins, direction); } // end method // ----------------------------------------------------------------------------- inline Range Net::allArcs() const { if (hasMultipleDrivers()) { throw Exception("Net::allArcs() does not support multiple drivers yet."); } else { if (hasDriver()) { return CollectionOfArcs(getAnyDriver()->arcs[FORWARD]); } else { static std::vector emptyCollectionOfArcs; // dummy return CollectionOfArcs(emptyCollectionOfArcs); } // end else } // end else } // end method // ----------------------------------------------------------------------------- inline bool Net::isIdeal() const { if (data->tag.ideal.isNotSpecified()) throw TagNotSpecifiedException("Ideal"); return data->tag.ideal; } // end method // ----------------------------------------------------------------------------- inline bool Net::isClockNetwork() const { if (data->tag.type == NET_TYPE_TAG_NOT_SPECIFIED) throw TagNotSpecifiedException("Net Type"); return data->tag.type == NET_TYPE_TAG_CLOCK; } // end method // ----------------------------------------------------------------------------- inline NetTypeTag Net::getNetTypeTag() const { return data->tag.type; } // end method // ============================================================================= // Tag // ============================================================================= inline TristateFlag NetTag::getIdeal() const { return data->type; } // end method // ----------------------------------------------------------------------------- inline NetTypeTag NetTag::getType() const { return data->type; } // end method // ----------------------------------------------------------------------------- inline void NetTag::setType(const NetTypeTag value) { data->type = value; } // end method // ----------------------------------------------------------------------------- inline void NetTag::setIdeal(const bool value) { data->ideal = value; } // end method // ----------------------------------------------------------------------------- inline Use Net::getUse() const { return data->netUse; } // end method // ----------------------------------------------------------------------------- inline void Net::setUse(const Use use) { data->netUse = use; } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/Object.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/Pin.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { inline const std::string Pin::getName() const { switch (getInstanceType()) { case Rsyn::CELL: return getLibraryPin().getName(); case Rsyn::PORT: return getInstanceName(); case Rsyn::MODULE: return getPort().getName(); } // end switch return ""; } // end method // ----------------------------------------------------------------------------- inline const std::string Pin::getFullName(const std::string::value_type separator) const { if (isPort()) { return data? getName() : NullName; } else { return data? (getInstance().getName() + separator + getName()) : NullName; } // end else } // end if // ----------------------------------------------------------------------------- inline Design Pin::getDesign() { // TODO: too many indirection (more inside cell), maybe we need to cache // this. return getInstance().getDesign(); } // end method // ----------------------------------------------------------------------------- inline const Design Pin::getDesign() const { // TODO: too many indirection (more inside cell), maybe we need to cache // this. return data->instance.getDesign(); } // end method // ----------------------------------------------------------------------------- inline Instance Pin::getInstance() const { return data->instance; } // end method // ----------------------------------------------------------------------------- inline Net Pin::getNet() const { return data->net; } // end method // ----------------------------------------------------------------------------- inline Direction Pin::getDirection() const { return data->direction; } // end method // ----------------------------------------------------------------------------- inline int Pin::getIndex() const { return data->index; } // end method // ----------------------------------------------------------------------------- inline const std::string Pin::getInstanceName() const { return getInstance().getName(); } // end method // ----------------------------------------------------------------------------- inline InstanceType Pin::getInstanceType() const { return data->type; } // end method // ----------------------------------------------------------------------------- inline const std::string & Pin::getNetName() const { return getNet().getName(); } // end method // ----------------------------------------------------------------------------- inline const std::string & Pin::getDirectionName() const { return Global::getDirectionName(getDirection()); } // end method // ----------------------------------------------------------------------------- inline LibraryPin Pin::getLibraryPin() const { Rsyn::LibraryCell lcell = getLibraryCell(); return lcell? lcell.getLibraryPinByIndex(data->index) : nullptr; } // end method // ----------------------------------------------------------------------------- inline LibraryCell Pin::getLibraryCell() const { return getInstanceType() == Rsyn::CELL? data->instance->lcell : nullptr; } // end method // ----------------------------------------------------------------------------- inline Port Pin::getPort() const { switch (getInstanceType()) { case Rsyn::MODULE: return getInstance().asModule().getPortByIndex(data->index); case Rsyn::PORT: return getInstance().asPort(); default: return nullptr; } // end if } // end method // ----------------------------------------------------------------------------- inline bool Pin::isPort() const { return data->boundary; } // end method // ----------------------------------------------------------------------------- inline bool Pin::isPort(const Direction direction) const { return isPort() && (getPort().getDirection() == direction); } // end method // ----------------------------------------------------------------------------- inline bool Pin::isPortToUpLevelHierarchy() const { return data->boundary && data->type == Rsyn::PORT; } // end method // ----------------------------------------------------------------------------- inline bool Pin::isPortToDownLevelHierarchy() const { return data->boundary && data->type == Rsyn::MODULE; } // end method // ----------------------------------------------------------------------------- inline bool Pin::isConnected() const { return getNet(); } // end method // ----------------------------------------------------------------------------- inline bool Pin::isDisconnected() const { return !getNet(); } // end method // ----------------------------------------------------------------------------- inline bool Pin::isInput() const { return getDirection() == Rsyn::IN; } // end method // ----------------------------------------------------------------------------- inline bool Pin::isOutput() const { return getDirection() == Rsyn::OUT; } // end method // ----------------------------------------------------------------------------- inline bool Pin::isBidirectional() const { return getDirection() == Rsyn::BIDIRECTIONAL; } // end method // ----------------------------------------------------------------------------- inline bool Pin::isDriver() const { return isOutput(); } // end method // ----------------------------------------------------------------------------- inline bool Pin::isSink() const { return isInput(); } // end method // ----------------------------------------------------------------------------- inline Arc Pin::getArcTo(Pin to) { for (Arc arc : allOutgoingArcs()) { if (arc.getToPin() == to) { return arc; } // end if } // end for return nullptr; } // end method // ----------------------------------------------------------------------------- inline Arc Pin::getArcFrom(Pin from) { for (Arc arc : allIncomingArcs()) { if (arc.getFromPin() == from) { return arc; } // end if } // end for return nullptr; } // end method // ----------------------------------------------------------------------------- inline int Pin::getNumIncomingArcs() const { return (int) data->arcs[BACKWARD].size(); } // end method // ----------------------------------------------------------------------------- inline int Pin::getNumOutgomingArcs() const { return (int) data->arcs[FORWARD].size(); } // end method // ----------------------------------------------------------------------------- inline Range Pin::allPredecessorPins(const bool crossBoundaries) const { return CollectionOfPredecessorPins(*this, crossBoundaries); } // end method // ----------------------------------------------------------------------------- inline Range Pin::allSucessorPins(const bool crossBoundaries) const { return CollectionOfSuccessorPins(*this, crossBoundaries); } // end method // ----------------------------------------------------------------------------- inline const std::vector & Pin::allIncomingArcs() const { return data->arcs[BACKWARD]; } // end method // ----------------------------------------------------------------------------- inline const std::vector & Pin::allOutgoingArcs() const { return data->arcs[FORWARD]; } // end method // ----------------------------------------------------------------------------- inline const std::vector & Pin::allArcs(const TraverseType direction) const { return data->arcs[direction]; } // end method // ----------------------------------------------------------------------------- inline void Pin::connect(Net net) { getDesign().connectPin(*this, net); } // end method // ----------------------------------------------------------------------------- inline void Pin::disconnect() { getDesign().disconnectPin(*this); } // end method // ----------------------------------------------------------------------------- inline TopologicalIndex Pin::getTopologicalIndex() const { return data->order; } // end method // ----------------------------------------------------------------------------- inline bool Pin::isMacroBlockPin() const { return data->instance.isMacroBlock(); } // end method // ----------------------------------------------------------------------------- inline bool Pin::isConnectedToClockNetwork() const { return data->net? data->net.isClockNetwork() : false; } // end method // ----------------------------------------------------------------------------- inline Use Pin::getUse() const { Rsyn::LibraryPin lpin = getLibraryPin(); if (!lpin) { return Rsyn::UNKNOWN_USE; } // end if return lpin.getUse(); } // end method // ----------------------------------------------------------------------------- inline bool Pin::isPowerOrGround() const { Rsyn::LibraryPin lpin = getLibraryPin(); if (!lpin) { return false; } // end if return (lpin.getUse() == POWER || lpin.getUse() == GROUND); } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/core/obj/impl/Port.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { // ----------------------------------------------------------------------------- inline Pin Port::getInnerPin() const { // Ports have just one pin, which is the inner pin... return data->pins[0]; } // end method // ----------------------------------------------------------------------------- inline Pin Port::getOuterPin() const { return Pin(data->outerPin); } // end method // ----------------------------------------------------------------------------- inline Pin Port::getOtherPin(Pin pin) const { Rsyn::Pin inner = getInnerPin(); Rsyn::Pin outer = getOuterPin(); if (inner == pin) return outer; if (outer == pin) return inner; return nullptr; } // end method // ----------------------------------------------------------------------------- inline Direction Port::getDirection() const { return Global::getReverseDirection(getInnerPin().getDirection()); } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/db/Database.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ ================================================ FILE: rsyn/src/rsyn/db/Database.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_DATABASE_H #define RSYN_DATABASE_H #include #include #include namespace Rsyn { class Database { public: void read(const std::string &key, Serializable &data); void write(const std::string &key, const Serializable &data); }; } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/db/Serializable.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_SERIALIZABLE_H #define RSYN_SERIALIZABLE_H #include "SerializationStream.h" namespace Rsyn { class Serializable { public: virtual void read(Rsyn::SerializationStream &stream) = 0; virtual void write(Rsyn::SerializationStream &stream) = 0; }; // end class } #endif /* SERIALIZABLE_H */ ================================================ FILE: rsyn/src/rsyn/db/SerializationStream.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_SERIALIZATION_STREAM_H #define RSYN_SERIALIZATION_STREAM_H #include #include // Note: Reference types are special as they are stored as an id in the stream, // but as a pointer in the memory (for efficiency reasons). Hence they need to // be converted to pointers once the database is loaded. We accomplish that by // storing the id in the reference during the database loading and registering // it for conversion once the database is fully read. Notice that an on-the-fly // conversion may not be always possible as the referenced value may not be // loaded yet (so we still don't know its position in the memory to get a // pointer). namespace Rsyn { class SerializationStream { public: template void read(T &value); template void read(std::vector &value); template void read(std::vector> &value); void read(Rsyn::Instance &instance); void read(Rsyn::Net &net); void read(Rsyn::Pin &pin); void read(Rsyn::Arc &arc); void read(Rsyn::LibraryCell &lcell); void read(Rsyn::LibraryPin &lpin); void read(Rsyn::LibraryArc &larc); template void write(const T &value); template void write(const std::vector &value); template void write(const std::vector> &value); void write(const Rsyn::Instance &instance); void write(const Rsyn::Net &net); void write(const Rsyn::Pin &pin); void write(const Rsyn::Arc &arc); void write(const Rsyn::LibraryCell &lcell); void write(const Rsyn::LibraryPin &lpin); void write(const Rsyn::LibraryArc &larc); private: }; } #endif /* SERIALIZATIONSTREAM_H */ ================================================ FILE: rsyn/src/rsyn/export/Rsyn/DesignObserver ================================================ #include "rsyn/core/infra/Observer.h" ================================================ FILE: rsyn/src/rsyn/export/Rsyn/PhysicalDesign ================================================ #include "rsyn/phy/PhysicalDesign.h" ================================================ FILE: rsyn/src/rsyn/export/Rsyn/PhysicalDesignObserver ================================================ #include "rsyn/phy/infra/PhysicalObserver.h" ================================================ FILE: rsyn/src/rsyn/export/Rsyn/Point ================================================ #include "rsyn/util/geometry/Point.h" ================================================ FILE: rsyn/src/rsyn/export/Rsyn/Polygon ================================================ #include "rsyn/util/geometry/Polygon.h" ================================================ FILE: rsyn/src/rsyn/export/Rsyn/Rect ================================================ #include "rsyn/util/geometry/Rect.h" ================================================ FILE: rsyn/src/rsyn/export/Rsyn/RoutingGuide ================================================ #include "rsyn/ispd18/RoutingGuide.h" ================================================ FILE: rsyn/src/rsyn/export/Rsyn/Scenario ================================================ #include "rsyn/model/scenario/Scenario.h" ================================================ FILE: rsyn/src/rsyn/export/Rsyn/Session ================================================ #include "rsyn/session/Session.h" ================================================ FILE: rsyn/src/rsyn/export/Rsyn/Timer ================================================ #include "rsyn/model/timing/Timer.h" ================================================ FILE: rsyn/src/rsyn/io/legacy/Legacy.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_LEGACY_H #define RSYN_LEGACY_H #include #include "rsyn/core/Rsyn.h" namespace Legacy { inline Rsyn::Direction lefPinDirectionFromString(const std::string &direction) { if (direction == "INPUT" ) return Rsyn::IN; if (direction.substr(0, 6) == "OUTPUT" ) return Rsyn::OUT; if (direction == "INOUT" ) return Rsyn::BIDIRECTIONAL; if (direction == "FEEDTHRU") return Rsyn::UNKNOWN_DIRECTION; return Rsyn::UNKNOWN_DIRECTION; } // end function inline Rsyn::Use lefPinUseFromString(const std::string &direction) { if (direction == "SIGNAL" ) return Rsyn::SIGNAL; if (direction == "POWER" ) return Rsyn::POWER; if (direction == "GROUND" ) return Rsyn::GROUND; if (direction == "CLOCK") return Rsyn::CLOCK; if (direction == "TIEOFF") return Rsyn::TIEOFF; if (direction == "ANALOG") return Rsyn::ANALOG; if (direction == "SCAN") return Rsyn::SCAN; if (direction == "RESET") return Rsyn::RESET; return Rsyn::UNKNOWN_USE; } // end function inline Rsyn::Direction bookshelfPinDirectionFromString(const std::string &direction) { if (direction == "I") return Rsyn::IN; if (direction == "O") return Rsyn::OUT; if (direction == "B") return Rsyn::OUT; // Due to Rsyn restrictions, I am considering the Bidirectional is only output. return Rsyn::UNKNOWN_DIRECTION; } // end function inline std::string bookshelfPinDirectionToString(const Rsyn::Direction direction) { if (direction == Rsyn::IN) return "I"; if (direction == Rsyn::OUT) return "O"; if (direction == Rsyn::BIDIRECTIONAL) return "B"; return ""; } // end function } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/io/legacy/PlacerInternals.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef PLACER_INTERNALS_H #define PLACER_INTERNALS_H #include #include //////////////////////////////////////////////////////////////////////////////// // Design Descriptor //////////////////////////////////////////////////////////////////////////////// #include "rsyn/util/Bounds.h" #include "rsyn/util/dbu.h" namespace Legacy { struct Design { struct Component { std::string id; std::string name; bool fixed; bool placed; double x; double y; }; struct Connection { std::string pin; std::string instance; }; struct Net { std::string name; std::vector connections; }; struct Row { double x; double y; int numSitesX; int numSitesY; std::string site; std::string name; double stepX; double stepY; }; struct Pin { std::string name; std::string net; std::string metal; std::string direction; double x; double y; DBUxy routingLower; DBUxy routingUpper; }; struct DieArea { int xmin; int ymin; int xmax; int ymax; }; struct Track { std::string direction; //X or Y int doStart; int doCount; int doStep; int numLayers; std::vector layers; Track () : direction("NULL"), doStart(-1), doCount(-1), doStep(-1), numLayers(-1) {} }; struct GCellGrid { std::string master; // direction X or Y int doStart; int doCount; int doStep; GCellGrid () : master("null"), doStart(-1), doCount(-1), doStep(-1) {} }; std::string name; double distanceUnit; double defVersion; std::vector components; std::vector ports; std::vector nets; std::vector rows; std::vector primaryInputs; std::vector primaryOutputs; std::vector tracks; std::vector gCellGrids; DieArea dieArea; Design() { distanceUnit = 1; defVersion = -1; } }; // end struct //////////////////////////////////////////////////////////////////////////////// // Library Descriptor //////////////////////////////////////////////////////////////////////////////// struct Library { struct Site { std::string name; std::string classSite; bool hasClass; double w; double h; Site() :name("null"), classSite("null"), hasClass(false), w(0), h(0) {} }; struct Pin { std::string name; std::string direction; std::string metalLayer; Bounds bound; std::vector routerPins; double dx; double dy; Pin() : dx(0), dy(0), metalLayer("null") {} }; struct Obstruction { std::string layer; std::vector rects; }; struct Macro { std::string name; std::string type; std::string site; double w; double h; std::vector pins; std::vector obs; Macro () : w(0), h(0) {} }; // end struct struct Layer { // for metals, vias and contacts std::string name; std::string type; std::string direction; double pitch; double width; double spacing; Layer () : name("null"), type("null"), direction("null"), pitch(-1), width(-1), spacing(-1) {} }; struct Spacing { std::string name1; std::string name2; double distance; }; std::string name; double distanceUnit; std::vector macros; std::vector sites; std::vector layers; std::vector metalSpaces; Library() : distanceUnit(1) {} }; // end struct struct DefStruct1 { struct DefMacro { std::string name; std::string lefCellName; bool placed; bool fixed; DBUxy pos; }; struct DefPin { std::string pinName; std::string cellName; }; struct DefConnection { std::string netName; std::vector pins; //cell and pin }; struct DefRow { std::string rowName; std::string rowType; int origX; int origY; int orient; int doCount; int doIncrement; int xStep; int yStep; DefRow () : rowType("core"), origX(0), origY(0), orient(0), doCount(0), doIncrement(0), xStep(0), yStep(0) {} // orient {0, 1, 2, 3, 4, 5, 6, 7} = {N, W, S, E, FN, FW, FS, FE} source: defapi.pdf version 5.8 }; struct DefPortLayer { std::string layerName; int spacing; int designRuleWidth; Bounds bounds; DefPortLayer() : spacing(0), designRuleWidth(0), layerName("NULL") {} }; struct DefPort { std::string portName; std::string netName; int special; // 0 is ignored; 1 writes a SPECIAL statement std::string direction; // {NULL, FEEDTHRU, INPUT, INOUT, OUTPUT} std::string use; // {NULL, ANALOG, CLOCK, GROUND, POWER, RESET, SCAN, SIGNAL, TIEOFF} std::string status; // {NULL, COVER, FIXED, PLACED} int statusX; // placement location; 0 ignore int statusY; // placement location; 0 ignore int orient; // orient {-1, 0, 1, 2, 3, 4, 5, 6, 7} = {IGNORE, N, W, S, E, FN, FW, FS, FE} source: defapi.pdf version 5.8 DefPortLayer clsDefPortLayer; DefPort () : direction("NULL"), orient(-1), special(0), status("NULL"), use("NULL") {} }; std::vector clsDefMacros; std::vector clsDefPorts; std::vector clsDefConnections; std::vector clsDefRows; int majorDefVersion; int minorDefVersion; std::string devideChar; std::string busBitChar; std::string designName; int designUnits; Bounds dieArea; }; // end struct } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/io/parser/guide-ispd18/GuideDescriptor.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ISPD18GUIDEDESCRIPTOR_H #define ISPD18GUIDEDESCRIPTOR_H #include #include "rsyn/util/Bounds.h" class GuideLayerDscp { public: Bounds clsLayerGuide; std::string clsLayer = ""; GuideLayerDscp() = default; }; // end class // ----------------------------------------------------------------------------- class GuideNetDscp { public: std::string clsNetName = ""; std::deque clsLayerDscps; GuideNetDscp() = default; }; // end class // ----------------------------------------------------------------------------- class GuideDscp { public: std::deque clsNetGuides; GuideDscp() = default; }; // end class // ----------------------------------------------------------------------------- #endif /* ISPD18GUIDEDESCRIPTOR_H */ ================================================ FILE: rsyn/src/rsyn/io/parser/guide-ispd18/GuideParser.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "rsyn/io/parser/guide-ispd18/GuideParser.h" void GuideParser::parse(std::string& guidePath, GuideDscp& guideDscp) { clsIS.open(guidePath.c_str()); if (!clsIS.is_open()) { std::cout << "[ERROR] File '" << guidePath << "' could not be opened.\n"; exit(1); } // end if while (!clsIS.eof()) { std::string netName; if(!readNet(netName)) continue; std::deque & nets = guideDscp.clsNetGuides; nets.push_back(GuideNetDscp()); GuideNetDscp & net = nets.back(); net.clsNetName = netName; readLayerGuide(net); } // end while clsIS.close(); } // end method // ----------------------------------------------------------------------------- bool GuideParser::readLine(std::vector& tokens) { tokens.clear(); std::string line; std::getline(clsIS, line); std::string token = ""; for (unsigned i = 0; i < line.size(); ++i) { char current = line[i]; if (std::isspace(current)) { if (!token.empty()) { tokens.push_back(token); token.clear(); } // end if } else { token.push_back(current); } //vend if-else } // end for if (!token.empty()) tokens.push_back(token); return !clsIS.eof(); } // end method // ----------------------------------------------------------------------------- bool GuideParser::readNet(std::string & net) { std::vector tokens; readLine(tokens); if (tokens.empty()) return false; net = tokens.front(); return true; } // end method // ----------------------------------------------------------------------------- bool GuideParser::isStartLayer(std::string & token) { return token.compare("(") == 0; } // end method // ----------------------------------------------------------------------------- bool GuideParser::isEndLayer(std::string & token) { return token.compare(")") == 0; } // end method // ----------------------------------------------------------------------------- bool GuideParser::readLayerGuide(GuideNetDscp & dscp) { while (true) { std::vector tokens; readLine(tokens); if (isStartLayer(tokens.front())) continue; if (isEndLayer(tokens.front())) return true; if(tokens.size() < 5) { std::cout<<"WARNING: skipping parsing a layer guide of net "< #include #include "GuideDescriptor.h" #include "rsyn/util/Bounds.h" /*net1230 ( 95010 71819 100710 91201 Metal2 95010 83220 100710 91201 Metal1 89310 71819 100710 77520 Metal3 95010 71819 100710 77520 Metal2 89310 71819 95010 77520 Metal2 89310 71819 95010 77520 Metal2 89310 71819 95010 77520 Metal1 ) */ class GuideParser { protected: std::ifstream clsIS; public: GuideParser() = default; void parse(std::string & guidePath, GuideDscp & guideDscp); protected: bool readLine(std::vector& tokens); bool readNet(std::string & net); bool isStartLayer(std::string & token); bool isEndLayer(std::string & token); bool readLayerGuide(GuideNetDscp & dscp); }; #endif /* ISPD18GUIDEPARSER_H */ ================================================ FILE: rsyn/src/rsyn/io/parser/lef_def/DEFControlParser.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "DEFControlParser.h" #ifndef WIN32 #include #else #include #endif /* not WIN32 */ #include #include #include // DEF headers #include "def5.8/defiComponent.hpp" #include "def5.8/defiNet.hpp" #include "def5.8/defiRowTrack.hpp" #include "def5.8/defwWriter.hpp" #include "def5.8/defrReader.hpp" extern void freeCB(void* name); extern void* mallocCB(size_t size); extern void* reallocCB(void* name, size_t size); #include "rsyn/util/Bounds.h" #include "rsyn/util/DoubleRectangle.h" // ----------------------------------------------------------------------------- DEFControlParser::DEFControlParser() { } // end constructor // ----------------------------------------------------------------------------- DEFControlParser::~DEFControlParser() { } // end destructor // ----------------------------------------------------------------------------- //DEF CALLBACKS char* defAddress(const char* in); void defCheckType(defrCallbackType_e c); int defCompf(defrCallbackType_e c, defiComponent* co, defiUserData ud); int defComponentStart(defrCallbackType_e c, int num, defiUserData ud); int defDesignName(defrCallbackType_e c, const char* string, defiUserData ud); int defEndFunc(defrCallbackType_e c, void* dummy, defiUserData ud); int defExt(defrCallbackType_e t, const char* c, defiUserData ud); int defNetStart(defrCallbackType_e c, int num, defiUserData ud); int defNetWires(defiNet* net, DefNetDscp& netDscp); int defNet(defrCallbackType_e c, defiNet* net, defiUserData ud); int defUnits(defrCallbackType_e c, double d, defiUserData ud); int defVersion(defrCallbackType_e c, double d, defiUserData ud); int defRow(defrCallbackType_e type, defiRow* rowInfo, defiUserData userData); char* defOrientStr(int orient); int defOrient(std::string orient); int defDieArea(defrCallbackType_e typ, defiBox* box, defiUserData ud); int defTrack(defrCallbackType_e typ, defiTrack * track, defiUserData data); int defGCellGrid(defrCallbackType_e typ, defiGcellGrid * gCell, defiUserData data); int defRegion(defrCallbackType_e type, defiRegion* region, defiUserData ud); int defRegionStart(defrCallbackType_e c, int num, defiUserData ud); int defGroupStart(defrCallbackType_e c, int num, defiUserData ud); int defGroupMember(defrCallbackType_e type, const char* name, defiUserData userData); int defGroupName(defrCallbackType_e type, const char* name, defiUserData ud); int defGroups(defrCallbackType_e type, defiGroup *group, defiUserData ud); int defPin(defrCallbackType_e, defiPin *pin, defiUserData ud); int defSpecialNetStart(defrCallbackType_e c, int num, defiUserData ud); int defSpecialNet(defrCallbackType_e c, defiNet* net, defiUserData ud); int defViaStart(defrCallbackType_e, int number, defiUserData); int defVia(defrCallbackType_e, defiVia *, defiUserData); DefDscp &getDesignFromUserData(defiUserData userData) { return *((DefDscp *) userData); } // end function // ============================================================================= // DEF Function Implementation // ============================================================================= void DEFControlParser::parseDEF(const std::string &filename, DefDscp &defDscp) { defrInit(); defrReset(); //defrSetAddPathToNet(); defrSetComponentCbk(defCompf); defrSetDesignCbk(defDesignName); defrSetPinCbk(defPin); defrSetUnitsCbk(defUnits); defrSetVersionCbk(defVersion); defrSetRowCbk(defRow); defrSetComponentStartCbk(defComponentStart); defrSetDieAreaCbk(defDieArea); defrSetMallocFunction(mallocCB); defrSetReallocFunction(reallocCB); defrSetFreeFunction(freeCB); defrSetNetStartCbk(defNetStart); defrSetNetCbk(defNet); //defrSetSNetWireCbk(); defrSetGroupsStartCbk(defGroupStart); defrSetGroupNameCbk(defGroupName); defrSetGroupMemberCbk(defGroupMember); defrSetGroupCbk(defGroups); defrSetTrackCbk(defTrack); defrSetGcellGridCbk(defGCellGrid); defrSetRegionStartCbk(defRegionStart); defrSetRegionCbk(defRegion); // register special net call backs defrSetSNetStartCbk(defSpecialNetStart); defrSetSNetCbk(defSpecialNet); // register via call backs defrSetViaStartCbk(defViaStart); defrSetViaCbk(defVia); //defrSetGcellGridWarnings(3); defrSetAddPathToNet(); FILE * f; int res; (void) defrSetOpenLogFileAppend(); if ((f = fopen(filename.c_str(), "r")) == 0) { printf("Couldn't open input file '%s'\n", filename.c_str()); return; } // Set case sensitive to 0 to start with, in History & PropertyDefinition // reset it to 1. res = defrRead(f, filename.c_str(), (void*) &defDscp, 1); if (res) printf("Reader returns bad status. %s\n", filename.c_str()); //(void) defrPrintUnusedCallbacks(fout); (void) defrReleaseNResetMemory(); (void) defrUnsetNonDefaultCbk(); (void) defrUnsetNonDefaultStartCbk(); (void) defrUnsetNonDefaultEndCbk(); defrClear(); } // ----------------------------------------------------------------------------- char* defAddress(const char* in) { return ((char*) in); } // end method // ----------------------------------------------------------------------------- void defCheckType(defrCallbackType_e c) { if (c >= 0 && c <= defrDesignEndCbkType) { // OK } else { printf("ERROR: callback type is out of bounds!\n"); } } // end method // ----------------------------------------------------------------------------- int defRow(defrCallbackType_e type, defiRow* rowInfo, defiUserData userData) { DefDscp &defDscp = getDesignFromUserData(userData); defDscp.clsRows.resize(defDscp.clsRows.size() + 1); DefRowDscp &defRow = defDscp.clsRows.back(); defRow.clsName = rowInfo->name(); defRow.clsSite = rowInfo->macro(); defRow.clsOrientation = rowInfo->orientStr(); defRow.clsOrigin[X] = static_cast (rowInfo->x()); defRow.clsOrigin[Y] = static_cast (rowInfo->y()); if (rowInfo->hasDoStep()) { defRow.clsNumX = static_cast (rowInfo->xNum()); defRow.clsNumY = static_cast (rowInfo->yNum()); defRow.clsStepX = static_cast (rowInfo->xStep()); defRow.clsStepY = static_cast (rowInfo->yStep()); } else if (rowInfo->hasDo()) { defRow.clsNumX = static_cast (rowInfo->xNum()); defRow.clsNumY = static_cast (rowInfo->yNum()); defRow.clsStepX = 0; defRow.clsStepY = 0; } else { defRow.clsNumX = 1; defRow.clsNumY = 1; defRow.clsStepX = 0; defRow.clsStepY = 0; } // end else return 0; } // end method // ----------------------------------------------------------------------------- int defPin(defrCallbackType_e, defiPin *pin, defiUserData userData) { DefDscp &defDscp = getDesignFromUserData(userData); defDscp.clsPorts.resize(defDscp.clsPorts.size() + 1); DefPortDscp &defPin = defDscp.clsPorts.back(); defPin.clsName = pin->pinName(); defPin.clsNetName = pin->netName(); defPin.clsDirection = pin->direction(); defPin.clsPos[X] = pin->placementX(); defPin.clsPos[Y] = pin->placementY(); defPin.clsICCADPos = defPin.clsPos; defPin.clsOrientation = pin->orientStr(); if (pin->hasLayer()) { defPin.clsLayerName = pin->layer(0); int xl, yl, xh, yh; pin->bounds(0, &xl, &yl, &xh, &yh); defPin.clsLayerBounds[LOWER][X] = xl; defPin.clsLayerBounds[LOWER][Y] = yl; defPin.clsLayerBounds[UPPER][X] = xh; defPin.clsLayerBounds[UPPER][Y] = yh; defPin.clsICCADPos += defPin.clsLayerBounds.computeCenter(); // legacy iccad15 contest pin position } // end if return 0; } // end method // ----------------------------------------------------------------------------- int defCompf(defrCallbackType_e c, defiComponent* co, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsComps.push_back(DefComponentDscp()); DefComponentDscp &defComp = defDscp.clsComps.back(); defComp.clsName = DEFControlParser::unescape(co->id()); defComp.clsMacroName = co->name(); defComp.clsIsFixed = co->isFixed(); defComp.clsIsPlaced = co->isPlaced(); defComp.clsPos[X] = co->placementX(); defComp.clsPos[Y] = co->placementY(); defComp.clsOrientation = co->placementOrientStr(); return 0; } // end method // ----------------------------------------------------------------------------- int defComponentStart(defrCallbackType_e c, int num, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsComps.reserve(num); return 0; } // end method // ----------------------------------------------------------------------------- int defNetStart(defrCallbackType_e c, int num, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsNets.reserve(num); return 0; } // end method // ----------------------------------------------------------------------------- int defDesignName(defrCallbackType_e c, const char* string, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsDesignName = string; return 0; } // end method // ----------------------------------------------------------------------------- int defNetWires(defiNet* net, DefNetDscp& netDscp) { netDscp.clsWires.resize(net->numWires()); for (unsigned i = 0; static_cast(i) < net->numWires(); ++i) { DefWireDscp & wireDscp = netDscp.clsWires[i]; defiWire * wire = net->wire(i); wireDscp.clsWireType = wire->wireType(); wireDscp.clsWireSegments.resize(wire->numPaths()); for (unsigned j = 0; static_cast(j) < wire->numPaths(); ++j) { DefWireSegmentDscp & segmentDscp = wireDscp.clsWireSegments[j]; defiPath* path = wire->path(j); path->initTraverse(); int pathId = path->next(); int x, y, extension; DefRoutingPointDscp * point; while (pathId != DEFIPATH_DONE) { switch (pathId) { case DEFIPATH_LAYER: segmentDscp.clsLayerName = path->getLayer(); break; case DEFIPATH_VIA: point->clsViaName = path->getVia(); point->clsHasVia = true; break; case DEFIPATH_VIAROTATION: { // TEMPORARY WARNING MESSAGE // mateus @ 180528 static bool warning = false; if (!warning) { warning = true; std::cout << "TODO DEFIPATH_VIAROTATION at " << __func__ << "\n"; } // end if } // end block break; case DEFIPATH_WIDTH: segmentDscp.clsRoutedWidth = static_cast (path->getWidth()); break; case DEFIPATH_POINT: path->getPoint(&x, &y); segmentDscp.clsRoutingPoints.emplace_back(); point = &segmentDscp.clsRoutingPoints.back(); point->clsPos = DBUxy(static_cast (x), static_cast (y)); point->clsExtension = -1; break; case DEFIPATH_FLUSHPOINT: path->getFlushPoint(&x, &y, &extension); segmentDscp.clsRoutingPoints.emplace_back(); point = &segmentDscp.clsRoutingPoints.back(); point->clsPos = DBUxy(static_cast (x), static_cast (y)); point->clsExtension = extension; point->clsHasExtension = true; break; case DEFIPATH_TAPER: { // TEMPORARY WARNING MESSAGE // mateus @ 180528 static bool warning = false; if (!warning) { warning = true; std::cout << "TODO DEFIPATH_TAPER at " << __func__ << "\n"; } // end if } // end block break; case DEFIPATH_SHAPE: segmentDscp.clsHasShape = true; segmentDscp.clsShape = path->getShape(); break; case DEFIPATH_MASK: { // TEMPORARY WARNING MESSAGE // mateus @ 180528 static bool warning = false; if (!warning) { warning = true; std::cout << "TODO DEFIPATH_MASK at " << __func__ << "\n"; } // end if } // end block break; case DEFIPATH_VIAMASK: { // TEMPORARY WARNING MESSAGE // mateus @ 180528 static bool warning = false; if (!warning) { warning = true; std::cout << "TODO DEFIPATH_VIAMASK at " << __func__ << "\n"; } // end if } // end block break; case DEFIPATH_RECT: int deltaxl, deltayl, deltaxu, deltayu; path->getViaRect(&deltaxl, &deltayl, &deltaxu, &deltayu); point->clsHasRectangle = true; point->clsRect[LOWER][X] = static_cast (deltaxl); point->clsRect[LOWER][Y] = static_cast (deltayl); point->clsRect[UPPER][X] = static_cast (deltaxu); point->clsRect[UPPER][Y] = static_cast (deltayu); break; case DEFIPATH_VIRTUALPOINT: { // TEMPORARY WARNING MESSAGE // mateus @ 180528 static bool warning = false; if (!warning) { warning = true; std::cout << "TODO DEFIPATH_VIRTUALPOINT at " << __func__ << "\n"; } // end if } // end block break; case DEFIPATH_TAPERRULE: { // TEMPORARY WARNING MESSAGE // mateus @ 180528 static bool warning = false; if (!warning) { warning = true; std::cout << "TODO DEFIPATH_TAPERRULE at " << __func__ << "\n"; } // end if } // end block break; case DEFIPATH_STYLE: { // TEMPORARY WARNING MESSAGE // mateus @ 180528 static bool warning = false; if (!warning) { warning = true; std::cout << "TODO DEFIPATH_STYLE at " << __func__ << "\n"; } // end if } // end block break; } // end switch pathId = path->next(); } // end while } // end for } // end for return 0; } // end method // ----------------------------------------------------------------------------- int defNet(defrCallbackType_e c, defiNet* net, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsNets.emplace_back(); DefNetDscp & netDscp = defDscp.clsNets.back(); netDscp.clsName = net->name(); netDscp.clsConnections.resize(net->numConnections()); for (unsigned i = 0; static_cast(i) < net->numConnections(); ++i) { DefNetConnection &connection = netDscp.clsConnections[i]; connection.clsPinName = net->pin(i); connection.clsComponentName = DEFControlParser::unescape(net->instance(i)); } // end for defNetWires(net, netDscp); return 0; } // end method // ----------------------------------------------------------------------------- int defSpecialNetStart(defrCallbackType_e c, int num, void* ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsSpecialNets.reserve(num); return 0; }// end method // ----------------------------------------------------------------------------- int defSpecialNet(defrCallbackType_e c, defiNet* net, void* ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsSpecialNets.emplace_back(); DefNetDscp & netDscp = defDscp.clsSpecialNets.back(); netDscp.clsName = net->name(); netDscp.clsConnections.resize(net->numConnections()); if (net->hasUse()) { netDscp.clsHasUse = true; netDscp.clsUse = net->use(); } for (unsigned i = 0; static_cast(i) < net->numConnections(); ++i) { DefNetConnection &connection = netDscp.clsConnections[i]; connection.clsPinName = net->pin(i); connection.clsComponentName = DEFControlParser::unescape(net->instance(i)); } // end for defNetWires(net, netDscp); return 0; }// end method // ----------------------------------------------------------------------------- int defTrack(defrCallbackType_e typ, defiTrack * track, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsTracks.push_back(DefTrackDscp()); DefTrackDscp & trackDscp = defDscp.clsTracks.back(); trackDscp.clsDirection = track->macro(); trackDscp.clsLocation = static_cast (std::round(track->x())); trackDscp.clsNumTracks = static_cast (std::round(track->xNum())); trackDscp.clsSpace = static_cast (std::round(track->xStep())); trackDscp.clsLayers.reserve(track->numLayers()); for (int i = 0; i < track->numLayers(); i++) { trackDscp.clsLayers.push_back(track->layer(i)); } // end for return 0; } // end method // ----------------------------------------------------------------------------- int defViaStart(defrCallbackType_e c, int number, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsVias.reserve(number); return 0; } // end method // ----------------------------------------------------------------------------- int defVia(defrCallbackType_e c, defiVia * via, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsVias.push_back(DefViaDscp()); DefViaDscp & viaDscp = defDscp.clsVias.back(); viaDscp.clsName = via->name(); if (via->hasViaRule()) { viaDscp.clsHasViaRule = true; char * name; int xSize, ySize, xCutSpacing, yCutSpacing, xBotEnc, yBotEnc, xTopEnc, yTopEnc; char * bottom; char * cut; char * top; via->viaRule(&name, &xSize, &ySize, &bottom, &cut, &top, &xCutSpacing, &yCutSpacing, &xBotEnc, &yBotEnc, &xTopEnc, &yTopEnc); viaDscp.clsViaRuleName = name; viaDscp.clsXCutSize = xSize; viaDscp.clsYCutSize = ySize; viaDscp.clsBottomLayer = bottom; viaDscp.clsCutLayer = cut; viaDscp.clsTopLayer = top; viaDscp.clsXCutSpacing = xCutSpacing; viaDscp.clsYCutSpacing = yCutSpacing; viaDscp.clsXBottomEnclosure = xBotEnc; viaDscp.clsYBottomEnclosure = yBotEnc; viaDscp.clsXTopEnclosure = xTopEnc; viaDscp.clsYTopEnclosure = yTopEnc; if (via->hasRowCol()) { viaDscp.clsHasRowCol = true; via->rowCol(&viaDscp.clsNumCutRows, &viaDscp.clsNumCutCols); } // end if if (via->hasOrigin()) { viaDscp.clsHasOrigin = true; int xOrigen, yOrigen; via->origin(&xOrigen, &yOrigen); viaDscp.clsXOffsetOrigin = xOrigen; viaDscp.clsYOffsetOrigin = yOrigen; } // end if if (via->hasOffset()) { viaDscp.clsHasOffset = true; int xBotOffset, yBotOffset, xTopOffset, yTopOffset; via->offset(&xBotOffset, &yBotOffset, &xTopOffset, &yTopOffset); viaDscp.clsXBottomOffset = xBotOffset; viaDscp.clsYBottomOffset = yBotOffset; viaDscp.clsXTopOffset = xTopOffset; viaDscp.clsYTopOffset = yTopOffset; } // end if if (via->hasPattern()) { viaDscp.clsHasPattern = true; viaDscp.clsPattern = via->pattern(); } // end if } else { viaDscp.clsHasViaRule = false; std::map> &mapGeos = viaDscp.clsGeometries; int xl, yl, xh, yh; char * layerName; for (int i = 0; i < via->numLayers(); ++i) { via->layer(i, &layerName, &xl, &yl, &xh, &yh); std::string name = layerName; std::deque & geos = mapGeos[name]; geos.push_back(DefViaGeometryDscp()); DefViaGeometryDscp & geoDscp = geos.back(); geoDscp.clsIsRect = true; geoDscp.clsBounds[LOWER][X] = static_cast (xl); geoDscp.clsBounds[LOWER][Y] = static_cast (yl); geoDscp.clsBounds[UPPER][X] = static_cast (xh); geoDscp.clsBounds[UPPER][Y] = static_cast (yh); if (via->hasRectMask(i)) { geoDscp.clsHasMask = true; geoDscp.clsMask = via->rectMask(i); } // end if } // end for } // end if-else return 0; } // end method // ----------------------------------------------------------------------------- int defUnits(defrCallbackType_e c, double d, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsDatabaseUnits = static_cast (d); return 0; } // end method // ----------------------------------------------------------------------------- int defVersion(defrCallbackType_e c, double d, defiUserData ud) { DefDscp &defDscp = getDesignFromUserData(ud); defDscp.clsVersion = d; return 0; } // end method // ----------------------------------------------------------------------------- char* defOrientStr(int orient) { switch (orient) { case 0: return ((char*) "N"); case 1: return ((char*) "W"); case 2: return ((char*) "S"); case 3: return ((char*) "E"); case 4: return ((char*) "FN"); case 5: return ((char*) "FW"); case 6: return ((char*) "FS"); case 7: return ((char*) "FE"); }; return ((char*) "BOGUS"); } // end method // ----------------------------------------------------------------------------- int defOrient(std::string orient) { if (orient.compare("N") == 0) return 0; if (orient.compare("W") == 0) return 1; if (orient.compare("S") == 0) return 2; if (orient.compare("E") == 0) return 3; if (orient.compare("FN") == 0) return 4; if (orient.compare("FW") == 0) return 5; if (orient.compare("FS") == 0) return 6; if (orient.compare("FE") == 0) return 7; return -1; } // end method // ----------------------------------------------------------------------------- int defDieArea(defrCallbackType_e typ, defiBox* box, defiUserData ud) { DefDscp &defDscp = getDesignFromUserData(ud); defDscp.clsDieBounds[LOWER][X] = box->defiBox::xl(); defDscp.clsDieBounds[LOWER][Y] = box->defiBox::yl(); defDscp.clsDieBounds[UPPER][X] = box->defiBox::xh(); defDscp.clsDieBounds[UPPER][Y] = box->defiBox::yh(); return 0; } // end method // ----------------------------------------------------------------------------- int defGCellGrid(defrCallbackType_e typ, defiGcellGrid * gcell, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsGcellGrids.emplace_back(); DefGcellGridDscp & gcellGridDscp = defDscp.clsGcellGrids.back(); gcellGridDscp.clsMacro = gcell->macro(); gcellGridDscp.clsX = gcell->x(); gcellGridDscp.clsXNum = gcell->xNum(); gcellGridDscp.clsXStep = gcell->xStep(); return 0; } // end method // ----------------------------------------------------------------------------- int defRegionStart(defrCallbackType_e c, int num, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsRegions.reserve(num); return 0; } // end method // ----------------------------------------------------------------------------- int defRegion(defrCallbackType_e type, defiRegion* region, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsRegions.push_back(DefRegionDscp()); DefRegionDscp & regionDscp = defDscp.clsRegions.back(); regionDscp.clsName = region->name(); regionDscp.clsType = region->type(); regionDscp.clsBounds.resize(region->numRectangles()); for (int i = 0; i < region->numRectangles(); i++) { Bounds & bounds = regionDscp.clsBounds[i]; bounds[LOWER][X] = region->xl(i); bounds[LOWER][Y] = region->yl(i); bounds[UPPER][X] = region->xh(i); bounds[UPPER][Y] = region->yh(i); } return 0; } // end method // ----------------------------------------------------------------------------- int defGroupStart(defrCallbackType_e c, int num, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsGroups.reserve(num); return 0; } // end method // ----------------------------------------------------------------------------- int defGroupName(defrCallbackType_e type, const char* name, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsGroups.push_back(DefGroupDscp()); DefGroupDscp & defGroup = defDscp.clsGroups.back(); defGroup.clsName = name; return 0; } // end method // ----------------------------------------------------------------------------- int defGroupMember(defrCallbackType_e type, const char* name, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); DefGroupDscp & defGroup = defDscp.clsGroups.back(); defGroup.clsPatterns.push_back(name); return 0; } // end method // ----------------------------------------------------------------------------- int defGroups(defrCallbackType_e type, defiGroup *group, defiUserData ud) { DefDscp & defDscp = getDesignFromUserData(ud); DefGroupDscp & defGroup = defDscp.clsGroups.back(); defGroup.clsRegion = group->regionName(); return 0; } // end method // ----------------------------------------------------------------------------- #define CHECK_STATUS(status) \ if (status) { \ defwPrintError(status); \ } // end if // ----------------------------------------------------------------------------- void DEFControlParser::writeDEF(const std::string &filename, const std::string designName, const std::vector &components) { FILE * defFile; defFile = fopen(filename.c_str(), "w"); if (defFile == NULL) { printf("ERROR: could not open output file: %s \n", filename.c_str()); } int status; int numComponents = components.size(); status = defwInitCbk(defFile); CHECK_STATUS(status); defwAddComment("ICCAD 2015 contest - CADA085 Team solution"); status = defwNewLine(); CHECK_STATUS(status); status = defwNewLine(); CHECK_STATUS(status); status = defwVersion(5, 7); CHECK_STATUS(status); status = defwDesignName(designName.c_str()); CHECK_STATUS(status); status = defwNewLine(); CHECK_STATUS(status); status = defwStartComponents(numComponents); CHECK_STATUS(status); for (const DefComponentDscp & comp : components) { //int defwComponent(const char* name, const char* master, const char* eeq, const char* source, const char* status, int statusX, int statusY, int statusOrient, double weight, const char* region); status = defwComponent(comp.clsName.c_str(), comp.clsMacroName.c_str(), 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, comp.clsIsFixed ? "FIXED" : "PLACED", (int) comp.clsPos[X], (int) comp.clsPos[Y], 0, 0, NULL, 0, 0, 0, 0); CHECK_STATUS(status); } //defwEndComponents(); status = defwEndComponents(); CHECK_STATUS(status); status = defwNewLine(); CHECK_STATUS(status); status = defwEnd(); CHECK_STATUS(status); fclose(defFile); } // end method // ----------------------------------------------------------------------------- void DEFControlParser::writeFullDEF(const string &filename, const DefDscp &defDscp) { //Opening FILE * defFile; int status; defFile = fopen(filename.c_str(), "w"); if (defFile == NULL) { printf("ERROR: could not open output file: %s \n", filename.c_str()); } status = defwInitCbk(defFile); CHECK_STATUS(status); //writing header defwAddComment("DEF file generated by CUHK DR"); status = defwNewLine(); CHECK_STATUS(status); status = defwNewLine(); CHECK_STATUS(status); status = defwVersion(5, 8); // TODO get from design CHECK_STATUS(status); status = defwDividerChar("/"); CHECK_STATUS(status); status = defwBusBitChars("[]"); CHECK_STATUS(status); status = defwDesignName(defDscp.clsDesignName.c_str()); CHECK_STATUS(status); if (defDscp.clsHasDatabaseUnits) { status = defwUnits(defDscp.clsDatabaseUnits); CHECK_STATUS(status); } // end if if (defDscp.clsHasDieBounds) { status = defwNewLine(); CHECK_STATUS(status); status = defwDieArea( (int) defDscp.clsDieBounds[LOWER][X], (int) defDscp.clsDieBounds[LOWER][Y], (int) defDscp.clsDieBounds[UPPER][X], (int) defDscp.clsDieBounds[UPPER][Y]); CHECK_STATUS(status); } // end if status = defwNewLine(); CHECK_STATUS(status); for (const DefRowDscp & defRow : defDscp.clsRows) { status = defwRow( defRow.clsName.c_str(), defRow.clsSite.c_str(), defRow.clsOrigin[X], defRow.clsOrigin[Y], defOrient(defRow.clsOrientation), defRow.clsNumX, defRow.clsNumY, defRow.clsStepX, defRow.clsStepY); CHECK_STATUS(status); status = defwNewLine(); CHECK_STATUS(status); } // end for // Write tracks const char** layers; for (const DefTrackDscp & track : defDscp.clsTracks) { int numLayers = track.clsLayers.size(); layers = (const char**) malloc(sizeof (char*)*numLayers); for (int i = 0; i < numLayers; i++) { layers[i] = track.clsLayers[i].c_str(); } // end for status = defwTracks(track.clsDirection.c_str(), track.clsLocation, track.clsNumTracks, track.clsSpace, numLayers, layers); CHECK_STATUS(status); free((char*) layers); } // end for status = defwNewLine(); CHECK_STATUS(status); // Write vias const unsigned numVias = defDscp.clsVias.size(); if (numVias > 0) { status = defwStartVias(numVias); CHECK_STATUS(status); for (const DefViaDscp & via : defDscp.clsVias) { status = defwViaName(via.clsName.c_str()); CHECK_STATUS(status); if (via.clsBottomLayer.size()) { std::map>::const_iterator it = via.clsGeometries.find(via.clsBottomLayer); if (it != via.clsGeometries.end()) { for (const DefViaGeometryDscp & geo : it->second) { const Bounds& bounds = geo.clsBounds; status = defwViaRect(via.clsBottomLayer.c_str(), bounds[LOWER][X], bounds[LOWER][Y], bounds[UPPER][X], bounds[UPPER][Y]); CHECK_STATUS(status); } } } if (via.clsTopLayer.size()) { std::map>::const_iterator it = via.clsGeometries.find(via.clsTopLayer); if (it != via.clsGeometries.end()) { for (const DefViaGeometryDscp & geo : it->second) { const Bounds& bounds = geo.clsBounds; status = defwViaRect(via.clsTopLayer.c_str(), bounds[LOWER][X], bounds[LOWER][Y], bounds[UPPER][X], bounds[UPPER][Y]); CHECK_STATUS(status); } } } if (via.clsCutLayer.size()) { std::map>::const_iterator it = via.clsGeometries.find(via.clsCutLayer); if (it != via.clsGeometries.end()) { for (const DefViaGeometryDscp & geo : it->second) { const Bounds& bounds = geo.clsBounds; status = defwViaRect(via.clsCutLayer.c_str(), bounds[LOWER][X], bounds[LOWER][Y], bounds[UPPER][X], bounds[UPPER][Y]); CHECK_STATUS(status); } } } if (via.clsHasViaRule) { status = defwNewLine(); CHECK_STATUS(status); status = defwViaViarule(via.clsViaRuleName.c_str(), via.clsXCutSize, via.clsYCutSize, via.clsBottomLayer.c_str(), via.clsCutLayer.c_str(), via.clsTopLayer.c_str(), via.clsXCutSpacing, via.clsYCutSpacing, via.clsXBottomEnclosure, via.clsYBottomEnclosure, via.clsXTopEnclosure, via.clsYTopEnclosure); CHECK_STATUS(status); } if (via.clsHasRowCol) { status = defwViaViaruleRowCol(via.clsNumCutRows, via.clsNumCutCols); CHECK_STATUS(status); } if (via.clsHasOrigin) { status = defwViaViaruleOrigin(via.clsXOffsetOrigin, via.clsYOffsetOrigin); CHECK_STATUS(status); } if (via.clsHasOffset) { status = defwViaViaruleOffset(via.clsXBottomOffset, via.clsYBottomOffset, via.clsXTopOffset, via.clsYTopOffset); CHECK_STATUS(status); } if (via.clsHasPattern) { status = defwViaViarulePattern(via.clsPattern.c_str()); CHECK_STATUS(status); } status = defwNewLine(); CHECK_STATUS(status); status = defwOneViaEnd(); CHECK_STATUS(status); } // end for status = defwEndVias(); CHECK_STATUS(status); } // end if status = defwNewLine(); CHECK_STATUS(status); // Write components const unsigned numComponents = defDscp.clsComps.size(); if (numComponents > 0) { status = defwStartComponents(numComponents); CHECK_STATUS(status); for (const DefComponentDscp & comp : defDscp.clsComps) { int orient = defOrient(comp.clsOrientation); status = defwComponent(comp.clsName.c_str(), comp.clsMacroName.c_str(), 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, comp.clsIsFixed ? "FIXED" : comp.clsIsPlaced ? "PLACED" : "UNPLACED", (int) comp.clsPos[X], (int) comp.clsPos[Y], orient, 0, NULL, 0, 0, 0, 0); CHECK_STATUS(status); } // end for status = defwEndComponents(); CHECK_STATUS(status); } // end if // write ports status = defwStartPins(defDscp.clsPorts.size()); CHECK_STATUS(status); for (const DefPortDscp & port : defDscp.clsPorts) { status = defwPin(port.clsName.c_str(), port.clsNetName.c_str(), (port.clsSpecial ? 1 : 0), // 0 ignores, 1 set net as special (port.clsDirection.compare(INVALID_DEF_NAME) == 0 ? NULL : port.clsDirection.c_str()), (port.clsUse.compare(INVALID_DEF_NAME) == 0 ? NULL : port.clsUse.c_str()), (port.clsLocationType.compare(INVALID_DEF_NAME) == 0 ? NULL : port.clsLocationType.c_str()), (int) port.clsPos[X], (int) port.clsPos[Y], defOrient(port.clsOrientation), (port.clsLayerName.compare(INVALID_DEF_NAME) == 0 ? NULL : port.clsLayerName.c_str()), (int) port.clsLayerBounds[LOWER][X], (int) port.clsLayerBounds[LOWER][Y], (int) port.clsLayerBounds[UPPER][X], (int) port.clsLayerBounds[UPPER][Y]); CHECK_STATUS(status); } // end for status = defwEndPins(); CHECK_STATUS(status); status = defwNewLine(); CHECK_STATUS(status); status = defwNewLine(); CHECK_STATUS(status); const unsigned numSpecialNets = defDscp.clsSpecialNets.size(); if (numSpecialNets > 0) { status = defwStartSpecialNets(numSpecialNets); CHECK_STATUS(status); // write special nets for (const DefNetDscp & defNet : defDscp.clsSpecialNets) { status = defwSpecialNet(defNet.clsName.c_str()); CHECK_STATUS(status); // Writing special net connections for (const DefNetConnection & defConn : defNet.clsConnections) { status = defwSpecialNetConnection(defConn.clsComponentName.c_str(), defConn.clsPinName.c_str(), 0); CHECK_STATUS(status); } // end for if (!defNet.clsWires.empty()) { bool routed = true; status = defwSpecialNetPathStart("ROUTED"); CHECK_STATUS(status); for (const DefWireDscp & wire : defNet.clsWires) { for (const DefWireSegmentDscp & segment : wire.clsWireSegments) { if (!routed) { status = defwSpecialNetPathStart("NEW"); CHECK_STATUS(status); } routed = false; bool hasVia = false; std::string viaName = ""; bool hasRect = false; Bounds rect; status = defwSpecialNetPathLayer(segment.clsLayerName.c_str()); CHECK_STATUS(status); status = defwSpecialNetPathWidth(segment.clsRoutedWidth); CHECK_STATUS(status); if (segment.clsHasShape) { status = defwSpecialNetPathShape(segment.clsShape.c_str()); CHECK_STATUS(status); } for (const DefRoutingPointDscp & pt : segment.clsRoutingPoints) { double posX = pt.clsPos[X]; double posY = pt.clsPos[Y]; if (pt.clsHasExtension) { double ext = pt.clsExtension; status = defwSpecialNetPathPointWithWireExt(1, &posX, &posY, &ext); CHECK_STATUS(status); } else { status = defwSpecialNetPathPoint(1, &posX, &posY); CHECK_STATUS(status); } // end if-else if (pt.clsHasVia) { hasVia = true; viaName = pt.clsViaName; } } // end for if (hasVia) { status = defwSpecialNetPathVia(viaName.c_str()); CHECK_STATUS(status); } } // end for } // end for status = defwSpecialNetPathEnd(); CHECK_STATUS(status); } // end if if (defNet.clsHasUse) { status = defwSpecialNetUse(defNet.clsUse.c_str()); CHECK_STATUS(status); } // end if status = defwNewLine(); CHECK_STATUS(status); status = defwSpecialNetEndOneNet(); CHECK_STATUS(status); } // end for status = defwEndSpecialNets(); CHECK_STATUS(status); } // end if const unsigned numNets = defDscp.clsNets.size(); if (numNets > 0) { status = defwStartNets(numNets); CHECK_STATUS(status); // write nets for (const DefNetDscp & defNet : defDscp.clsNets) { status = defwNet(defNet.clsName.c_str()); CHECK_STATUS(status); // Writing net connections for (const DefNetConnection & defConn : defNet.clsConnections) { status = defwNetConnection(defConn.clsComponentName.c_str(), defConn.clsPinName.c_str(), 0); CHECK_STATUS(status); } // end for if (!defNet.clsWires.empty()) { bool routed = true; status = defwNetPathStart("ROUTED"); CHECK_STATUS(status); for (const DefWireDscp & wire : defNet.clsWires) { for (const DefWireSegmentDscp & segment : wire.clsWireSegments) { if (!routed) { status = defwNetPathStart("NEW"); CHECK_STATUS(status); } routed = false; bool hasVia = false; std::string viaName = ""; bool hasRect = false; Bounds rect; status = defwNetPathLayer(segment.clsLayerName.c_str(), 0, NULL); CHECK_STATUS(status); for (const DefRoutingPointDscp & pt : segment.clsRoutingPoints) { double posX = pt.clsPos[X]; double posY = pt.clsPos[Y]; if (pt.clsHasExtension) { double ext = pt.clsExtension; status = defwNetPathPointWithExt(1, &posX, &posY, &ext); CHECK_STATUS(status); } else { status = defwNetPathPoint(1, &posX, &posY); CHECK_STATUS(status); } // end if-else if (pt.clsHasVia) { hasVia = true; viaName = pt.clsViaName; } if (pt.clsHasRectangle) { hasRect = true; rect = pt.clsRect; } } // end for if (hasVia) { status = defwNetPathViaWithOrient(viaName.c_str(), -1); CHECK_STATUS(status); } if (hasRect) { status = defwNetPathRect(rect[LOWER][X], rect[LOWER][Y], rect[UPPER][X], rect[UPPER][Y]); CHECK_STATUS(status); } } // end for } // end for status = defwNetPathEnd(); CHECK_STATUS(status); } // end if if (defNet.clsUse != INVALID_DEF_NAME) { status = defwNetUse(defNet.clsUse.c_str()); status = defwNetPathEnd(); CHECK_STATUS(status); } // end if status = defwNetEndOneNet(); CHECK_STATUS(status); } // end for status = defwEndNets(); CHECK_STATUS(status); } // end if status = defwEnd(); CHECK_STATUS(status); fclose(defFile); } // end method // ----------------------------------------------------------------------------- std::string DEFControlParser::unescape(const std::string &str) { std::string result; bool scapeNext = false; for (char ch : str) { if (scapeNext) { result += ch; scapeNext = false; } else if (ch == '\\') { scapeNext = true; } else { result += ch; scapeNext = false; } // end else } // end if return result; } // end method // ----------------------------------------------------------------------------- int defVia(defrCallbackType_e c, int num, void* ud) { std::cout << "Entered here!\n"; DefDscp & defDscp = getDesignFromUserData(ud); defDscp.clsVias.reserve(num); return 0; }// end method // ----------------------------------------------------------------------------- ================================================ FILE: rsyn/src/rsyn/io/parser/lef_def/DEFControlParser.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef DEFCONTROLPARSER_H #define DEFCONTROLPARSER_H #include using std::string; #include using std::cout; #include using std::vector; #include "rsyn/io/legacy/PlacerInternals.h" //! DEF files must be parsed after LEF files #include "rsyn/phy/util/DefDescriptors.h" class DEFControlParser { public: DEFControlParser(); void parseDEF(const std::string &filename, DefDscp &defDscp) ; void writeDEF(const std::string &filename, const std::string designName, const std::vector &components); void writeFullDEF(const std::string &filename, const DefDscp & defDscp); virtual ~DEFControlParser(); static std::string unescape(const std::string &str); }; // end class #endif /* DEFCONTROLPARSER_H */ ================================================ FILE: rsyn/src/rsyn/io/parser/lef_def/LEFControlParser.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "LEFControlParser.h" #ifndef WIN32 #include #else #include #endif /* not WIN32 */ #include #include #include #include #include #include "rsyn/util/DoubleRectangle.h" #include "rsyn/util/double2.h" //LEF headers #include "lef5.8/lefrReader.hpp" #include "lef5.8/lefwWriter.hpp" #include "lef5.8/lefiDebug.hpp" #include "lef5.8/lefiUtil.hpp" #define BOOST_POLYGON_NO_DEPS #include // ----------------------------------------------------------------------------- // ============================================================================= // LEF/DEF Common Function for parser // ============================================================================= //void freeCB(void* name); //void* mallocCB(size_t size); //void* reallocCB(void* name, int size); void* mallocCB(size_t size) { // DEF Parser version 5.8 return malloc(size); } void* mallocCB(int size) { // LEF Parser version 5.8 return malloc(size); } // ----------------------------------------------------------------------------- void* reallocCB(void* name, size_t size) { // DEF Parser version 5.8 return realloc(name, size); } void* reallocCB(void* name, int size) { // LEF Parser version 5.8 return realloc(name, size); } // ----------------------------------------------------------------------------- void freeCB(void* name) { free(name); return; } // ----------------------------------------------------------------------------- //LEF CALLBACKS void lefCheckType(lefrCallbackType_e c); int lefMacroBeginCB(lefrCallbackType_e c, const char* macroName, lefiUserData ud); int lefMacroEndCB(lefrCallbackType_e c, const char* macroName, lefiUserData ud); int lefMacroCB(lefrCallbackType_e c, lefiMacro* macro, lefiUserData ud); int lefPinCB(lefrCallbackType_e c, lefiPin* pin, lefiUserData ud); int lefSiteCB(lefrCallbackType_e c, lefiSite* site, lefiUserData ud); int lefUnits(lefrCallbackType_e c, lefiUnits* units, lefiUserData ud); int lefObstructionCB(lefrCallbackType_e c, lefiObstruction* obs, lefiUserData ud); int lefLayerCB(lefrCallbackType_e c, lefiLayer* layer, lefiUserData ud); int lefSpacingCB(lefrCallbackType_e c, lefiSpacing* spacing, lefiUserData ud); int lefViaCb(lefrCallbackType_e typ, lefiVia* via, lefiUserData data); int lefViaRuleCb(lefrCallbackType_e typ, lefiViaRule* via, lefiUserData data); LefDscp &getLibraryFromUserData(lefiUserData userData) { return *((LefDscp *) userData); } // end function // ============================================================================= // LEF Function Implementation // ============================================================================= void LEFControlParser::parseLEF(const std::string &filename, LefDscp & dscp) { // int retStr = 0; unused variable FILE* lefFile; int res; lefrInit(); lefrReset(); (void) lefrSetOpenLogFileAppend(); //(void) lefrSetShiftCase(); // will shift name to uppercase if caseinsensitive // is set to off or not set lefrSetMacroBeginCbk(lefMacroBeginCB); lefrSetMacroEndCbk(lefMacroEndCB); lefrSetMacroCbk(lefMacroCB); lefrSetPinCbk(lefPinCB); lefrSetSiteCbk(lefSiteCB); lefrSetUnitsCbk(lefUnits); lefrSetUserData((void*) 3); lefrSetMallocFunction(mallocCB); lefrSetReallocFunction(reallocCB); lefrSetFreeFunction(freeCB); lefrSetObstructionCbk(lefObstructionCB); lefrSetLayerCbk(lefLayerCB); lefrSetSpacingCbk(lefSpacingCB); lefrSetViaCbk(lefViaCb); lefrSetViaRuleCbk(lefViaRuleCb); lefrSetRegisterUnusedCallbacks(); // Open the lef file for the reader to read if ((lefFile = fopen(filename.c_str(), "r")) == 0) { printf("Couldn’t open input file ’%s’\n", filename.c_str()); exit(1); } // Invoke the parser res = lefrRead(lefFile, filename.c_str(), (void*) &dscp); if (res != 0) { printf("LEF parser returns an error. #: %d \n", res); return; } //(void) lefrPrintUnusedCallbacks(fout); (void) lefrReleaseNResetMemory(); fclose(lefFile); } // end method // ----------------------------------------------------------------------------- void lefCheckType(lefrCallbackType_e c) { if (c >= 0 && c <= lefrLibraryEndCbkType) { // OK } else { printf("ERROR: callback type is out of bounds!\n"); } } // end call back // ----------------------------------------------------------------------------- int lefMacroBeginCB(lefrCallbackType_e c, const char* macroName, lefiUserData ud) { LefDscp & dscp = getLibraryFromUserData(ud); dscp.clsLefMacroDscps.resize(dscp.clsLefMacroDscps.size() + 1); return 0; } // end function // ----------------------------------------------------------------------------- int lefMacroEndCB(lefrCallbackType_e c, const char* macroName, lefiUserData ud) { return 0; } // end function // ----------------------------------------------------------------------------- int lefMacroCB(lefrCallbackType_e c, lefiMacro* macro, lefiUserData ud) { LefDscp & dscp = getLibraryFromUserData(ud); LefMacroDscp & lefMacro = dscp.clsLefMacroDscps.back(); lefMacro.clsMacro->setClass(macro->macroClass()); lefMacro.clsMacro->setName(macro->name()); if (macro->hasOrigin()) { lefMacro.clsMacro->setOrigin(macro->originX(), macro->originY()); } lefMacro.clsMacro->setSize(macro->sizeX(), macro->sizeY()); if (macro->hasXSymmetry()) { lefMacro.clsMacro->setXSymmetry(); } // end if if (macro->hasYSymmetry()) { lefMacro.clsMacro->setYSymmetry(); } // end if if (macro->has90Symmetry()) { lefMacro.clsMacro->set90Symmetry(); } // end if return 0; } // end function // ----------------------------------------------------------------------------- int numWarningsInoutPins = 0; int numWarningsTristatePins = 0; int lefPinCB(lefrCallbackType_e c, lefiPin* pin, lefiUserData ud) { typedef boost::polygon::polygon_90_with_holes_data Polygon90; typedef boost::polygon::polygon_traits::point_type BoostPoint; // Skip power and ground pins... //if (strcmp(pin->use(), "GROUND") == 0) return 0; //if (strcmp(pin->use(), "POWER") == 0) return 0; LefDscp & dscp = getLibraryFromUserData(ud); LefMacroDscp & lefMacro = dscp.clsLefMacroDscps.back(); lefMacro.clsPins.resize(lefMacro.clsPins.size() + 1); LefPinDscp & lefPin = lefMacro.clsPins.back(); lefPin.clsPinName = pin->name(); lefPin.clsPinDirection = pin->direction(); lefPin.clsPinUse = pin->use(); // WORKORUND to support inout data pin if (lefPin.clsPinDirection.compare("INOUT") == 0) { lefPin.clsPinDirection = "OUTPUT"; // if (numWarningsInoutPins < 10) // std::cout << "WARNING: Unsupported INOUT direction in data pin. " // << lefPin.clsPinName << ". Pin direction is replaced to " << lefPin.clsPinDirection // << " [LEF CONTROL PARSER]\n"; numWarningsInoutPins++; } // end if // END WORKORUND to support inout data pin // Mateus @ 190108 -- WORKORUND to support tristate pin if (lefPin.clsPinDirection.compare("OUTPUT TRISTATE") == 0) { lefPin.clsPinDirection = "OUTPUT"; if (numWarningsTristatePins < 10) std::cout << "WARNING: Ignoring TRISTATE OUTPUT statement in pin " << lefPin.clsPinName << ". Pin direction is replaced to " << lefPin.clsPinDirection << " [LEF CONTROL PARSER]\n"; numWarningsTristatePins++; } // end if // END WORKORUND to support tristate data pin lefPin.clsHasPort = pin->numPorts() > 0; if (lefPin.clsHasPort) lefPin.clsPorts.reserve(pin->numPorts()); for (int j = 0; j < pin->numPorts(); j++) { const lefiGeometries* geometry = pin->port(j); lefPin.clsPorts.push_back(LefPortDscp()); LefPortDscp & lefPort = lefPin.clsPorts.back(); int numGeo = geometry->numItems(); lefPort.clsLefPortGeoDscp.reserve(numGeo); LefPortGeometryDscp * geoDscp = nullptr; for (int i = 0; i < numGeo; i++) { lefiGeomEnum geoType = geometry->itemType(i); lefiGeomRect* rect; DoubleRectangle * bound; lefiGeomPolygon * poly; LefPolygonDscp * polyDscp; double2 * point; std::vector< boost::polygon::rectangle_data > rects; Polygon90 polygon90; std::vector pts; switch (geoType) { case lefiGeomLayerE: lefPort.clsLefPortGeoDscp.push_back(LefPortGeometryDscp()); geoDscp = &lefPort.clsLefPortGeoDscp.back(); geoDscp->clsMetalName = geometry->lefiGeometries::getLayer(i); break; case lefiGeomRectE: rect = geometry->getRect(i); geoDscp->clsBounds.resize(geoDscp->clsBounds.size() + 1); bound = &geoDscp->clsBounds.back(); bound->updatePoints(rect->xl, rect->yl, rect->xh, rect->yh); break; case lefiGeomPolygonE: // Mateus @ 2018/09/13: // Support for polygon-shapped pins poly = geometry->getPolygon(i); for (int k = 0; k < poly->numPoints; k++) { pts.push_back(boost::polygon::construct(poly->x[k], poly->y[k])); } // end for boost::polygon::set_points(polygon90, pts.begin(), pts.end()); boost::polygon::get_rectangles(rects, polygon90); for (int k = 0; k < rects.size(); k++) { double xl = rects[k].get(boost::polygon::HORIZONTAL).low(); double xh = rects[k].get(boost::polygon::HORIZONTAL).high(); double yl = rects[k].get(boost::polygon::VERTICAL).low(); double yh = rects[k].get(boost::polygon::VERTICAL).high(); ; geoDscp->clsBounds.resize(geoDscp->clsBounds.size() + 1); bound = &geoDscp->clsBounds.back(); bound->updatePoints(xl, yl, xh, yh); } // end for // end Mateus @ 2018/09/13 break; default: std::cout << "WARNING: function " << __func__ << " does not supports pin geometry type in the LEF Parser Control.\n"; break; } // end switch } // end for } // end for return 0; } // end function // ----------------------------------------------------------------------------- int lefSiteCB(lefrCallbackType_e c, lefiSite* site, lefiUserData ud) { LefDscp & dscp = getLibraryFromUserData(ud); dscp.clsLefSiteDscps.resize(dscp.clsLefSiteDscps.size() + 1); LefSiteDscp &lefSite = dscp.clsLefSiteDscps.back(); lefSite.clsName = site->name(); lefSite.clsHasClass = site->hasClass(); if (site->hasClass()) { lefSite.clsSiteClass = site->siteClass(); } // end if lefSite.clsSize[X] = site->sizeX(); lefSite.clsSize[Y] = site->sizeY(); lefSite.clsSymmetry.clear(); if (site->hasXSymmetry()) { lefSite.clsSymmetry.append("X"); } // end if if (site->hasYSymmetry()) { lefSite.clsSymmetry.append(" Y"); } // end if if (site->has90Symmetry()) { lefSite.clsSymmetry.append(" R90"); } // end if if (lefSite.clsSymmetry.empty()) { lefSite.clsSymmetry = INVALID_LEF_NAME; } // end if return 0; } // end function // ----------------------------------------------------------------------------- int lefUnits(lefrCallbackType_e c, lefiUnits* units, lefiUserData ud) { LefDscp & dscp = getLibraryFromUserData(ud); LefUnitsDscp & lefUnits = dscp.clsLefUnitsDscp; if (units->hasDatabase()) { lefUnits.clsDatabase = (int) units->databaseNumber(); lefUnits.clsHasDatabase = true; } return 0; } // end function // ----------------------------------------------------------------------------- int lefObstructionCB(lefrCallbackType_e c, lefiObstruction* obs, lefiUserData ud) { //std::cout << "Reading lef obstacles\n"; LefDscp & dscp = getLibraryFromUserData(ud); LefMacroDscp & lefMacro = dscp.clsLefMacroDscps.back(); lefiGeometries *geometry; lefiGeomRect *rect; geometry = obs->lefiObstruction::geometries(); const int numItems = geometry->lefiGeometries::numItems(); for (int i = 0; i < numItems; i++) { if (geometry->lefiGeometries::itemType(i) == lefiGeomLayerE) { lefMacro.clsObs.resize(lefMacro.clsObs.size() + 1); LefObsDscp & lefObs = lefMacro.clsObs.back(); lefObs.clsMetalLayer = geometry->getLayer(i); } else if (geometry->lefiGeometries::itemType(i) == lefiGeomRectE) { LefObsDscp & lefObs = lefMacro.clsObs.back(); rect = geometry->lefiGeometries::getRect(i); DoubleRectangle libRect = DoubleRectangle(rect->xl, rect->yl, rect->xh, rect->yh); lefObs.clsBounds.push_back(libRect); } // end if-else } // end for // if (lefMacro.clsMacroName == "bufx2" || lefMacro.clsMacroName == "BUFX2") { // std::cout << "#Obstacles" << lefMacro.clsObs.size() << "\n"; // } return 0; } // end method // ----------------------------------------------------------------------------- int lefLayerCB(lefrCallbackType_e c, lefiLayer* layer, lefiUserData ud) { LefDscp & dscp = getLibraryFromUserData(ud); lefiLayer* lefLayer = new lefiLayer(); dscp.clsLefLayer.push_back(lefLayer); lefLayer->setName(layer->name()); if (layer->lefiLayer::hasType()) { lefLayer->setType(layer->type()); } if (layer->lefiLayer::hasPitch()) { lefLayer->setPitch(layer->pitch()); } if (layer->lefiLayer::hasXYPitch()) { lefLayer->setPitchXY(layer->pitchX(), layer->pitchY()); } if (layer->lefiLayer::hasWidth()) { lefLayer->setWidth(layer->width()); } if (layer->lefiLayer::hasMinwidth()) { lefLayer->setMinwidth(layer->minwidth()); } if (layer->lefiLayer::hasDirection()) { lefLayer->setDirection(layer->direction()); } if (layer->lefiLayer::hasSpacingNumber()) { int numSpacing = layer->lefiLayer::numSpacing(); for (int i = 0; i < numSpacing; ++i) { lefLayer->setSpacingMin(layer->spacing(i)); if (layer->hasSpacingEndOfLine(i)) { lefLayer->setSpacingEol(layer->spacingEolWidth(i), layer->spacingEolWithin(i)); } if (layer->hasSpacingParellelEdge(i)) { lefLayer->setSpacingParSW(layer->spacingParSpace(i), layer->spacingParWithin(i)); } } // end for } // end if for (int i = 0; i < layer->lefiLayer::numSpacingTable(); ++i) { lefLayer->addSpacingTable(); if (layer->lefiLayer::spacingTable(i)->isParallel()) { lefiParallel* parallel = layer->lefiLayer::spacingTable(i)->parallel(); int numLength = parallel->numLength(); int numWidth = parallel->numWidth(); if (numLength > 0) { for (int iLength = 0; iLength < numLength; ++iLength) { lefLayer->addNumber(parallel->length(iLength)); } lefLayer->addSpParallelLength(); } if (numWidth > 0) { for (int iWidth = 0; iWidth < numWidth; ++iWidth) { lefLayer->addSpParallelWidth(parallel->width(iWidth)); for (int iLength = 0; iLength < numLength; ++iLength) { lefLayer->addNumber(parallel->widthSpacing(iWidth, iLength)); } lefLayer->addSpParallelWidthSpacing(); } } } } if (layer->lefiLayer::hasArea()) { lefLayer->setArea(layer->area()); } for (unsigned i = 0; static_cast(i) < layer->lefiLayer::numProps(); ++i) { if (layer->lefiLayer::propIsNumber(i)) { lefLayer->addNumProp(layer->lefiLayer::propName(i), layer->lefiLayer::propNumber(i), layer->lefiLayer::propValue(i), layer->lefiLayer::propType(i)); } else if (layer->lefiLayer::propIsString(i)) { lefLayer->addProp(layer->lefiLayer::propName(i), layer->lefiLayer::propValue(i), layer->lefiLayer::propType(i)); } else { printf("ERROR: LEF layer prop %u is neither number nor string!\n", i); } } return 0; } // end method // ----------------------------------------------------------------------------- int lefSpacingCB(lefrCallbackType_e c, lefiSpacing* spacing, lefiUserData ud) { LefDscp & dscp = getLibraryFromUserData(ud); dscp.clsLefSpacingDscps.resize(dscp.clsLefSpacingDscps.size() + 1); LefSpacingDscp & lefSpacing = dscp.clsLefSpacingDscps.back(); lefSpacing.clsLayer1 = spacing->lefiSpacing::name1(); lefSpacing.clsLayer2 = spacing->lefiSpacing::name2(); lefSpacing.clsDistance = spacing->lefiSpacing::distance(); return 0; } // end method // ----------------------------------------------------------------------------- int lefViaCb(lefrCallbackType_e typ, lefiVia* via, lefiUserData data) { LefDscp & dscp = getLibraryFromUserData(data); dscp.clsLefViaDscps.resize(dscp.clsLefViaDscps.size() + 1); LefViaDscp & viaDscp = dscp.clsLefViaDscps.back(); viaDscp.clsIsDefault = via->hasDefault(); viaDscp.clsName = via->name(); viaDscp.clsHasViaRule = via->hasViaRule(); if (viaDscp.clsHasViaRule) { viaDscp.clsViaRuleName = via->viaRuleName(); viaDscp.clsXCutSize = via->xCutSize(); viaDscp.clsYCutSize = via->yCutSize(); viaDscp.clsXCutSpacing = via->xCutSpacing(); viaDscp.clsYCutSpacing = via->yCutSpacing(); viaDscp.clsXBottomEnclosure = via->xBotEnc(); viaDscp.clsYBottomEnclosure = via->yBotEnc(); viaDscp.clsXTopEnclosure = via->xTopEnc(); viaDscp.clsYTopEnclosure = via->yTopEnc(); viaDscp.clsBottomLayer = via->botMetalLayer(); viaDscp.clsCutLayer = via->cutLayer(); viaDscp.clsTopLayer = via->topMetalLayer(); if (via->hasOrigin()) { viaDscp.clsHasOrigin = true; viaDscp.clsXOrigin = via->xOffset(); viaDscp.clsYOrigin = via->yOffset(); } // end if if (via->hasOffset()) { viaDscp.clsHasOffset = true; viaDscp.clsXBottomOffset = via->xBotOffset(); viaDscp.clsYBottomOffset = via->yBotOffset(); viaDscp.clsXTopOffset = via->xTopOffset(); viaDscp.clsYTopOffset = via->yTopOffset(); } // end if if (via->hasRowCol()) { viaDscp.clsHasRowCol = true; viaDscp.clsNumCutRows = via->numCutRows(); viaDscp.clsNumCutCols = via->numCutCols(); } // end if } else { if(via->hasResistance()) { viaDscp.clsHasResistance = true; viaDscp.clsCutResistance = via->resistance(); } // end if for (int i = 0; i < via->numLayers(); ++i) { std::string layerName = via->layerName(i); std::deque & geoDscps = viaDscp.clsGeometries[layerName]; for (int j = 0; j < via->numRects(i); ++j) { geoDscps.push_back(LefViaGeometryDscp()); LefViaGeometryDscp & geoDscp = geoDscps.back(); DoubleRectangle & bounds = geoDscp.clsBounds; bounds[LOWER][X] = via->xl(i, j); bounds[LOWER][Y] = via->yl(i, j); bounds[UPPER][X] = via->xh(i, j); bounds[UPPER][Y] = via->yh(i, j); } // end for } // end for } // end if-else return 0; } // end method // ----------------------------------------------------------------------------- int lefViaRuleCb(lefrCallbackType_e typ, lefiViaRule* via, lefiUserData data) { LefDscp & dscp = getLibraryFromUserData(data); dscp.clsLefViaRuleDscps.push_back(LefViaRuleDscp()); LefViaRuleDscp & viaDscp = dscp.clsLefViaRuleDscps.back(); viaDscp.clsName = via->name(); viaDscp.clsIsDefault = via->hasDefault(); viaDscp.clsIsGenerate = via->hasGenerate(); std::vector & layers = viaDscp.clsLayers; layers.resize(via->numLayers()); for (int i = 0; i < via->numLayers(); i++) { LefViaRuleLayerDscp & layer = layers[i]; lefiViaRuleLayer * viaLayer = via->layer(i); layer.clsName = viaLayer->name(); if (viaLayer->hasDirection()) { layer.clsHasDirection = true; layer.clsIsHorizontal = viaLayer->isHorizontal(); layer.clsIsVertical = viaLayer->isVertical(); } // end if if (viaLayer->hasEnclosure()) { layer.clsHasEnclosure = true; layer.clsEnclosure1 = viaLayer->enclosureOverhang1(); layer.clsEnclosure2 = viaLayer->enclosureOverhang2(); } // end if if (viaLayer->hasRect()) { layer.clsHasRect = true; DoubleRectangle & bounds = layer.clsRect; bounds[LOWER][X] = viaLayer->xl(); bounds[LOWER][Y] = viaLayer->yl(); bounds[UPPER][X] = viaLayer->xh(); bounds[UPPER][Y] = viaLayer->yh(); } // end if if (viaLayer->hasResistance()) { layer.clsHasResistance = true; layer.clsCutResistance = viaLayer->resistance(); } // end if if (viaLayer->hasWidth()) { layer.clsHasWidth = true; layer.clsMinWidth = viaLayer->widthMin(); layer.clsMaxWidth = viaLayer->widthMax(); } // end if if (viaLayer->hasSpacing()) { layer.clsHasSpacing = true; layer.clsXSpacing = viaLayer->spacingStepX(); layer.clsYSpacing = viaLayer->spacingStepY(); } // end if } // end for std::vector & vias = viaDscp.clsVias; vias.reserve(via->numVias()); for (int i = 0; i < via->numVias(); ++i) { vias.push_back(via->viaName(i)); } // end for return 0; } // end method // ----------------------------------------------------------------------------- ================================================ FILE: rsyn/src/rsyn/io/parser/lef_def/LEFControlParser.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LEFCONTROLPARSER_H #define LEFCONTROLPARSER_H #include #include "rsyn/phy/util/LefDescriptors.h" //! LEF file must be parsed first than DEF file class LEFControlParser { public: LEFControlParser() { } virtual ~LEFControlParser() = default; void parseLEF(const std::string &filename, LefDscp & dscp); }; // end class #endif /* LEFCONTROLPARSER_H */ ================================================ FILE: rsyn/src/rsyn/io/parser/parser_helper.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ ////////////////////////////////////////////////////////////////// // // // Helper functions and classes to parse the ISPD 2013 contest // benchmark files. // // This code is provided for description purposes only. The contest // organizers cannot guarantee that the provided code is free of // bugs or defects. !!!! USE THIS CODE AT YOUR OWN RISK !!!!! // // // The contestants are free to use these functions as-is or make // modifications. If the contestants choose to use the provided // code, they are responsible for making sure that it works as // expected. // // The code provided here has no real or implied warranties. // // //////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include "rsyn/io/parser/parser_helper.h" namespace ISPD13 { bool is_special_char (char c) { static const char specialChars[] = {'(', ')', ',', ';', '/', '#', '[', ']', '{', '}', '*', '\"', '\\'} ; for (unsigned i=0; i < sizeof(specialChars); ++i) { if (c == specialChars[i]) return true ; } return false ; } // Read the next line and return it as a list of tokens skipping white space and special characters // The return value indicates success/failure. bool read_line_as_tokens (istream& is, vector& tokens, bool includeSpecialChars = false) { tokens.clear() ; string line ; std::getline (is, line) ; while (is && tokens.empty()) { string token = "" ; for (unsigned i=0; i < line.size(); ++i) { char currChar = line[i] ; bool isSpecialChar = is_special_char(currChar) ; if (std::isspace (currChar) || isSpecialChar) { if (!token.empty()) { // Add the current token to the list of tokens tokens.push_back(token) ; token.clear() ; } if (includeSpecialChars && isSpecialChar) { tokens.push_back(string(1, currChar)) ; } } else { // Add the char to the current token token.push_back(currChar) ; } } if (!token.empty()) tokens.push_back(token) ; if (tokens.empty()) // Previous line read was empty. Read the next one. std::getline (is, line) ; } //for (int i=0; i < tokens.size(); ++i) // cout << tokens[i] << " " ; //cout << endl ; return !tokens.empty() ; } bool VerilogParser::read_module (string& moduleName) { vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; while (valid) { if (tokens.size() == 2 && tokens[0] == "module") { moduleName = tokens[1] ; break ; } valid = read_line_as_tokens (is, tokens) ; } // Read and skip the port names in the module definition // until we encounter the tokens {"Start", "PIs"} while (valid && !(tokens.size() == 2 && tokens[0] == "Start" && tokens[1] == "PIs")) { valid = read_line_as_tokens (is, tokens) ; assert (valid) ; } return valid ; } bool VerilogParser::read_primary_input (string& primaryInput) { primaryInput = "" ; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() == 2) ; if (valid && tokens[0] == "input") { primaryInput = tokens[1] ; } else { assert (tokens[0] == "Start" && tokens[1] == "POs") ; return false ; } return valid ; } bool VerilogParser::read_primary_output (string& primaryOutput) { primaryOutput = "" ; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() == 2) ; if (valid && tokens[0] == "output") { primaryOutput = tokens[1] ; } else { assert (tokens[0] == "Start" && tokens[1] == "wires") ; return false ; } return valid ; } bool VerilogParser::read_wire (string& wire) { wire = "" ; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() == 2) ; if (valid && tokens[0] == "wire") { wire = tokens[1] ; } else { assert (tokens[0] == "Start" && tokens[1] == "cells") ; return false ; } return valid ; } bool VerilogParser::read_cell_inst (string& cellType, string& cellInstName, vector >& pinNetPairs) { cellType = "" ; cellInstName = "" ; pinNetPairs.clear() ; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; if (tokens.size() == 1) { assert (tokens[0] == "endmodule") ; return false ; } assert (tokens.size() >= 4) ; // We should have cellType, instName, and at least one pin-net pair cellType = tokens[0] ; cellInstName = tokens[1] ; for (unsigned i=2; i < tokens.size()-1; i += 2) { assert (tokens[i][0] == '.') ; // pin names start with '.' string pinName = tokens[i].substr(1) ; // skip the first character of tokens[i] pinNetPairs.push_back(std::make_pair(pinName, tokens[i+1])) ; } return valid ; } bool VerilogParser::read_module_tau15 (string& moduleName) { vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; while (valid) { if (tokens.size() == 2 && tokens[0] == "module") { moduleName = tokens[1] ; break ; } valid = read_line_as_tokens (is, tokens) ; } // Read and skip the port names in the module definition // until we encounter the tokens {"Start", "PIs"} while (valid && !count(tokens.begin(), tokens.end(), ";") == 1) { valid = read_line_as_tokens (is, tokens, true) ; assert (valid) ; } return valid ; } bool VerilogParser::read_module_ispd15 (string& moduleName) { vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; while (valid) { if (tokens[0] == "module") { moduleName = tokens[1] ; break ; } valid = read_line_as_tokens (is, tokens) ; } // Read and skip the port names in the module definition // until we encounter the tokens {"Start", "PIs"} while (valid && !count(tokens.begin(), tokens.end(), ";") == 1) { valid = read_line_as_tokens (is, tokens, true) ; assert (valid) ; } return valid ; } tauVerilog VerilogParser::read_line_tau15(string &aux){ bool valid; do{ valid = read_line_as_tokens (is, tauTokens) ; if(tauTokens[0] == "input"){ aux = tauTokens[1] ; return INPUT_TAU15; } else if (tauTokens [0] == "output"){ aux = tauTokens[1] ; return OUTPUT_TAU15; } else if (tauTokens [0] == "Start") { valid = false; } else if (tauTokens [0] == "wire"){ aux = tauTokens[1] ; return WIRE_TAU15; } else if(tauTokens [0] == "endmodule"){ return ENDMOD_TAU15; } else{ return GATE_TAU15; } }while(!valid); throw std::runtime_error("parsing error"); } bool VerilogParser::read_cell_inst_tau15 (string& cellType, string& cellInstName, vector >& pinNetPairs) { cellType = "" ; cellInstName = "" ; pinNetPairs.clear() ; assert (tauTokens.size() >= 4) ; // We should have cellType, instName, and at least one pin-net pair cellType = tauTokens[0] ; cellInstName = tauTokens[1] ; for (unsigned i=2; i < tauTokens.size()-1; i += 2) { assert (tauTokens[i][0] == '.') ; // pin names start with '.' string pinName = tauTokens[i].substr(1) ; // skip the first character of tokens[i] pinNetPairs.push_back(std::make_pair(pinName, tauTokens[i+1])) ; } return true ; } // Read clock definition // Return value indicates if the last read was successful or not. bool SdcParser::read_clock (string& clockName, string& clockPort, double& period) { clockName = "" ; clockPort = "" ; period = 0.0 ; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; while (valid) { if (tokens.size() == 7 && tokens[0] == "create_clock" && tokens[1] == "-name") { clockName = tokens[2] ; assert (tokens[3] == "-period") ; period = std::atof(tokens[4].c_str()) ; assert (tokens[5] == "get_ports") ; clockPort = tokens[6] ; break ; } valid = read_line_as_tokens (is, tokens) ; } // Skip the next comment line to prepare for the next stage bool valid2 = read_line_as_tokens (is, tokens) ; assert (valid2) ; assert (tokens.size() == 2) ; assert (tokens[0] == "input" && tokens[1] == "delays") ; return valid ; } // Read input delay // Return value indicates if the last read was successful or not. bool SdcParser::read_input_delay (string& portName, double& delay) { portName = "" ; delay = 0.0 ; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() >= 2) ; if (valid && tokens[0] == "set_input_delay") { // Workaround.. a better parser must be implemented later //assert (tokens.size() == 6) ; delay = std::atof(tokens[1].c_str()) ; assert (tokens[2] == "get_ports") ; portName = tokens[3]; if( tokens.size() > 6 ) portName += "[" + tokens[4] + "]"; // Workaround.. a better parser must be implemented later //assert (tokens[4] == "-clock") ; } else { assert (tokens.size() == 2) ; assert (tokens[0] == "input" && tokens[1] == "drivers") ; return false ; } return valid ; } // Read output delay // Return value indicates if the last read was successful or not. bool SdcParser::read_output_delay (string& portName, double& delay) { portName = "" ; delay = 0.0 ; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() >= 2) ; if (valid && tokens[0] == "set_output_delay") { // Workaround.. a better parser must be implemented later //assert (tokens.size() == 6) ; delay = std::atof(tokens[1].c_str()) ; assert (tokens[2] == "get_ports") ; portName = tokens[3]; if( tokens.size() > 6 ) portName += "[" + tokens[4] + "]"; // Workaround.. a better parser must be implemented later //assert (tokens[4] == "-clock") ; } else { assert (tokens.size() == 2) ; assert (tokens[0] == "output" && tokens[1] == "loads") ; return false ; } return valid ; } // Read driver info for the input port // Return value indicates if the last read was successful or not. bool SdcParser::read_driver_info (string& inPortName, string& driverSize, string& driverPin, double& inputTransitionFall, double& inputTransitionRise) { inPortName = "" ; driverSize = "" ; driverPin = "" ; inputTransitionFall = 0.0 ; inputTransitionRise = 0.0 ; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() >= 2) ; if (valid && tokens[0] == "set_driving_cell") { // Workaround, a better parser must be implemented in the future assert( tokens.size() == 11 || tokens.size() == 12 ); if(tokens.size() == 11) { assert (tokens[1] == "-lib_cell") ; driverSize = tokens[2] ; assert (tokens[3] == "-pin") ; driverPin = tokens[4] ; assert (tokens[5] == "get_ports") ; inPortName = tokens[6] ; assert (tokens[7] == "-input_transition_fall") ; inputTransitionFall = std::atof(tokens[8].c_str()) ; assert (tokens[9] == "-input_transition_rise") ; inputTransitionRise = std::atof(tokens[10].c_str()) ; } else if(tokens.size() != 11) { assert (tokens[1] == "-lib_cell") ; driverSize = tokens[2] ; assert (tokens[3] == "-pin") ; driverPin = tokens[4] ; assert (tokens[5] == "get_ports") ; inPortName = tokens[6] + "[" + tokens[7] + "]"; assert (tokens[8] == "-input_transition_fall") ; inputTransitionFall = std::atof(tokens[9].c_str()) ; assert (tokens[10] == "-input_transition_rise") ; inputTransitionRise = std::atof(tokens[11].c_str()) ; } } else { assert (tokens.size() == 2) ; assert (tokens[0] == "output" && tokens[1] == "delays") ; return false ; } return valid ; } // Read output load // Return value indicates if the last read was successful or not. bool SdcParser::read_output_load (string& outPortName, double& load) { outPortName = "" ; load = 0.0 ; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; if (valid && tokens[0] == "set_load") { // Workaround, a better parser must be implemented in the future //assert (tokens.size() == 5) ; assert (tokens[1] == "-pin_load") ; load = std::atof(tokens[2].c_str()) ; assert (tokens[3] == "get_ports") ; outPortName = tokens[4] ; if( tokens.size() > 5 ) outPortName += "[" + tokens[5] + "]"; } else { assert (!valid) ; return false ; } return valid ; } // The return value indicates whether the *CONN section has been read or not bool SpefParser::read_connections (vector& connections) { connections.clear() ; // in case the input is not empty bool terminateEarly = false ; vector tokens ; bool valid = read_line_as_tokens (is, tokens, true /*include special chars*/) ; // Skip the lines that are not "*CONN" while (valid && !(tokens.size() == 2 && tokens[0] == "*" && tokens[1] == "CONN")) { // The following if condition checks for nets without any connections // This is needed for clock nets. if (tokens.size() == 2 && tokens[0] == "*" && tokens[1] == "END") { terminateEarly = true ; break ; } valid = read_line_as_tokens (is, tokens, true /*include special chars*/) ; } assert (valid) ; // end of file not expected here if (terminateEarly) return false ; while (valid) { valid = read_line_as_tokens (is, tokens, true /*include special chars*/) ; if (tokens.size() == 2 && tokens[0] == "*" && tokens[1] == "CAP") break ; // the beginning of the next section if (tokens.size() == 2 && tokens[0] == "*" && tokens[1] == "END") return false ; // spef file for iccad 2015 contest //for(auto str: tokens) // cout<& capacitances) { capacitances.clear() ; // in case the input is not empty vector tokens ; bool valid = true ; while (valid) { valid = read_line_as_tokens (is, tokens, true /*include special chars*/) ; if (tokens.size() == 2 && tokens[0] == "*" && tokens[1] == "RES") break ; // the beginning of the next section // Line format: "index nodeName cap" // Note that nodeName can be either a single token or 3 tokens assert (tokens.size() == 3 || tokens.size() == 5) ; SpefCapacitance curr ; int tokenIndex = 1 ; curr.nodeName.n1 = tokens[tokenIndex++] ; if (tokens[tokenIndex] == ":") { ++tokenIndex ; // skip the current token curr.nodeName.n2 = tokens[tokenIndex++] ; } curr.capacitance = std::atof(tokens[tokenIndex++].c_str()) ; assert (curr.capacitance >= 0) ; capacitances.push_back(curr) ; } } void SpefParser::read_resistances (vector& resistances) { resistances.clear() ; // in case the input is not empty vector tokens ; bool valid = true ; while (valid) { valid = read_line_as_tokens (is, tokens, true /*include special chars*/) ; if (tokens.size() == 2 && tokens[0] == "*" && tokens[1] == "END") break ; // end for this net // Line format: "index fromNodeName toNodeName res" // Note that each nodeName can be either a single token or 3 tokens assert (tokens.size() >= 4 && tokens.size() <= 8) ; SpefResistance curr ; int tokenIndex = 1 ; curr.fromNodeName.n1 = tokens[tokenIndex++] ; if (tokens[tokenIndex] == ":") { ++tokenIndex ; // skip the current token curr.fromNodeName.n2 = tokens[tokenIndex++] ; } curr.toNodeName.n1 = tokens[tokenIndex++] ; if (tokens[tokenIndex] == ":") { ++tokenIndex ; // skip the current token curr.toNodeName.n2 = tokens[tokenIndex++] ; } curr.resistance = std::atof(tokens[tokenIndex++].c_str()) ; assert (curr.resistance >= 0) ; resistances.push_back(curr) ; } } // Read the spef data for the next net. // Return value indicates if the last read was successful or not. bool SpefParser::read_net_data (SpefNet& spefNet) { spefNet.clear() ; vector tokens ; bool valid = read_line_as_tokens (is, tokens, true /*include special chars*/) ; // Read until a valid D_NET line is found while (valid) { if (tokens.size() == 4 && tokens[0] == "*" && tokens[1] == "D_NET") { spefNet.netName = tokens[2] ; spefNet.netLumpedCap = std::atof(tokens[3].c_str()) ; bool readConns = read_connections (spefNet.connections) ; if (readConns) { read_capacitances (spefNet.capacitances) ; read_resistances (spefNet.resistances) ; } return true ; } else { if ( tokens[0] == "*" && tokens[1] == "D_NET" ) cout << "[BUG] @ SpefParser::read_net_data: possibly wrong-named net starting with '" << tokens[2] << "'\n"; } // end else valid = read_line_as_tokens (is, tokens, true /*include special chars*/) ; } return false ; // a valid net was not read } // Read timing info for the next pin or port // Return value indicates if the last read was successful or not. // If the line read corresponds to a pin, then name1 and name2 will be set to the cell // instance name and the pin name, respectively. // If the line read corresponds to a port, then name1 will be set to the port name, and // name2 will be set to "". bool TimingParser::read_timing_line (string& name1, string& name2, double& riseSlack, double& fallSlack, double& riseTransition, double& fallTransition, double& riseArrival, double& fallArrival) { vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; if (!valid) return false ; assert (tokens.size() >= 7) ; int tokenIndex = 0 ; name1 = tokens[tokenIndex++] ; name2 = "" ; if (tokens.size() == 8) { // line corresponds to a cell pin name2 = tokens[tokenIndex++] ; } riseSlack = std::atof(tokens[tokenIndex++].c_str()) ; fallSlack = std::atof(tokens[tokenIndex++].c_str()) ; riseTransition = std::atof(tokens[tokenIndex++].c_str()) ; fallTransition = std::atof(tokens[tokenIndex++].c_str()) ; riseArrival = std::atof(tokens[tokenIndex++].c_str()) ; fallArrival = std::atof(tokens[tokenIndex++].c_str()) ; return true ; } bool TimingParser::read_timing_tau15 ( string & str1, string &str2, double &val1, double &val2, double &val3, double &val4){ str1 = ""; str2 = ""; val1 = 0; val2 = 0; val3 = 0; val4 = 0; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; int tokenSize = tokens.size(); if (!valid) return false ; int tokenIndex = 0 ; str1 = tokens[tokenIndex++] ; str2 = tokens[tokenIndex++] ; val1 = std::atof(tokens[tokenIndex++].c_str()) ; if(tokenIndex < tokenSize) val2 = std::atof(tokens[tokenIndex++].c_str()) ; if(tokenIndex < tokenSize) val3 = std::atof(tokens[tokenIndex++].c_str()) ; if(tokenIndex < tokenSize) val4 = std::atof(tokens[tokenIndex++].c_str()) ; return true; } bool OperationsParser::read_ops_tau15 ( ISPD13::CommandTypeEnum &cmdType, ISPD13::QueryTypeEnum &queryType, string &pin, string &net, string &file, string &gate, string &cell, bool &early, bool &rise, int &paths ){ pin = net = file = gate = cell = ""; early = rise = true; paths = 1; cmdType = UNKNOWN; queryType = NOT_VALID; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; int tokenSize = tokens.size(); if (!valid) return false ; int tokenIndex = 0 ; string str1 = tokens[tokenIndex++]; if ( str1 == "report_at" ) { queryType = REPORT_AT; assert( tokens[tokenIndex++] == "-pin" ); pin = tokens[tokenIndex++]; while ( tokenIndex < tokenSize ) { string tmp = tokens[tokenIndex++]; if ( tmp == "-fall") { rise = false; } else if ( tmp == "-late" ) { early = false; } } } else if ( str1 == "report_rat" ) { queryType = REPORT_RAT; assert( tokens[tokenIndex++] == "-pin" ); pin = tokens[tokenIndex++]; while ( tokenIndex < tokenSize ) { string tmp = tokens[tokenIndex++]; if ( tmp == "-fall") { rise = false; } else if ( tmp == "-late" ) { early = false; } } } else if ( str1 == "report_slack" ) { queryType = REPORT_SLACK; assert( tokens[tokenIndex++] == "-pin" ); pin = tokens[tokenIndex++]; while ( tokenIndex < tokenSize ) { string tmp = tokens[tokenIndex++]; if ( tmp == "-fall") { rise = false; } else if ( tmp == "-late" ) { early = false; } } } else if ( str1 == "report_worst_paths" ) { queryType = REPORT_PATHS; while ( tokenIndex < tokenSize ) { assert ( tokenIndex + 1 < tokenSize ); string tmp1 = tokens[tokenIndex++]; string tmp2 = tokens[tokenIndex++]; if ( tmp1 == "-pin" ) { //read pin char after ':' when it's internal pin if ( tokenIndex == tokenSize-1 || tokenIndex == tokenSize-3 ) { pin = tmp2 + ":" + tokens[tokenIndex++]; } else pin = tmp2; } else if ( tmp1 == "-numPaths" ) { paths = (int) std::atof(tmp2.c_str()); } } } else if ( str1 == "insert_gate") { cmdType = INSERT_GATE; gate = tokens[tokenIndex++]; cell = tokens[tokenIndex++]; } else if ( str1 == "repower_gate") { cmdType = REPOWER_GATE; gate = tokens[tokenIndex++]; cell = tokens[tokenIndex++]; } else if ( str1 == "remove_gate") { cmdType = REMOVE_GATE; gate = tokens[tokenIndex++]; } else if ( str1 == "insert_net") { cmdType = INSERT_NET; net = tokens[tokenIndex++]; } else if ( str1 == "remove_net") { cmdType = REMOVE_NET; net = tokens[tokenIndex++]; } else if ( str1 == "read_spef") { cmdType = READ_SPEF; file = tokens[tokenIndex++]; } else if ( str1 == "connect_pin") { cmdType = CONNECT_PIN; pin = tokens[tokenIndex++]; net = tokens[tokenIndex++]; } else if ( str1 == "disconnect_pin") { cmdType = DISCONNECT_PIN; pin = tokens[tokenIndex++]; } return true; } // Read ceff values for the next pin or port // Return value indicates if the last read was successful or not. // If the line read corresponds to a pin, then name1 and name2 will be set to the cell // instance name and the pin name, respectively. // If the line read corresponds to a port, then name1 will be set to the port name, and // name2 will be set to "". bool CeffParser::read_ceff_line (string& name1, string& name2, double& riseCeff, double& fallCeff) { vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; if (!valid) return false ; assert (tokens.size() >= 3) ; int tokenIndex = 0 ; name1 = tokens[tokenIndex++] ; name2 = "" ; if (tokens.size() == 4) { // line corresponds to a cell pin name2 = tokens[tokenIndex++] ; } riseCeff = std::atof(tokens[tokenIndex++].c_str()) ; fallCeff = std::atof(tokens[tokenIndex++].c_str()) ; return true ; } // No need to parse the 3D LUTs, because they will be ignored void LibParser::_skip_lut_3D () { std::vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; if ( tokens[0] == "values" ) return; assert (tokens[0] == "index_1") ; assert (tokens.size() >= 2) ; unsigned size1 = tokens.size() - 1 ; valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens[0] == "index_2") ; assert (tokens.size() >= 2) ; unsigned size2 = tokens.size() - 1 ; valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens[0] == "index_3") ; assert (tokens.size() >= 2) ; unsigned size3 = tokens.size() - 1 ; valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() == 1 && tokens[0] == "values") ; for (unsigned i=0; i < size1; ++i) { for (unsigned j=0; j < size2; ++j) { valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() == size3) ; } } } void LibParser::_begin_read_lut (LibParserLUT& lut) { std::vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens[0] == "index_1") ; assert (tokens.size() >= 2) ; unsigned size1 = tokens.size()-1 ; lut.loadIndices.resize(size1) ; for (unsigned i=0; i < tokens.size()-1; ++i) { lut.loadIndices[i] = std::atof(tokens[i+1].c_str()) ; } valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens[0] == "index_2") ; assert (tokens.size() >= 2) ; int size2 = tokens.size()-1 ; lut.transitionIndices.resize(size2) ; for (unsigned i=0; i < tokens.size()-1; ++i) { lut.transitionIndices[i] = std::atof(tokens[i+1].c_str()) ; } valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() == 1 && tokens[0] == "values") ; lut.tableVals.initialize(size1, size2) ; for (unsigned i=0 ; i < lut.loadIndices.size(); ++i) { valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() == lut.transitionIndices.size()) ; for (unsigned j=0; j < lut.transitionIndices.size(); ++j) { lut.tableVals(i, j) = std::atof(tokens[j].c_str()) ; } } } void LibParser::_begin_read_timing_info (string toPin, LibParserPinInfo& pin, LibParserTimingInfo& timing) { timing.toPin = toPin ; bool finishedReading = false ; bool setup = false; std::vector tokens ; while (!finishedReading) { bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() >= 1) ; if (tokens[0] == "cell_fall") { _begin_read_lut (timing.fallDelay) ; } else if (tokens[0] == "cell_rise") { _begin_read_lut (timing.riseDelay) ; } else if (tokens[0] == "fall_transition") { _begin_read_lut (timing.fallTransition) ; } else if (tokens[0] == "rise_transition") { _begin_read_lut (timing.riseTransition) ; } else if (tokens[0] == "fall_constraint") { //_skip_lut_3D() ; // will ignore fall constraints bool valid = read_line_as_tokens (is, tokens) ; //assert (valid) ; //assert ( tokens[0] == "values" ); if ( setup ) _begin_read_lut (pin.fallSetup) ; //pin.fallSetup = std::atof(tokens[1].c_str()); else _begin_read_lut (pin.fallHold) ; //pin.fallHold = std::atof(tokens[1].c_str()); pin.isTimingEndpoint = true; //cout << "setup/hold: " << std::atof(tokens[1].c_str()) << endl; } else if (tokens[0] == "rise_constraint") { // _skip_lut_3D() ; // will ignore rise constraints bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert ( tokens[0] == "values" ); if ( setup ) _begin_read_lut (pin.riseSetup) ; //pin.riseSetup = std::atof(tokens[1].c_str()); else _begin_read_lut (pin.riseHold) ; //pin.riseHold = std::atof(tokens[1].c_str()); //cout << pin.name << " \tsetup/hold: " << std::atof(tokens[1].c_str()) << endl; } else if (tokens[0] == "timing_sense") { timing.timingSense = tokens[1] ; } else if (tokens[0] == "related_pin") { assert (tokens.size() == 2) ; timing.fromPin = tokens[1] ; } else if (tokens[0] == "End") { assert (tokens.size() == 2) ; assert (tokens[1] == "timing") ; finishedReading = true ; } else if (tokens[0] == "timing_type") { if ( tokens[1] == "setup_rising") setup = true; else setup = false; } else if (tokens[0] == "related_output_pin") { // ignore data } else { cout << "Error: Unknown keyword: " << tokens[0] << endl ; assert (false) ; // unknown keyword } } } void LibParser::_begin_read_pin_info (string pinName, LibParserCellInfo& cell, LibParserPinInfo& pin) { pin.name = pinName ; pin.isClock = false ; pin.maxCapacitance = std::numeric_limits::max() ; //cout << "\tpin: " << pinName << endl; bool finishedReading = false ; std::vector tokens ; while (!finishedReading) { bool valid = read_line_as_tokens (is, tokens) ; assert (valid) ; assert (tokens.size() >= 1) ; //cout << tokens[0] << "\t" << tokens[1] << endl; if (tokens[0] == "direction") { assert (tokens.size() == 2) ; if (tokens[1] == "input") pin.isInput = true ; else if (tokens[1] == "output") pin.isInput = false ; else assert (false) ; // undefined direction } else if (tokens[0] == "capacitance") { assert (tokens.size() == 2) ; pin.capacitance = std::atof(tokens[1].c_str()) ; } else if (tokens[0] == "max_capacitance") { assert (tokens.size() == 2) ; pin.maxCapacitance = std::atof(tokens[1].c_str()) ; } else if (tokens[0] == "timing") { cell.timingArcs.push_back(LibParserTimingInfo()) ; // add an empty TimingInfo object _begin_read_timing_info (pinName, pin, cell.timingArcs.back()) ; // pass the empty object to the function to be filled } else if (tokens[0] == "clock") { pin.isClock = true ; cell.isSequential = true; } else if (tokens[0] == "End") { assert (tokens.size() == 2) ; assert (tokens[1] == "pin") ; finishedReading = true ; } else if (tokens[0] == "function") { // ignore data } else if (tokens[0] == "min_capacitance") { // ignore data } else if (tokens[0] == "nextstate_type") { // ignore data } else { cout << "Error: Unknown keyword: " << tokens[0] << endl ; assert (false) ; // unknown keyword } } } void LibParser::_begin_read_cell_info (string cellName, LibParserCellInfo& cell) { cell.name = cellName ; cell.isSequential = false ; cell.dontTouch = false ; bool finishedReading = false ; //cout << "Cell: " << cellName << endl; std::vector tokens ; while (!finishedReading) { bool valid = read_line_as_tokens (is, tokens) ; //cout << "size: " << tokens.size() << endl; assert (valid) ; assert (tokens.size() >= 1) ; //cout << tokens[0] << endl; if (tokens[0] == "cell_leakage_power") { assert (tokens.size() == 2) ; cell.leakagePower = std::atof(tokens[1].c_str()) ; } else if (tokens[0] == "cell_footprint") { assert (tokens.size() == 2) ; cell.footprint = tokens[1] ; } else if (tokens[0] == "area") { assert (tokens.size() == 2) ; cell.area = std::atof(tokens[1].c_str()) ; } else if (tokens[0] == "clocked_on") { cell.isSequential = true ; } else if (tokens[0] == "dont_touch") { cell.dontTouch = true ; } else if (tokens[0] == "pin") { assert (tokens.size() == 2) ; cell.pins.push_back(LibParserPinInfo()) ; // add empty PinInfo object _begin_read_pin_info (tokens[1], cell, cell.pins.back()) ; // pass the new PinInfo object to be filled } else if (tokens[0] == "End") { assert (tokens.size() == 3) ; assert (tokens[1] == "cell") ; assert (tokens[2] == cellName) ; finishedReading = true ; } else if (tokens[0] == "cell_footprint") { // ignore data } else if (tokens[0] == "ff") { // ignore data } else if (tokens[0] == "next_state") { // ignore data } else if (tokens[0] == "dont_use") { // ignore data } else { cout << "Error: Unknown keyword: " << tokens[0] << endl ; assert (false) ; // unknown keyword } } } // Read the default max_transition defined for the library. // Return value indicates if the last read was successful or not. // This function must be called in the beginning before any read_cell_info function call. bool LibParser::read_default_max_transition (double& maxTransition) { maxTransition = 0.0 ; vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; while (valid) { if (tokens.size() == 2 && tokens[0] == "default_max_transition") { maxTransition = std::atof(tokens[1].c_str()) ; return true ; } valid = read_line_as_tokens (is, tokens) ; } return false ; } // Read the next standard cell definition. // Return value indicates if the last read was successful or not. bool LibParser::read_cell_info (LibParserCellInfo& cell) { vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; while (valid) { if (tokens.size() == 2 && tokens[0] == "cell") { _begin_read_cell_info (tokens[1], cell) ; return true ; } valid = read_line_as_tokens (is, tokens) ; } return false ; } ostream& operator<< (ostream& os, LibParserLUT& lut) { if (lut.loadIndices.empty() && lut.transitionIndices.empty() && lut.tableVals.isEmpty()) return os ; // We should have either all empty or none empty. assert (!lut.loadIndices.empty() && !lut.transitionIndices.empty() && !lut.tableVals.isEmpty()) ; assert (lut.tableVals.getNumElements() == lut.loadIndices.size()) ; assert (lut.tableVals.getNumRows() == lut.transitionIndices.size()) ; cout << "\t" ; for (unsigned i=0; i < lut.transitionIndices.size(); ++i) { cout << lut.transitionIndices[i] << "\t" ; } cout << endl ; for (unsigned i=0; i < lut.loadIndices.size(); ++i) { cout << lut.loadIndices[i] << "\t" ; for (unsigned j=0; j < lut.transitionIndices.size(); ++j) cout << lut.tableVals(i, j) << "\t" ; cout << endl ; } return os ; } ostream& operator<< (ostream& os, LibParserTimingInfo& timing) { cout << "Timing info from " << timing.fromPin << " to " << timing.toPin << ": " << endl ; cout << "Timing sense: " << timing.timingSense << endl ; cout << "Fall delay LUT: " << endl ; cout << timing.fallDelay ; cout << "Rise delay LUT: " << endl ; cout << timing.riseDelay ; cout << "Fall transition LUT: " << endl ; cout << timing.fallTransition ; cout << "Rise transition LUT: " << endl ; cout << timing.riseTransition ; return os ; } ostream& operator<< (ostream& os, LibParserPinInfo& pin) { cout << "Pin " << pin.name << ":" << endl ; cout << "capacitance: " << pin.capacitance << endl ; cout << "maxCapacitance: " << pin.maxCapacitance << endl ; cout << "isInput? " << (pin.isInput ? "true" : "false") << endl ; cout << "isClock? " << (pin.isClock ? "true" : "false") << endl ; cout << "End pin" << endl ; return os ; } ostream& operator<< (ostream& os, LibParserCellInfo& cell) { cout << "Library cell " << cell.name << ": " << endl ; cout << "Footprint: " << cell.footprint << endl ; cout << "Leakage power: " << cell.leakagePower << endl ; cout << "Area: " << cell.area << endl ; cout << "Sequential? " << (cell.isSequential ? "yes" : "no") << endl ; cout << "Dont-touch? " << (cell.dontTouch ? "yes" : "no") << endl ; cout << "Cell has " << cell.pins.size() << " pins: " << endl ; for (unsigned i=0; i < cell.pins.size(); ++i) { cout << cell.pins[i] << endl ; } cout << "Cell has " << cell.timingArcs.size() << " timing arcs: " << endl ; for (unsigned i=0; i < cell.timingArcs.size(); ++i) { cout << cell.timingArcs[i] << endl ; } cout << "End of cell " << cell.name << endl << endl ; return os ; } // Example function that uses VerilogParser class to parse the given ISPD-13 verilog // file. The extracted data is simply printed out in this example. void test_verilog_parser (string filename) { VerilogParser vp (filename) ; string moduleName ; bool valid = vp.read_module (moduleName) ; assert (valid) ; cout << "Module " << moduleName << endl << endl ; do { string primaryInput ; valid = vp.read_primary_input (primaryInput) ; if (valid) cout << "Primary input: " << primaryInput << endl ; } while (valid) ; cout << endl ; do { string primaryOutput ; valid = vp.read_primary_output (primaryOutput) ; if (valid) cout << "Primary output: " << primaryOutput << endl ; } while (valid) ; cout << endl ; do { string net ; valid = vp.read_wire (net) ; if (valid) cout << "Net: " << net << endl ; } while (valid) ; cout << endl ; cout << "Cell insts: " << std::endl ; do { string cellType, cellInst ; vector > pinNetPairs ; valid = vp.read_cell_inst (cellType, cellInst, pinNetPairs) ; if (valid) { cout << cellType << " " << cellInst << " " ; for (unsigned i=0; i < pinNetPairs.size(); ++i) { cout << "(" << pinNetPairs[i].first << " " << pinNetPairs[i].second << ") " ; } cout << endl ; } } while (valid) ; } // Example function that uses SdcParser class to parse the given ISPD-13 sdc // file. The extracted data is simply printed out in this example. void test_sdc_parser (string filename) { SdcParser sp (filename) ; string clockName ; string clockPort ; double period ; bool valid = sp.read_clock (clockName, clockPort, period) ; assert(valid) ; cout << "Clock " << clockName << " connected to port " << clockPort << " has period " << period << endl ; do { string portName ; double delay ; valid = sp.read_input_delay (portName, delay) ; if (valid) cout << "Input port " << portName << " has delay " << delay << endl ; } while (valid) ; do { string portName ; string driverSize ; string driverPin ; double inputTransitionFall ; double inputTransitionRise ; valid = sp.read_driver_info (portName, driverSize, driverPin, inputTransitionFall, inputTransitionRise) ; if (valid) { cout << "Input port " << portName << " is assumed to be connected to the " << driverPin << " pin of lib cell " << driverSize << endl ; cout << "This virtual driver is assumed to have input transitions: " << inputTransitionFall << " (fall) and " << inputTransitionRise << " (rise)" << endl ; } } while (valid) ; do { string portName ; double delay ; valid = sp.read_output_delay (portName, delay) ; if (valid) cout << "Output port " << portName << " has delay " << delay << endl ; } while (valid) ; do { string portName ; double load ; valid = sp.read_output_load (portName, load) ; if (valid) cout << "Output port " << portName << " has load " << load << endl ; } while (valid) ; } // Example function that uses SpefParser class to parse the given ISPD-13 spef // file. The extracted data is simply printed out in this example. void test_spef_parser (string filename) { SpefParser sp (filename) ; SpefNet spefNet ; bool valid = sp.read_net_data (spefNet) ; int readCnt = 0 ; while (valid) { ++readCnt ; // print out the contents of the spefNet just read cout << "Net: " << spefNet.netName << endl ; cout << "Net lumped cap: " << spefNet.netLumpedCap << endl ; cout << "Connections: " << endl ; for (int i=0; i < spefNet.connections.size(); ++i) { cout << spefNet.connections[i] << endl ; } cout << "Capacitances: " << endl ; for (int i=0; i < spefNet.capacitances.size(); ++i) { cout << spefNet.capacitances[i] << endl ; } cout << "Resistances: " << endl ; for (int i=0; i < spefNet.resistances.size(); ++i) { cout << spefNet.resistances[i] << endl ; } cout << endl ; valid = sp.read_net_data (spefNet) ; } cout << "Read " << readCnt << " nets in the spef file." << endl ; } // Example function that uses TimingParser class to parse the given ISPD-13 timing // file. The extracted data is simply printed out in this example. void test_timing_parser (string filename) { TimingParser tp (filename) ; bool valid = false ; while (true) { string name1, name2 ; double riseSlack, fallSlack, riseTransition, fallTransition, riseArrival, fallArrival ; valid = tp.read_timing_line (name1, name2, riseSlack, fallSlack, riseTransition, fallTransition, riseArrival, fallArrival) ; if (!valid) break ; if (name2 != "") { // timing info of a pin // name1: cellInstance, name2: pin std::cout << name1 << "/" << name2 << " " << riseSlack << " " << fallSlack << " " << riseTransition << " " << fallTransition << " " << riseArrival << " " << fallArrival << endl ; } else { // timing of a port // name1: port name std::cout << name1 << " " << riseSlack << " " << fallSlack << " " << riseTransition << " " << fallTransition << " " << riseArrival << " " << fallArrival << endl ; } } } // Example function that uses CeffParser class to parse the given ISPD-13 ceff // file. The extracted data is simply printed out in this example. void test_ceff_parser (string filename) { CeffParser tp (filename) ; bool valid = false ; while (true) { string name1, name2 ; double riseCeff, fallCeff ; valid = tp.read_ceff_line (name1, name2, riseCeff, fallCeff) ; if (!valid) break ; if (name2 != "") { // ceff values of a pin // name1: cellInstance, name2: pin std::cout << name1 << "/" << name2 << " " << riseCeff << " " << fallCeff << endl ; } else { // timing of a port // name1: port name std::cout << name1 << " " << riseCeff << " " << fallCeff << endl ; } } } // Example function that uses LibParser class to parse the given ISPD-13 lib // file. The extracted data is simply printed out in this example. void test_lib_parser (string filename) { LibParser lp (filename) ; double maxTransition = 0.0 ; bool valid = lp.read_default_max_transition(maxTransition) ; assert (valid) ; cout << "The default max transition defined is " << maxTransition << endl ; int readCnt = 0 ; do { LibParserCellInfo cell ; valid = lp.read_cell_info (cell) ; if (valid) { ++readCnt ; cout << cell << endl ; } } while (valid) ; cout << "Read " << readCnt << " number of library cells" << endl ; } ostream& operator<< (ostream& os, const SpefNodeName& n) { os << n.n1 << ((n.n2 != "") ? ":" : "") << n.n2 ; return os ; } ostream& operator<< (ostream& os, const SpefConnection& c) { os << c.nodeType << " " << c.nodeName << " " << c.direction ; return os ; }; ostream& operator<< (ostream& os, const SpefCapacitance& c) { os << c.nodeName << " " << c.capacitance ; return os ; } ostream& operator<< (ostream& os, const SpefResistance& r) { os << r.fromNodeName << " " << r.toNodeName << " " << r.resistance ; return os ; } bool OPSParser::read_operation (OPSInfo &ops) { vector tokens ; bool valid = read_line_as_tokens (is, tokens) ; int tokenSize = tokens.size(); if (!valid) return false ; string opt = tokens[tokenSize++]; ops.opsType = opt; if(opt == "report_at"){ ops.pin = tokens[++tokenSize]; //if() } //TODO return true; } } // end namespace ================================================ FILE: rsyn/src/rsyn/io/parser/parser_helper.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ ////////////////////////////////////////////////////////////////// // // // Helper functions and classes to parse the ISPD 2012 contest // benchmark files. // // This code is provided for description purposes only. The contest // organizers cannot guarantee that the provided code is free of // bugs or defects. !!!! USE THIS CODE AT YOUR OWN RISK !!!!! // // // The contestants are free to use these functions as-is or make // modifications. If the contestants choose to use the provided // code, they are responsible for making sure that it works as // expected. // // The code provided here has no real or implied warranties. // // //////////////////////////////////////////////////////////////////// #ifndef _PARSER_HELPER_H #define _PARSER_HELPER_H #include #include #include #include #include #include "rsyn/util/Array.h" using std::cout ; using std::endl ; using std::istream ; using std::ostream ; using std::vector ; using std::string ; namespace ISPD13 { enum CommandTypeEnum { INSERT_GATE, REPOWER_GATE, REMOVE_GATE, INSERT_NET, READ_SPEF, REMOVE_NET, CONNECT_PIN, DISCONNECT_PIN, UNKNOWN }; // end enum enum QueryTypeEnum { REPORT_AT, REPORT_RAT, REPORT_SLACK, REPORT_PATHS, NOT_VALID }; // end enum enum OpsType {CMD, QUERY, NONE}; ///////////////////////////////////////////////////////////////////// // // This class can be used to parse the specific verilog // format as defined in the ISPD-13 contest benchmarks. It is not // intended to be used as a generic verilog parser. // // See test_verilog_parser () function in parser_helper.cpp for an // example of how to use this class. // ///////////////////////////////////////////////////////////////////// enum tauVerilog {INPUT_TAU15, OUTPUT_TAU15, WIRE_TAU15, GATE_TAU15, ENDMOD_TAU15}; class VerilogParser { std::ifstream is ; public: vector < string > tauTokens; // Constructor that opens the given filename VerilogParser (string filename): is(filename.c_str()) { if (!is) { std::cout << "[ERROR] File '" << filename << "' could not be opened.\n"; } // end if } // The following functions must be issued in a particular order // See test_verilog_parser function for an example // Read the module definition bool read_module (string& moduleName) ; // Read the next primary input. // Return value indicates if the last read was successful or not. bool read_primary_input (string& primaryInput) ; // Read the next primary output. // Return value indicates if the last read was successful or not. bool read_primary_output (string& primaryInput) ; // Read the next net. // Return value indicates if the last read was successful or not. bool read_wire (string& wire) ; // Read the next cell instance. // Return value indicates if the last read was successful or not. bool read_cell_inst (string& cellType, string& cellInstName, vector >& pinNetPairs) ; //function adapted for TAU 15 contest tauVerilog read_line_tau15(string &aux); bool read_module_tau15 (string& moduleName) ; bool read_module_ispd15 (string& moduleName) ; bool read_cell_inst_tau15 (string& cellType, string& cellInstName, vector >& pinNetPairs); } ; ///////////////////////////////////////////////////////////////////// // // This class can be used to parse the specific sdc // format as defined in the ISPD-13 contest benchmarks. It is not // intended to be used as a generic sdc parser. // // See test_sdc_parser () function in parser_helper.cpp for an // example of how to use this class. // ///////////////////////////////////////////////////////////////////// class SdcParser { std::ifstream is ; public: // Constructor that opens the given filename SdcParser (string filename): is(filename.c_str()) { if (!is) { std::cout << "ERROR: SDC file '" << filename << "' could not be opened.\n"; std::exit(1); } // end if } // end constructor // The following functions must be issued in a particular order // See test_sdc_parser function for an example // Read clock definition // Return value indicates if the last read was successful or not. bool read_clock (string& clockName, string& clockPort, double& period) ; // Read input delay // Return value indicates if the last read was successful or not. bool read_input_delay (string& portName, double& delay) ; // Read driver info for the input port // Return value indicates if the last read was successful or not. bool read_driver_info (string& inPortName, string& driverSize, string& driverPin, double& inputTransitionFall, double& inputTransitionRise) ; // Read output delay // Return value indicates if the last read was successful or not. bool read_output_delay (string& portName, double& delay) ; // Read output load // Return value indicates if the last read was successful or not. bool read_output_load (string& outPortName, double& load) ; } ; ///////////////////////////////////////////////////////////////////// // // The following classes can be used to parse the specific spef // format as defined in the ISPD-13 contest benchmarks. It is not // intended to be used as a generic spef parser. // // See test_spef_parser () function in parser_helper.cpp for an // example of how to use this class. // ///////////////////////////////////////////////////////////////////// struct SpefNodeName { string n1 ; string n2 ; // A node in the spef file can be defined in 3 different ways: // 1. For the node corresponding to the connection to a port: // nodeName = "portName", i.e. n1 = "portName", n2 = "" // // 2. For the node corresponding to the connection to a cell pin: // nodeName = "cellName":"pinName", i.e. n1 = "cellName", n2 = "pinName" // // 3. For an internal node of an RC tree: // nodeName = "netName":"index", i.e. n1 = "netName", n2 = "index" // Added by Guilherme Flach operator string() const {return n1 + ((n2 != "") ? ":" : "") + n2;} } ; ostream& operator<< (ostream& os, const SpefNodeName& n) ; struct SpefConnection { char nodeType ; // either 'P' (port) or 'I' (internal) SpefNodeName nodeName ; char direction ; // either 'I' (receiver pin) or 'O' (driver pin) }; ostream& operator<< (ostream& os, const SpefConnection& c) ; struct SpefCapacitance { SpefNodeName nodeName ; double capacitance ; } ; ostream& operator<< (ostream& os, const SpefCapacitance& c) ; struct SpefResistance { SpefNodeName fromNodeName ; SpefNodeName toNodeName ; double resistance ; } ; ostream& operator<< (ostream& os, const SpefResistance& r) ; struct SpefNet { string netName ; double netLumpedCap ; vector connections ; vector capacitances ; vector resistances ; void clear() { netName = "" ; netLumpedCap = 0.0 ; connections.clear() ; capacitances.clear() ; resistances.clear() ; } } ; class SpefParser { std::ifstream is ; bool read_connections (vector& connections) ; void read_capacitances (vector& capacitances) ; void read_resistances (vector& resistances) ; public: SpefParser (string filename): is(filename.c_str()) {} // Read the spef data for the next net. // Return value indicates if the last read was successful or not. bool read_net_data (SpefNet& spefNet) ; } ; ///////////////////////////////////////////////////////////////////// // // This class can be used to parse the specific .timing // format as defined in the ISPD-13 contest benchmarks. // // See test_timing_parser () function in parser_helper.cpp for an // example of how to use this class. // ///////////////////////////////////////////////////////////////////// class TimingParser { std::ifstream is ; public: TimingParser (string filename): is(filename.c_str()) {} // Read timing info for the next pin or port // Return value indicates if the last read was successful or not. // If the line read corresponds to a pin, then name1 and name2 will be set to the cell // instance name and the pin name, respectively. // If the line read corresponds to a port, then name1 will be set to the port name, and // name2 will be set to "". bool read_timing_line (string& name1, string& name2, double& riseSlack, double& fallSlack, double& riseTransition, double& fallTransition, double& riseArrival, double& fallArrival) ; bool read_timing_tau15(string & str1, string &str2, double &val1, double &val2, double &val3, double &val4); } ; ///////////////////////////////////////////////////////////////////// // // This class can be used to parse the specific .ops // format as defined in the TAU-15 contest benchmarks. // ///////////////////////////////////////////////////////////////////// class OperationsParser { std::ifstream is ; public: OperationsParser (string filename): is(filename.c_str()) {} // Read timing info for the next pin or port // Return value indicates if the last read was successful or not. // If the line read corresponds to a pin, then name1 and name2 will be set to the cell // instance name and the pin name, respectively. // If the line read corresponds to a port, then name1 will be set to the port name, and // name2 will be set to "". bool read_ops_tau15(ISPD13::CommandTypeEnum &cmdType, ISPD13::QueryTypeEnum &queryType, string &pin, string &net, string &file, string &gate, string &cell, bool &early, bool &rise, int &paths ); } ; ///////////////////////////////////////////////////////////////////// // // This class can be used to parse the specific .ceff // format as defined in the ISPD-13 contest benchmarks. // // See test_ceff_parser () function in parser_helper.cpp for an // example of how to use this class. // ///////////////////////////////////////////////////////////////////// class CeffParser { std::ifstream is ; public: CeffParser (string filename): is(filename.c_str()) {} // Read ceff values for the next pin or port // Return value indicates if the last read was successful or not. // If the line read corresponds to a pin, then name1 and name2 will be set to the cell // instance name and the pin name, respectively. // If the line read corresponds to a port, then name1 will be set to the port name, and // name2 will be set to "". bool read_ceff_line (string& name1, string& name2, double& riseCeff, double& fallCeff) ; } ; ///////////////////////////////////////////////////////////////////// // // The following classes can be used to parse the specific lib // format as defined in the ISPD-13 contest benchmarks. They are not // intended to be used as a generic lib parser. // // See test_lib_parser () function in parser_helper.cpp for an // example of how to use these classes. // ///////////////////////////////////////////////////////////////////// // Look up table to store delay or slew functions struct LibParserLUT { // Look up table is indexed by the output load and the input transition values // Example: // Let L = loadIndices[i] // T = transitionIndices[j] // Then, the table value corresponding to L and T will be: // table[i][j] // bool isScalar; vector loadIndices ; vector transitionIndices ; Array2D tableVals ; LibParserLUT() : isScalar(false) {}; double getMaxLoad() const { return loadIndices[loadIndices.size() -1]; } double getMinLoad() const { return loadIndices[0]; } double getMaxTransition() const { return transitionIndices[transitionIndices.size() -1]; } double getMinTransition() const { return transitionIndices[0]; } } ; ostream& operator<< (ostream& os, LibParserLUT& lut) ; struct LibParserTimingInfo { string fromPin ; string toPin ; string timingSense ; // "non_unate" or "negative_unate" or "positive_unate". // Note that ISPD-13 library will have only negative-unate combinational cells. The clock arcs // for sequentials will be non_unate (which can be ignored because of the simplified sequential // timing model for ISPD-13). // Guilherme Flach - 2016/08/21 // Added to identify non-common timing arcs (e.g. clear, preset, // three-state). string timingType; LibParserLUT fallDelay ; LibParserLUT riseDelay ; LibParserLUT fallTransition ; LibParserLUT riseTransition ; } ; ostream& operator<< (ostream& os, LibParserTimingInfo& timing) ; struct LibParserPinInfo { string name ; // pin name string related; double capacitance ; // input pin cap (not defined for output pins) double maxCapacitance ; // the max load this pin can drive double maxTransition; // max input transition time bool isInput ; // whether the pin is input or output pin bool isClock ; // whether the pin is a clock pin or not bool isTimingEndpoint; bool risingEdge; LibParserLUT riseSetup; LibParserLUT fallSetup; LibParserLUT riseHold; LibParserLUT fallHold; LibParserPinInfo () : capacitance (0.0), maxCapacitance (std::numeric_limits::max()), maxTransition (-std::numeric_limits::infinity()), isInput(true), isClock(false), isTimingEndpoint(false), risingEdge(false) {} } ; ostream& operator<< (ostream& os, LibParserPinInfo& pin) ; struct LibParserCellInfo { string name ; // cell name string footprint ; // only the cells with the same footprint are swappable double leakagePower ; // cell leakage power double area ; // cell area (will not be a metric for ISPD-13) bool isSequential ; // if true then sequential cell, else combinational bool dontTouch ; // is the sizer allowed to size this cell? bool isTieLow; // Tie are cells that keeps output constantly in VDD or GND bool isTieHigh; vector pins ; vector timingArcs ; LibParserCellInfo () : leakagePower (0.0), area (0.0), isSequential (false), dontTouch(false), isTieLow(false), isTieHigh(false) {} } ; ostream& operator<< (ostream& os, LibParserCellInfo& cell) ; // See test_lib_parser () function in parser_helper.cpp for an // example of how to use this class. class LibParser { std::ifstream is ; void _skip_lut_3D () ; void _begin_read_lut (LibParserLUT& lut) ; void _begin_read_timing_info (string pinName, LibParserPinInfo& pin, LibParserTimingInfo& cell) ; void _begin_read_pin_info (string pinName, LibParserCellInfo& cell, LibParserPinInfo& pin) ; void _begin_read_cell_info (string cellName, LibParserCellInfo& cell) ; public: LibParser (string filename): is(filename.c_str()) {} // Read the default max_transition defined for the library. // Return value indicates if the last read was successful or not. // This function must be called in the beginning before any read_cell_info function call. bool read_default_max_transition (double& maxTransition) ; // Read the next standard cell definition. // Return value indicates if the last read was successful or not. bool read_cell_info (LibParserCellInfo& cell) ; } ; /* * * PArsing TAU 2015 operations * * */ enum propType {LATE, EARLY}; enum timeTransType {RISE, FALL}; class OPSInfo{ public: string opsType; string pin; string cell; string gate; string file; propType prop; timeTransType timeTrans; int numPaths; }; class OPSParser { std::ifstream is ; public: OPSParser (string filename): is(filename.c_str()) {} // Read ceff values for the next pin or port // Return value indicates if the last read was successful or not. // If the line read corresponds to a pin, then name1 and name2 will be set to the cell // instance name and the pin name, respectively. // If the line read corresponds to a port, then name1 will be set to the port name, and // name2 will be set to "". bool read_operation (OPSInfo &ops) ; }; } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/io/reader/ISPD2018Reader.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ISPD2018Reader.h" #include #include "rsyn/ispd18/Guide.h" #include "rsyn/ispd18/RoutingGuide.h" #include "rsyn/io/parser/guide-ispd18/GuideParser.h" #include "rsyn/io/parser/lef_def/LEFControlParser.h" #include "rsyn/io/parser/lef_def/DEFControlParser.h" namespace Rsyn { bool ISPD2018Reader::load(const Rsyn::Json& params) { Rsyn::Session session; std::string path = params.value("path", ""); if (!params.count("lefFile")) { std::cout << "[ERROR] LEF file not specified...\n"; return false; } // end if lefFile = session.findFile(params.value("lefFile", ""), path); if (!params.count("defFile")) { std::cout << "[ERROR] DEF file not specified...\n"; return false; } // end if defFile = session.findFile(params.value("defFile", ""), path); // if (!params.count("guideFile")) { // std::cout << "[ERROR] Guide file not specified...\n"; // return false; // } // end if // guideFile = session.findFile(params.value("guideFile", ""), path); parsingFlow(); return true; } // end method // ----------------------------------------------------------------------------- void ISPD2018Reader::parsingFlow() { parseLEFFile(); parseDEFFile(); populateDesign(); // parseGuideFile(); } // end method // ----------------------------------------------------------------------------- void ISPD2018Reader::parseLEFFile() { LEFControlParser lefParser; lefParser.parseLEF(lefFile, lefDescriptor); } // end method // ----------------------------------------------------------------------------- void ISPD2018Reader::parseDEFFile() { DEFControlParser defParser; defParser.parseDEF(defFile, defDescriptor); } // end method // ----------------------------------------------------------------------------- void ISPD2018Reader::parseGuideFile() { GuideDscp guideDescriptor; GuideParser guideParser; guideParser.parse(guideFile, guideDescriptor); session.startService("rsyn.routingGuide"); routingGuide = (RoutingGuide*) session.getService("rsyn.routingGuide"); routingGuide->loadGuides(guideDescriptor); } // end method void ISPD2018Reader::populateDesign() { Rsyn::Design design = session.getDesign(); Reader::populateRsyn(lefDescriptor, defDescriptor, design); Rsyn::Json physicalDesignConfiguration; physicalDesignConfiguration["clsEnableMergeRectangles"] = false; physicalDesignConfiguration["clsEnableNetPinBoundaries"] = true; physicalDesignConfiguration["clsEnableRowSegments"] = true; session.startService("rsyn.physical", physicalDesignConfiguration); Rsyn::PhysicalDesign physicalDesign = session.getPhysicalDesign(); physicalDesign.loadLibrary(lefDescriptor); physicalDesign.loadDesign(defDescriptor); physicalDesign.updateAllNetBounds(false); } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/io/reader/ISPD2018Reader.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_ISPD2018_READER_H #define RSYN_ISPD2018_READER_H #include namespace Rsyn { class RoutingGuide; class ISPD2018Reader : public Reader { public: ISPD2018Reader() = default; virtual bool load(const Rsyn::Json& params) override; private: Session session; std::string lefFile; std::string defFile; std::string guideFile; LefDscp lefDescriptor; DefDscp defDescriptor; RoutingGuide *routingGuide; void parsingFlow(); void parseLEFFile(); void parseDEFFile(); void parseGuideFile(); void populateDesign(); }; } #endif /* ISPD2018READER_H */ ================================================ FILE: rsyn/src/rsyn/io/reader/PopulateRsyn.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PopulateRsyn.cpp * Author: jucemar * * Created on 18 de Fevereiro de 2017, 15:21 */ #include "PopulateRsyn.h" namespace Rsyn { // ----------------------------------------------------------------------------- void PopulateRsyn::populateRsynLibraryFromLef( const LefDscp &lefDscp, Rsyn::Design rsynDesign ) { for (const LefMacroDscp & macro : lefDscp.clsLefMacroDscps) { Rsyn::CellDescriptor dscp; dscp.setMacro(macro.clsMacro); for (const LefPinDscp &pin : macro.clsPins) { // Mateus @ 20180917: Adding PinUse dscp.addPin(pin.clsPinName, Legacy::lefPinDirectionFromString(pin.clsPinDirection), Legacy::lefPinUseFromString(pin.clsPinUse)); } // end for rsynDesign.createLibraryCell(dscp, true); } // end for } // end method // ----------------------------------------------------------------------------- void PopulateRsyn::populateRsynNetlistFromVerilog( const Legacy::Design &verilogDesign, Rsyn::Design rsynDesign ) { bool keepWarning; int keepWarningCounter; Rsyn::Module top = rsynDesign.getTopModule(); rsynDesign.updateName(verilogDesign.name); keepWarning = true; keepWarningCounter = 0; for (auto &port : verilogDesign.primaryInputs) { Rsyn::Port rsynCell = rsynDesign.findPortByName(port); if (!rsynCell) { top.createPort(Rsyn::IN, port); } else { if (keepWarning) { if (++keepWarningCounter > 10) { keepWarning = false; std::cout << "[WARNING] At leat one more duplicated port...\n"; } else { std::cout << "[WARNING] The primary input port '" << port << "' is already defined.\n"; } // end else } // end if } // end else } // end for keepWarning = true; keepWarningCounter = 0; for (auto &port : verilogDesign.primaryOutputs) { Rsyn::Port rsynCell = rsynDesign.findPortByName(port); if (!rsynCell) { top.createPort(Rsyn::OUT, port); } else { if (keepWarning) { if (++keepWarningCounter > 10) { keepWarning = false; std::cout << "[WARNING] At leat one more duplicated port...\n"; } else { std::cout << "[WARNING] The primary output port '" << port << "' is already defined.\n"; } // end else } // end if } // end else } // end for // Creates cells. for (auto &component : verilogDesign.components) { Rsyn::LibraryCell lcell = rsynDesign.findLibraryCellByName(component.id); if (!lcell) { std::string str = "Library cell " + component.id + " not found\n"; throw Exception(str); } // end if top.createCell(lcell, component.name); } // end for // Creates nets and connections. for (auto &net : verilogDesign.nets) { if (net.name == "") { std::cout << "[ERROR] Empty net name.\n"; for (unsigned i = 0; i < net.connections.size(); i++) { std::cout << "Connection: " << net.connections[i].instance << ":" << net.connections[i].pin << "\n"; } // end for exit(1); } // end if Rsyn::Net rsynNet = top.createNet(net.name); for (auto &connection : net.connections) { if (connection.instance == "PIN") { Rsyn::Port rsynCell = rsynDesign.findPortByName(connection.pin); if (!rsynCell) { std::cout << "[ERROR] The primary input/ouput port '" << connection.pin << "' not found.\n"; exit(1); } // end if Rsyn::Pin rsynPin = rsynCell.getInnerPin(); rsynPin.connect(rsynNet); } else { Rsyn::Cell rsynCell = rsynDesign.findCellByName(connection.instance); if (!rsynCell) { std::cout << "[ERROR] Cell '" << connection.instance << "' not found.\n"; exit(1); } // end if Rsyn::Pin rsynPin = rsynCell.getPinByName(connection.pin); rsynPin.connect(rsynNet); } // end else } // end for } // end for } // end method // ----------------------------------------------------------------------------- void PopulateRsyn::populateRsyn( const LefDscp &lefDscp, const DefDscp &defDscp, const Legacy::Design &verilogDesign, Rsyn::Design rsynDesign) { bool keepWarning; int keepWarningCounter; Rsyn::Module top = rsynDesign.getTopModule(); rsynDesign.updateName(defDscp.clsDesignName); // Create library cells. // Some cells (e.g. TIE) only appears in the LEF, not in the Liberty // at least for ICCAD 15 benchmarks. That's why we need to try to create // also cells using LEF. populateRsynLibraryFromLef(lefDscp, rsynDesign); // Creates ports. for (const DefPortDscp &port : defDscp.clsPorts) { const Rsyn::Direction direction = (port.clsDirection == "INPUT") ? Rsyn::IN : Rsyn::OUT; top.createPort(direction, port.clsName); } // end for keepWarning = true; keepWarningCounter = 0; for (auto &port : verilogDesign.primaryInputs) { Rsyn::Port rsynCell = rsynDesign.findPortByName(port); if (!rsynCell) { if (keepWarning) { if (++keepWarningCounter > 10) { keepWarning = false; std::cout << "[WARNING] At leat one more undefined port...\n"; } else { std::cout << "[WARNING] The primary input port '" << port << "' is defined in Verilog file but not in the DEF file.\n"; } // end else } // end if top.createPort(Rsyn::IN, port); } // end if } // end for keepWarning = true; keepWarningCounter = 0; for (auto &port : verilogDesign.primaryOutputs) { Rsyn::Port rsynCell = rsynDesign.findPortByName(port); if (!rsynCell) { if (keepWarning) { if (++keepWarningCounter > 10) { keepWarning = false; std::cout << "[WARNING] At leat one more undefined port...\n"; } else { std::cout << "[WARNING] The primary output port '" << port << "' is defined in Verilog file but not in the DEF file.\n"; } // end else } // end if top.createPort(Rsyn::OUT, port); } // end if } // end for // Creates cells. for (const DefComponentDscp &component : defDscp.clsComps) { Rsyn::LibraryCell lcell = rsynDesign.findLibraryCellByName(component.clsMacroName); if (!lcell) { std::string str = "Library cell " + component.clsMacroName + " not found\n"; throw Exception(str); } // end if top.createCell(lcell, component.clsName); } // end for // Creates nets and connections. for (auto &net : verilogDesign.nets) { if (net.name == "") { std::cout << "[ERROR] Empty net name.\n"; for (unsigned i = 0; i < net.connections.size(); i++) { std::cout << "Connection: " << net.connections[i].instance << ":" << net.connections[i].pin << "\n"; } // end for exit(1); } // end if Rsyn::Net rsynNet = top.createNet(net.name); for (auto &connection : net.connections) { if (connection.instance == "PIN") { Rsyn::Port rsynCell = rsynDesign.findPortByName(connection.pin); if (!rsynCell) { std::cout << "[ERROR] The primary input/ouput port '" << connection.pin << "' not found.\n"; exit(1); } // end if Rsyn::Pin rsynPin = rsynCell.getInnerPin(); rsynPin.connect(rsynNet); } else { Rsyn::Cell rsynCell = rsynDesign.findCellByName(connection.instance); if (!rsynCell) { std::cout << "[ERROR] Cell '" << connection.instance << "' not found.\n"; exit(1); } // end if Rsyn::Pin rsynPin = rsynCell.getPinByName(connection.pin); rsynPin.connect(rsynNet); } // end else } // end for } // end for } // end method // ----------------------------------------------------------------------------- void PopulateRsyn::populateRsyn( const LefDscp &lefDscp, const DefDscp &defDscp, Rsyn::Design rsynDesign) { bool keepWarning; int keepWarningCounter; Rsyn::Module top = rsynDesign.getTopModule(); rsynDesign.updateName(defDscp.clsDesignName); // Create library cells. // Some cells (e.g. TIE) only appears in the LEF, not in the Liberty // at least for ICCAD 15 benchmarks. That's why we need to try to create // also cells using LEF. populateRsynLibraryFromLef(lefDscp, rsynDesign); // Creates ports. for (const DefPortDscp &port : defDscp.clsPorts) { const Rsyn::Direction direction = (port.clsDirection == "INPUT") ? Rsyn::IN : Rsyn::OUT; top.createPort(direction, port.clsName); } // end for // // Creates cells. for (const DefComponentDscp &component : defDscp.clsComps) { Rsyn::LibraryCell lcell = rsynDesign.findLibraryCellByName(component.clsMacroName); if (!lcell) { std::string str = "Library cell " + component.clsMacroName + " not found\n"; throw Exception(str); } // end if top.createCell(lcell, component.clsName); } // end for // Creates nets and connections. for (const DefNetDscp &net : defDscp.clsNets) { if (net.clsName == "") { std::cout << "[ERROR] Empty net name.\n"; for (unsigned i = 0; i < net.clsConnections.size(); i++) { std::cout << "Connection: " << net.clsConnections[i].clsComponentName << ":" << net.clsConnections[i].clsPinName << "\n"; } // end for exit(1); } // end if Rsyn::Net rsynNet = top.createNet(net.clsName); const std::string use = net.clsUse; if (use == "ANALOG") { rsynNet.setUse(Rsyn::ANALOG); } else if (use == "CLOCK") { rsynNet.setUse(Rsyn::CLOCK); } else if (use == "GROUND") { rsynNet.setUse(Rsyn::GROUND); } else if (use == "POWER") { rsynNet.setUse(Rsyn::POWER); } else if (use == "RESET") { rsynNet.setUse(Rsyn::RESET); } else if (use == "SCAN") { rsynNet.setUse(Rsyn::SCAN); } else if (use == "SIGNAL") { rsynNet.setUse(Rsyn::SIGNAL); } else if (use == "TIEOFF") { rsynNet.setUse(Rsyn::TIEOFF); } // end if for (const DefNetConnection &connection : net.clsConnections) { if (connection.clsComponentName == "PIN") { Rsyn::Port rsynCell = rsynDesign.findPortByName(connection.clsPinName); if (!rsynCell) { std::cout << "[ERROR] The primary input/ouput port '" << connection.clsPinName << "' not found.\n"; exit(1); } // end if Rsyn::Pin rsynPin = rsynCell.getInnerPin(); rsynPin.connect(rsynNet); } else { Rsyn::Cell rsynCell = rsynDesign.findCellByName(connection.clsComponentName); if (!rsynCell) { std::cout << "[ERROR] Cell '" << connection.clsComponentName << "' not found.\n"; exit(1); } // end if Rsyn::Pin rsynPin = rsynCell.getPinByName(connection.clsPinName); rsynPin.connect(rsynNet); } // end else } // end for } // end for for (const DefNetDscp &net : defDscp.clsSpecialNets) { if (net.clsName == "") { std::cout << "[ERROR] Empty net name.\n"; for (unsigned i = 0; i < net.clsConnections.size(); i++) { std::cout << "Connection: " << net.clsConnections[i].clsComponentName << ":" << net.clsConnections[i].clsPinName << "\n"; } // end for exit(1); } // end if Rsyn::Net rsynNet = top.createNet(net.clsName); const std::string use = net.clsUse; if (use == "ANALOG") { rsynNet.setUse(Rsyn::ANALOG); } else if (use == "CLOCK") { rsynNet.setUse(Rsyn::CLOCK); } else if (use == "GROUND") { rsynNet.setUse(Rsyn::GROUND); } else if (use == "POWER") { rsynNet.setUse(Rsyn::POWER); } else if (use == "RESET") { rsynNet.setUse(Rsyn::RESET); } else if (use == "SCAN") { rsynNet.setUse(Rsyn::SCAN); } else if (use == "SIGNAL") { rsynNet.setUse(Rsyn::SIGNAL); } else if (use == "TIEOFF") { rsynNet.setUse(Rsyn::TIEOFF); } // end if for (const DefNetConnection &connection : net.clsConnections) { if (connection.clsComponentName == "PIN") { Rsyn::Port rsynCell = rsynDesign.findPortByName(connection.clsPinName); if (!rsynCell) { std::cout << "[ERROR] The primary input/ouput port '" << connection.clsPinName << "' not found.\n"; exit(1); } // end if Rsyn::Pin rsynPin = rsynCell.getInnerPin(); rsynPin.connect(rsynNet); } else if (connection.clsComponentName == "*") { for (Rsyn::Instance inst: rsynDesign.getTopModule().allInstances()) { Rsyn::Pin rsynPin = inst.getPinByName(connection.clsPinName); if (!rsynPin) { continue; } // end if rsynPin.connect(rsynNet); } // end for } else { Rsyn::Cell rsynCell = rsynDesign.findCellByName(connection.clsComponentName); if (!rsynCell) { std::cout << "[ERROR] Cell '" << connection.clsComponentName << "' not found.\n"; exit(1); } // end if Rsyn::Pin rsynPin = rsynCell.getPinByName(connection.clsPinName); rsynPin.connect(rsynNet); } // end else } // end for } // end for } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/io/reader/PopulateRsyn.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PopulateRsyn.h * Author: jucemar * * Created on 18 de Fevereiro de 2017, 15:21 */ #ifndef RSYN_POPULATERSYN_H #define RSYN_POPULATERSYN_H #include "rsyn/phy/util/DefDescriptors.h" #include "rsyn/phy/util/LefDescriptors.h" #include "rsyn/core/Rsyn.h" #include "rsyn/io/legacy/PlacerInternals.h" #include "rsyn/io/legacy/Legacy.h" namespace Rsyn { class PopulateRsyn { public: PopulateRsyn() = default; PopulateRsyn(const PopulateRsyn& orig) = default; virtual ~PopulateRsyn() = default; protected: virtual void populateRsynLibraryFromLef( const LefDscp &lefDscp, Rsyn::Design rsynDesign); virtual void populateRsynNetlistFromVerilog( const Legacy::Design &verilogDesign, Rsyn::Design rsynDesign); virtual void populateRsyn( const LefDscp &lefDscp, const DefDscp &defDscp, const Legacy::Design &verilogDesign, Rsyn::Design rsynDesign); virtual void populateRsyn( const LefDscp &lefDscp, const DefDscp &defDscp, Rsyn::Design rsynDesign); }; } // end namespace #endif /* RSYN_POPULATERSYN_H */ ================================================ FILE: rsyn/src/rsyn/ispd18/Guide.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: Guide.h * Author: jucemar * * Created on 21 de Dezembro de 2016, 17:58 */ #ifndef ISPD18_GUIDE #define ISPD18_GUIDE #include #include namespace Rsyn { class LayerGuide { friend class RoutingGuide; friend class NetGuide; protected: Rsyn::PhysicalLayer clsPhLayer; Bounds clsBounds; int clsId; public: LayerGuide() = default; const Bounds & getBounds() const { return clsBounds; } // end method Rsyn::PhysicalLayer getLayer() const { return clsPhLayer; } // end method int getId() const { return clsId; } void setBounds(Bounds bounds) { clsBounds = bounds; } // end method void setLayer(Rsyn::PhysicalLayer layer) { clsPhLayer = layer; } // end method void setId(int id) { clsId = id; }//end method }; // end class class NetGuide { friend class RoutingGuide; protected: std::vector clsLayerGuides; public: NetGuide() = default; const LayerGuide& getGuide(int id) const { if(id > clsLayerGuides.size()) { std::cout << "Invalid access to net guide"; std::cout << "layer guide vector size is: " << clsLayerGuides.size() << ", index is: " << id << std::endl; getchar(); }// return clsLayerGuides[id]; } // end method const std::vector & allLayerGuides() const { return clsLayerGuides; } // end method void setLayerGuides(std::vector guides) { clsLayerGuides = guides; } }; // end class } // end namespace #endif /* ISPD18_ROUTINGGUIDE */ ================================================ FILE: rsyn/src/rsyn/ispd18/RoutingGuide.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: RoutingGuide.cpp * Author: jucemar * * Created on 21 de Dezembro de 2016, 17:47 */ #include "RoutingGuide.h" #include namespace Rsyn { void RoutingGuide::start(const Rsyn::Json ¶ms) { if(clsInitialized) return; clsDesign = clsSession.getDesign(); clsModule = clsSession.getTopModule(); clsPhDesign = clsSession.getPhysicalDesign(); clsGuides = clsDesign.createAttribute(); clsInitialized = true; } // end method // ----------------------------------------------------------------------------- void RoutingGuide::stop() { } // end method // ----------------------------------------------------------------------------- void RoutingGuide::loadGuides(const GuideDscp & dscp) { for (const GuideNetDscp & netDscp : dscp.clsNetGuides) { Rsyn::Net net = clsDesign.findNetByName(netDscp.clsNetName); if (net) { int id = 0; NetGuide & netGuide = clsGuides[net]; std::vector & layerGuides= netGuide.clsLayerGuides; layerGuides.reserve(netDscp.clsLayerDscps.size()); for (const GuideLayerDscp & layerDscp : netDscp.clsLayerDscps) { layerGuides.push_back(LayerGuide()); LayerGuide & layerGuide = layerGuides.back(); layerGuide.clsId = id++; layerGuide.clsBounds = layerDscp.clsLayerGuide; layerGuide.clsPhLayer = clsPhDesign.getPhysicalLayerByName(layerDscp.clsLayer); } // end for } else { std::cout << "WARNING: Net '" << netDscp.clsNetName << "' does not exist and the routing guide is being ignored.\n"; } // end else } // end for } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/ispd18/RoutingGuide.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: RoutingGuide.h * Author: jucemar * * Created on 21 de Dezembro de 2016, 17:47 */ #ifndef RSYN_ISPD18_ROUTING_GUIDE_H #define RSYN_ISPD18_ROUTING_GUIDE_H #include "rsyn/session/Service.h" #include #include "rsyn/ispd18/Guide.h" #include "rsyn/io/parser/guide-ispd18/GuideDescriptor.h" namespace Rsyn { class RoutingGuide : public Rsyn::Service { protected: Rsyn::Session clsSession; Rsyn::Design clsDesign; Rsyn::Module clsModule; Rsyn::PhysicalDesign clsPhDesign; Rsyn::Attribute clsGuides; bool clsInitialized = false; public: RoutingGuide() = default; void start(const Rsyn::Json ¶ms); void stop(); void loadGuides(const GuideDscp & dscp); const NetGuide & getGuide(Rsyn::Net net) const { return clsGuides[net]; } void updateGuide(Rsyn::Net net, Rsyn::NetGuide guide) { clsGuides[net] = guide; } }; // end class } // end namespace #endif /* ISPD18_ROUTINGGUIDE */ ================================================ FILE: rsyn/src/rsyn/phy/PhysicalDesign.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_PHYSICAL_DESIGN_H #define RSYN_PHYSICAL_DESIGN_H #include #include #include #include #include #include #include #include #include #include #include #include "rsyn/core/Rsyn.h" #include "rsyn/util/Bounds.h" #include "rsyn/util/FloatingPoint.h" #include "rsyn/util/dbu.h" #include "rsyn/util/Proxy.h" #include "rsyn/phy/util/DefDescriptors.h" #include "rsyn/phy/util/LefDescriptors.h" #include "rsyn/phy/util/PhysicalTypes.h" #include "rsyn/phy/util/PhysicalUtil.h" #include "rsyn/phy/util/PhysicalTransform.h" #include "rsyn/util/Exception.h" #include "rsyn/util/Json.h" namespace Rsyn { // std::numeric_limts::max() reserved to invalid initialization object. typedef std::uint32_t PhysicalIndex; static PhysicalIndex INVALID_PHYSICAL_INDEX = std::numeric_limits::max(); class PhysicalObject; class PhysicalRoutingPointData; class PhysicalDieData; class PhysicalGCellData; class PhysicalLayerData; class PhysicalSpacingData; class PhysicalSpacingRuleData; class PhysicalSpacingTableData; class PhysicalSiteData; class PhysicalRowData; class PhysicalObstacleData; class PhysicalPinLayerData; class PhysicalPinGeometryData; class PhysicalLibraryPinData; class PhysicalLibraryCellData; class PhysicalPinData; class PhysicalNetData; class PhysicalInstanceData; class PhysicalRegionData; class PhysicalGroupData; class PhysicalViaData; class ViaGeometryData; class ViaRuleData; class PhysicalSpecialWireData; class PhysicalSpecialNetData; class PhysicalTracksData; class PhysicalRoutingGridData; class LayerViaManagerData; class PhysicalDesignData; class PhysicalRoutingPoint; class PhysicalDie; class PhysicalGCell; class PhysicalLayer; class PhysicalSpacing; class PhysicalSite; class PhysicalRow; class PhysicalObstacle; class PhysicalPinLayer; class PhysicalPinGeometry; class PhysicalLibraryPin; class PhysicalLibraryCell; class PhysicalPin; class PhysicalNet; class PhysicalInstance; class PhysicalPort; class PhysicalCell; class PhysicalModule; class PhysicalRegion; class PhysicalGroup; class PhysicalVia; class PhysicalViaGeometry; class PhysicalViaRuleBase; class PhysicalViaRule; class PhysicalViaRuleGenerate; class PhysicalSpecialWire; class PhysicalSpecialNet; class PhysicalTracks; class PhysicalRoutingGrid; class LayerViaManager; class PhysicalDesign; class PhysicalAttributeInitializer; template class PhysicalAttributeInitializerWithDefaultValue; class PhysicalDesignObserver; class PhysicalRouting; } // end namespace // Object's Declarations (Proxies) #include "rsyn/phy/obj/decl/PhysicalRoutingPoint.h" #include "rsyn/phy/obj/decl/PhysicalDie.h" #include "rsyn/phy/obj/decl/PhysicalGCell.h" #include "rsyn/phy/obj/decl/PhysicalLayer.h" #include "rsyn/phy/obj/decl/PhysicalSpacing.h" #include "rsyn/phy/obj/decl/PhysicalSite.h" #include "rsyn/phy/obj/decl/PhysicalRow.h" #include "rsyn/phy/obj/decl/PhysicalPinLayer.h" #include "rsyn/phy/obj/decl/PhysicalPinGeometry.h" #include "rsyn/phy/obj/decl/PhysicalObstacle.h" #include "rsyn/phy/obj/decl/PhysicalLibraryPin.h" #include "rsyn/phy/obj/decl/PhysicalLibraryCell.h" #include "rsyn/phy/obj/decl/PhysicalPin.h" #include "rsyn/phy/obj/decl/PhysicalNet.h" #include "rsyn/phy/obj/decl/PhysicalInstance.h" #include "rsyn/phy/obj/decl/PhysicalCell.h" #include "rsyn/phy/obj/decl/PhysicalModule.h" #include "rsyn/phy/obj/decl/PhysicalPort.h" #include "rsyn/phy/obj/decl/PhysicalRegion.h" #include "rsyn/phy/obj/decl/PhysicalGroup.h" #include "rsyn/phy/obj/decl/PhysicalVia.h" #include "rsyn/phy/obj/decl/PhysicalViaGeometry.h" #include "rsyn/phy/obj/decl/PhysicalViaRuleBase.h" #include "rsyn/phy/obj/decl/PhysicalViaRule.h" #include "rsyn/phy/obj/decl/PhysicalViaRuleGenerate.h" #include "rsyn/phy/obj/decl/PhysicalSpecialWire.h" #include "rsyn/phy/obj/decl/PhysicalSpecialNet.h" #include "rsyn/phy/obj/decl/PhysicalTracks.h" #include "rsyn/phy/obj/decl/PhysicalRoutingGrid.h" #include "rsyn/phy/obj/decl/LayerViaManager.h" #include "rsyn/phy/obj/decl/PhysicalDesign.h" // Routing #include "rsyn/phy/PhysicalRouting.h" // Object's Data #include "rsyn/phy/obj/data/PhysicalObject.h" #include "rsyn/phy/obj/data/PhysicalRoutingPointData.h" #include "rsyn/phy/obj/data/PhysicalDieData.h" #include "rsyn/phy/obj/data/PhysicalGCellData.h" #include "rsyn/phy/obj/data/PhysicalLayerData.h" #include "rsyn/phy/obj/data/PhysicalSpacingData.h" #include "rsyn/phy/obj/data/PhysicalSpacingRuleData.h" #include "rsyn/phy/obj/data/PhysicalSpacingTableData.h" #include "rsyn/phy/obj/data/PhysicalSiteData.h" #include "rsyn/phy/obj/data/PhysicalRowData.h" #include "rsyn/phy/obj/data/PhysicalPinLayerData.h" #include "rsyn/phy/obj/data/PhysicalPinGeometryData.h" #include "rsyn/phy/obj/data/PhysicalObstacleData.h" #include "rsyn/phy/obj/data/PhysicalLibraryPinData.h" #include "rsyn/phy/obj/data/PhysicalLibraryCellData.h" #include "rsyn/phy/obj/data/PhysicalPinData.h" #include "rsyn/phy/obj/data/PhysicalNetData.h" #include "rsyn/phy/obj/data/PhysicalInstanceData.h" #include "rsyn/phy/obj/data/PhysicalRegionData.h" #include "rsyn/phy/obj/data/PhysicalGroupData.h" #include "rsyn/phy/obj/data/PhysicalViaData.h" #include "rsyn/phy/obj/data/ViaGeometryData.h" #include "rsyn/phy/obj/data/ViaRuleData.h" #include "rsyn/phy/obj/data/PhysicalSpecialWireData.h" #include "rsyn/phy/obj/data/PhysicalSpecialNetData.h" #include "rsyn/phy/obj/data/PhysicalTracksData.h" #include "rsyn/phy/obj/data/PhysicalRoutingGridData.h" #include "rsyn/phy/obj/data/LayerViaManagerData.h" #include "rsyn/phy/obj/data/PhysicalDesign.h" // Physical Infrastructure #include "rsyn/phy/infra/PhysicalAttribute.h" #include "rsyn/phy/infra/PhysicalObserver.h" // Object's Implementations #include "rsyn/phy/obj/impl/PhysicalRoutingPoint.h" #include "rsyn/phy/obj/impl/PhysicalLayer.h" #include "rsyn/phy/obj/impl/PhysicalDie.h" #include "rsyn/phy/obj/impl/PhysicalGCell.h" #include "rsyn/phy/obj/impl/PhysicalSpacing.h" #include "rsyn/phy/obj/impl/PhysicalSite.h" #include "rsyn/phy/obj/impl/PhysicalRow.h" #include "rsyn/phy/obj/impl/PhysicalPinLayer.h" #include "rsyn/phy/obj/impl/PhysicalPinGeometry.h" #include "rsyn/phy/obj/impl/PhysicalObstacle.h" #include "rsyn/phy/obj/impl/PhysicalLibraryPin.h" #include "rsyn/phy/obj/impl/PhysicalLibraryCell.h" #include "rsyn/phy/obj/impl/PhysicalPin.h" #include "rsyn/phy/obj/impl/PhysicalNet.h" #include "rsyn/phy/obj/impl/PhysicalInstance.h" #include "rsyn/phy/obj/impl/PhysicalPort.h" #include "rsyn/phy/obj/impl/PhysicalCell.h" #include "rsyn/phy/obj/impl/PhysicalModule.h" #include "rsyn/phy/obj/impl/PhysicalRegion.h" #include "rsyn/phy/obj/impl/PhysicalGroup.h" #include "rsyn/phy/obj/impl/PhysicalVia.h" #include "rsyn/phy/obj/impl/PhysicalViaGeometry.h" #include "rsyn/phy/obj/impl/PhysicalViaRuleBase.h" #include "rsyn/phy/obj/impl/PhysicalViaRule.h" #include "rsyn/phy/obj/impl/PhysicalViaRuleGenerate.h" #include "rsyn/phy/obj/impl/PhysicalSpecialWire.h" #include "rsyn/phy/obj/impl/PhysicalSpecialNet.h" #include "rsyn/phy/obj/impl/PhysicalTracks.h" #include "rsyn/phy/obj/impl/PhysicalRoutingGrid.h" #include "rsyn/phy/obj/impl/LayerViaManager.h" #include "rsyn/phy/obj/impl/PhysicalDesign.h" #endif /* PHYSICALDESIGN_PHYSICALDESIGN__H */ ================================================ FILE: rsyn/src/rsyn/phy/PhysicalRouting.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "PhysicalRouting.h" namespace Rsyn { // ----------------------------------------------------------------------------- // PhysicalRoutingWire // ----------------------------------------------------------------------------- PhysicalRoutingWire::PhysicalRoutingWire(const PhysicalRoutingWire & wire) { clsLayer = wire.clsLayer; clsPoints = wire.clsPoints; clsSourceExtension = wire.clsSourceExtension; clsTargetExtension = wire.clsTargetExtension; clsWidth = wire.clsWidth; } // end constructor // ----------------------------------------------------------------------------- DBUxy PhysicalRoutingWire::getExtendedSourcePosition() const { const int numPoints = getNumPoints(); if (numPoints == 0) { return DBUxy(0, 0); } else if (numPoints == 1) { return clsPoints[0]; } else { return getExtendedPosition(clsPoints[0], clsPoints[1], getSourceExtension()); } // end else } // end method // ----------------------------------------------------------------------------- DBUxy PhysicalRoutingWire::getExtendedTargetPosition() const { const int numPoints = getNumPoints(); if (numPoints == 0) { return DBUxy(0, 0); } else if (numPoints == 1) { return clsPoints[0]; } else { return getExtendedPosition(clsPoints[numPoints - 1], clsPoints[numPoints - 2], getTargetExtension()); } // end else } // end method // ----------------------------------------------------------------------------- DBU PhysicalRoutingWire::getSourceExtension() const { return clsSourceExtension == DefaultRoutingWireExtension? getLayer().getWidth() / 2 : clsSourceExtension; } // end method // ----------------------------------------------------------------------------- DBU PhysicalRoutingWire::getTargetExtension() const { return clsTargetExtension == DefaultRoutingWireExtension? getLayer().getWidth() / 2 : clsTargetExtension; } // end method // ----------------------------------------------------------------------------- std::vector PhysicalRoutingWire::getPoints(const bool useWireExtension) const { std::vector points = clsPoints; if (useWireExtension && getNumPoints() >= 1) { points.front() = getExtendedSourcePosition(); points.back() = getExtendedTargetPosition(); } // end method return points; } // end method // ----------------------------------------------------------------------------- bool PhysicalRoutingWire::hasNonDefaultWidth() const { return clsWidth != DefaultRoutingWireWidth && clsWidth != clsLayer.getWidth(); } // end method // ----------------------------------------------------------------------------- bool PhysicalRoutingWire::hasNonDefaultSourceExtension() const { return clsSourceExtension != DefaultRoutingWireExtension; } // end method // ----------------------------------------------------------------------------- bool PhysicalRoutingWire::hasNonDefaultTargetExtension() const { return clsTargetExtension != DefaultRoutingWireExtension; } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalLayer PhysicalRoutingWire::getLayer() const { return clsLayer; } // end method // ----------------------------------------------------------------------------- DBU PhysicalRoutingWire::getWidth() const { return clsWidth == DefaultRoutingWireWidth? getLayer().getWidth() : clsWidth; } // end method // ----------------------------------------------------------------------------- DBUxy PhysicalRoutingWire::getExtendedPosition( const DBUxy p0, const DBUxy p1, const DBU extension ) const { DBUxy pos = p0; const DBUxy d = p1 - p0; const bool horizontal = d.x != 0; const bool vertical = d.y != 0; if (horizontal && !vertical) { // Horizontal if (d.x > 0) { // p0.x < p1.x pos.x -= extension; } else { // p0.x > p1.x pos.x += extension; } // end else } else if (vertical && !horizontal) { // Vertical if (d.y > 0) { // p0.y < p1.y pos.y -= extension; } else { // p0.y > p1.y pos.y += extension; } // end else } // end else-if return pos; } // end method // ----------------------------------------------------------------------------- bool PhysicalRoutingWire::isValid() const { if (!getLayer() || getLayer().getType() != Rsyn::ROUTING) return false; if (getNumPoints() < 2) return false; return true; } // end method // ----------------------------------------------------------------------------- void PhysicalRoutingWire::addRoutingPoint(const DBUxy p) { clsPoints.push_back(p); } // end method // ----------------------------------------------------------------------------- void PhysicalRoutingWire::setLayer(Rsyn::PhysicalLayer layer) { clsLayer = layer; } // end method // ----------------------------------------------------------------------------- void PhysicalRoutingWire::clear() { *this = PhysicalRoutingWire(); } // end method // ----------------------------------------------------------------------------- bool PhysicalRoutingWire::convertToPolygon(Rsyn::Polygon &polygon) const { if (isValid()) { polygon = Polygon::createFromLineString(getPoints(true), getWidth()); return true; } else { polygon.clear(); return false; } // end else } // end method // ----------------------------------------------------------------------------- // PhysicalRoutingVia // ----------------------------------------------------------------------------- PhysicalRoutingVia::PhysicalRoutingVia(const PhysicalRoutingVia & via) { clsPosition = via.clsPosition; clsVia = via.clsVia; } // end constructor // ----------------------------------------------------------------------------- Rsyn::PhysicalVia PhysicalRoutingVia::getVia() const { return clsVia; } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalLayer PhysicalRoutingVia::getTopLayer() const { return clsVia.getTopLayer(); } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalLayer PhysicalRoutingVia::getCutLayer() const { return clsVia.getCutLayer(); } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalLayer PhysicalRoutingVia::getBottomLayer() const { return clsVia.getBottomLayer(); } // end method // ----------------------------------------------------------------------------- void PhysicalRoutingVia::setVia(Rsyn::PhysicalVia via) { clsVia = via; } // end method // ----------------------------------------------------------------------------- bool PhysicalRoutingVia::isValid() const { return clsVia != nullptr; } // end method // ----------------------------------------------------------------------------- // PhysicalRoutingRect // ----------------------------------------------------------------------------- PhysicalRoutingRect::PhysicalRoutingRect(const PhysicalRoutingRect & rect) { clsLayer = rect.clsLayer; clsRect = rect.clsRect; } // end constructor // ----------------------------------------------------------------------------- Rsyn::PhysicalLayer PhysicalRoutingRect::getLayer() const { return clsLayer; } // end method // ----------------------------------------------------------------------------- bool PhysicalRoutingRect::isValid() const { return clsLayer; } // end method // ----------------------------------------------------------------------------- void PhysicalRoutingRect::setLayer(Rsyn::PhysicalLayer layer) { clsLayer = layer; } // end method // ----------------------------------------------------------------------------- // PhysicalRouting // ----------------------------------------------------------------------------- PhysicalRouting::PhysicalRouting(const PhysicalRouting & routing) { clsWires = routing.clsWires; clsVias = routing.clsVias; clsRects = routing.clsRects; } // end constructor // ----------------------------------------------------------------------------- void PhysicalRouting::addWire(const PhysicalRoutingWire &wire) { assert(wire.isValid()); clsWires.push_back(wire); } // end method // ----------------------------------------------------------------------------- void PhysicalRouting::addWire( Rsyn::PhysicalLayer layer, const DBUxy source, const DBUxy target, const DBU width, const DBU sourceExtension, const DBU targetExtension ) { PhysicalRoutingWire wire; wire.setLayer(layer); wire.addRoutingPoint(source); wire.addRoutingPoint(target); wire.setWidth(width); wire.setSourceExtension(sourceExtension); wire.setTargetExtension(targetExtension); addWire(wire); } // end method // ----------------------------------------------------------------------------- void PhysicalRouting::addWire( Rsyn::PhysicalLayer layer, const std::vector &points, const DBU width, const DBU sourceExtension, const DBU targetExtension ) { PhysicalRoutingWire wire; wire.setLayer(layer); for (const DBUxy point : points) wire.addRoutingPoint(point); wire.setWidth(width); wire.setSourceExtension(sourceExtension); wire.setTargetExtension(targetExtension); addWire(wire); } // end method // ----------------------------------------------------------------------------- void PhysicalRouting::addVia( const PhysicalRoutingVia &via ) { clsVias.push_back(via); } // end method // ----------------------------------------------------------------------------- void PhysicalRouting::addVia( Rsyn::PhysicalVia physicalVia, const DBUxy position ) { PhysicalRoutingVia via; via.setVia(physicalVia); via.setPosition(position); addVia(via); } // end method // ----------------------------------------------------------------------------- void PhysicalRouting::addRect( const PhysicalRoutingRect &rect ) { clsRects.push_back(rect); } // end method // ----------------------------------------------------------------------------- void PhysicalRouting::addRect( Rsyn::PhysicalLayer layer, const Bounds &rect ) { PhysicalRoutingRect patch; patch.setLayer(layer); patch.setRect(rect); addRect(patch); } // end method // ----------------------------------------------------------------------------- bool PhysicalRouting::isValid() const { for (const PhysicalRoutingWire &wire : allWires()) { if (!wire.isValid()) { return false; } // end if } // end for for (const PhysicalRoutingVia &via : allVias()) { if (!via.isValid()) { return false; } // end if } // end for return !(clsWires.empty() && clsVias.empty()); } // end method // ----------------------------------------------------------------------------- bool PhysicalRouting::isEmpty() const { return clsWires.empty() && clsVias.empty() && clsRects.empty(); } // end method // ----------------------------------------------------------------------------- void PhysicalRouting::clear() { clsWires.clear(); clsVias.clear(); clsRects.clear(); } // end method // ----------------------------------------------------------------------------- DBU PhysicalRouting::computeWirelength() const { DBU wirelength = 0; for (Rsyn::PhysicalRoutingWire wire : allWires()) { wirelength += DBUxy::computeManhattanDistance(wire.allPoints()[0], wire.allPoints()[1]); } // end for return wirelength; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/PhysicalRouting.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_PHYSICAL_ROUTING_H #define RSYN_PHYSICAL_ROUTING_H #include #include "rsyn/util/dbu.h" #include "rsyn/util/Bounds.h" namespace Rsyn { class PhysicalLayer; class PhysicalVia; const DBU DefaultRoutingWireExtension = -1; const DBU DefaultRoutingWireWidth = -1; // ----------------------------------------------------------------------------- // PhysicalRoutingWire // ----------------------------------------------------------------------------- class PhysicalRoutingWire { public: PhysicalRoutingWire() {}; PhysicalRoutingWire(const PhysicalRoutingWire & wire); int getNumPoints() const {return (int) clsPoints.size();} DBUxy getExtendedSourcePosition() const; DBUxy getExtendedTargetPosition() const; DBU getWidth() const; DBU getSourceExtension() const; DBU getTargetExtension() const; std::vector getPoints(const bool useWireExtension) const; bool hasNonDefaultWidth() const; bool hasNonDefaultSourceExtension() const; bool hasNonDefaultTargetExtension() const; Rsyn::PhysicalLayer getLayer() const; bool isValid() const; void addRoutingPoint(const DBUxy p); void setLayer(Rsyn::PhysicalLayer layer); void setWidth(const DBU width) {clsWidth = width;} void setSourceExtension(const DBU extension) {clsSourceExtension = extension;} void setTargetExtension(const DBU extension) {clsTargetExtension = extension;} bool convertToPolygon(Rsyn::Polygon &polygon) const; void clear(); const std::vector &allPoints() const {return clsPoints;} private: DBUxy getExtendedPosition(const DBUxy p0, const DBUxy p1, const DBU extension) const; Rsyn::PhysicalLayer clsLayer; std::vector clsPoints; DBU clsSourceExtension = DefaultRoutingWireExtension; DBU clsTargetExtension = DefaultRoutingWireExtension; DBU clsWidth = DefaultRoutingWireWidth; }; // end class // ----------------------------------------------------------------------------- // PhysicalRoutingVia // ----------------------------------------------------------------------------- class PhysicalRoutingVia { public: PhysicalRoutingVia(){}; PhysicalRoutingVia(const PhysicalRoutingVia & via); Rsyn::PhysicalVia getVia() const; Rsyn::PhysicalLayer getTopLayer() const; Rsyn::PhysicalLayer getCutLayer() const; Rsyn::PhysicalLayer getBottomLayer() const; DBUxy getPosition() const {return clsPosition;} void setPosition(const DBUxy p) {clsPosition = p;} void setVia(Rsyn::PhysicalVia via); bool isValid() const; private: DBUxy clsPosition; Rsyn::PhysicalVia clsVia; }; // end class // ----------------------------------------------------------------------------- // PhysicalRoutingRect // ----------------------------------------------------------------------------- class PhysicalRoutingRect { public: PhysicalRoutingRect() {}; PhysicalRoutingRect(const PhysicalRoutingRect & rect); DBU getX() const {return clsRect.getX();} DBU getY() const { return clsRect.getY(); } DBU getWidth() const { return clsRect.getWidth(); } DBU getHeight() const { return clsRect.getHeight(); } const Bounds &getRect() const {return clsRect;} Rsyn::PhysicalLayer getLayer() const; bool isValid() const; void setRect(const Bounds &rect) {clsRect = rect;} void setLayer(Rsyn::PhysicalLayer layer); private: Bounds clsRect; Rsyn::PhysicalLayer clsLayer; }; // end class // ----------------------------------------------------------------------------- // PhysicalRouting // ----------------------------------------------------------------------------- class PhysicalRouting { public: PhysicalRouting() {} PhysicalRouting(const PhysicalRouting & routing); //! @brief Adds a wire. void addWire( const PhysicalRoutingWire &wire); //! @brief Adds a wire. void addWire( Rsyn::PhysicalLayer layer, const DBUxy source, const DBUxy target, const DBU width = DefaultRoutingWireWidth, const DBU sourceExtension = DefaultRoutingWireExtension, const DBU targetExtension = DefaultRoutingWireExtension); //! @brief Adds a wire. void addWire( Rsyn::PhysicalLayer layer, const std::vector &points, const DBU width = DefaultRoutingWireWidth, const DBU sourceExtension = DefaultRoutingWireExtension, const DBU targetExtension = DefaultRoutingWireExtension); //! @brief Adds a via. void addVia( const PhysicalRoutingVia &via); //! @brief Adds a via. void addVia( Rsyn::PhysicalVia via, const DBUxy position); //! @brief Adds a patch rectangle. void addRect( const PhysicalRoutingRect &rect); //! @brief Adds a patch rectangle. void addRect( Rsyn::PhysicalLayer layer, const Bounds &rect); //! @brief Checks if this physical routing is valid by visiting all routing //! elements (e.g. wires and vias) and checking if they are valid. bool isValid() const; //! @brief Checks if this physical routing is empty (i.e. no wires, vias, //! etc.) bool isEmpty() const; //! @brief Iterates over all wires. const std::vector & allWires() const {return clsWires;} //! @brief Iterates over all vias. const std::vector & allVias() const {return clsVias;} //! @brief Iterates over all patch rectangles. const std::vector & allRects() const {return clsRects;} //! @brief Removes all the wires, vias and rects. void clear(); //! @brief Computes net routed wirelength DBU computeWirelength() const; private: std::vector clsWires; std::vector clsVias; std::vector clsRects; }; // end class } // end namespace #endif /* PHYSICALROUTING_H */ ================================================ FILE: rsyn/src/rsyn/phy/PhysicalService.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "rsyn/phy/PhysicalService.h" namespace Rsyn { void PhysicalService::start(const Rsyn::Json ¶ms) { Rsyn::Session session; clsDesign = session.getDesign(); clsPhysicalDesign.initPhysicalDesign(clsDesign, params); // Observe changes in the design. clsDesign.registerObserver(this); } // end method // ----------------------------------------------------------------------------- void PhysicalService::stop() { } // end method // ----------------------------------------------------------------------------- void PhysicalService::onPostCellRemap(Rsyn::Cell cell, Rsyn::LibraryCell oldLibraryCell) { PhysicalDesignData *data = clsPhysicalDesign.data; PhysicalLibraryCellData &oldPhysicalLibraryCell = data->clsPhysicalLibraryCells[oldLibraryCell]; PhysicalLibraryCellData &newPhysicalLibraryCell = data->clsPhysicalLibraryCells[cell.getLibraryCell()]; PhysicalInstanceData &physicalCell = data->clsPhysicalInstances[cell]; const DBU newWidth = newPhysicalLibraryCell.clsSize[X]; const DBU newHeight = newPhysicalLibraryCell.clsSize[Y]; const DBU oldWidth = oldPhysicalLibraryCell.clsSize[X]; const DBU oldHeight = oldPhysicalLibraryCell.clsSize[Y]; // Update physical cell size. physicalCell.clsInstance->clsBounds.setLength(X, newWidth); physicalCell.clsInstance->clsBounds.setLength(Y, newHeight); // Update area. const DBU oldArea = oldWidth * oldHeight; if (physicalCell.clsBlock) data->clsTotalAreas[PHYSICAL_BLOCK] -= oldArea; if (cell.isFixed()) { if (cell.isPort()) data->clsTotalAreas[PHYSICAL_PORT] -= oldArea; else data->clsTotalAreas[PHYSICAL_FIXED] -= oldArea; } else { data->clsTotalAreas[PHYSICAL_MOVABLE] -= oldArea; } // end if-else const DBU newArea = newWidth * newHeight; if (physicalCell.clsBlock) data->clsTotalAreas[PHYSICAL_BLOCK] += newArea; if (cell.isFixed()) { if (cell.isPort()) data->clsTotalAreas[PHYSICAL_PORT] += newArea; else data->clsTotalAreas[PHYSICAL_FIXED] += newArea; } else { data->clsTotalAreas[PHYSICAL_MOVABLE] += newArea; } // end if-else } // end method // ----------------------------------------------------------------------------- void PhysicalService::onPostInstanceCreate(Rsyn::Instance instance) { if (instance.getType() != Rsyn::CELL) { std::cout << "[WARNING] Created instance is not a cell.\n"; return; } // end if PhysicalDesignData *data = clsPhysicalDesign.data; PhysicalLibraryCellData &physicalLibraryCell = data->clsPhysicalLibraryCells[instance.asCell().getLibraryCell()]; PhysicalInstanceData &physicalCell = data->clsPhysicalInstances[instance.asCell()]; physicalCell.clsInstance = instance; Rsyn::InstanceTag tag = clsDesign.getTag(instance); tag.setFixed(false); tag.setMacroBlock(!strcmp(physicalLibraryCell.clsMacro->macroClass(), "BLOCK")); physicalCell.clsHasLayerBounds = false; physicalCell.clsPlaced = true; physicalCell.clsBlock = false; physicalCell.clsInstance->clsOrientation = PhysicalOrientation::ORIENTATION_N; const DBUxy dieOrigin = data->clsPhysicalDie.clsBounds[LOWER]; physicalCell.clsInitialPos = DBUxy(dieOrigin); const DBU width = physicalLibraryCell.clsSize[X]; const DBU height = physicalLibraryCell.clsSize[Y]; physicalCell.clsInstance->clsBounds.updatePoints( dieOrigin.x, dieOrigin.y, dieOrigin.x + width, dieOrigin.y + height); DBU area = width * height; data->clsTotalAreas[PHYSICAL_MOVABLE] += area; } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/PhysicalService.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_PHYSICAL_SERVICE_H #define RSYN_PHYSICAL_SERVICE_H #include "rsyn/session/Service.h" #include namespace Rsyn { class PhysicalService : public Rsyn::Service, public DesignObserver { private: Rsyn::PhysicalDesign clsPhysicalDesign; Rsyn::Design clsDesign; public: //! @brief Start method to the Rsyn::PhysicalDesign service virtual void start(const Rsyn::Json ¶ms); //! @brief Stop method to the Rsyn::PhysicalDesign service virtual void stop(); //! @brief Getting the Rsyn::PhysicalDesign object. Rsyn::PhysicalDesign getPhysicalDesign() { return clsPhysicalDesign; } // Events virtual void onPostCellRemap(Rsyn::Cell cell, Rsyn::LibraryCell oldLibraryCell) override; virtual void onPostInstanceCreate(Rsyn::Instance instance) override; }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/phy/infra/PhysicalAttribute.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_PHYSICALDESIGN_ATTRIBUTE_H #define RSYN_PHYSICALDESIGN_ATTRIBUTE_H #include namespace Rsyn { class PhysicalAttributeInitializer { friend class PhysicalDesign; private: PhysicalDesign design; PhysicalAttributeInitializer(PhysicalDesign design) : design(design) { }; public: PhysicalDesign getPhysicalDesign() { return design; } // end method }; // end class // ----------------------------------------------------------------------------- template class PhysicalAttributeInitializerWithDefaultValue { friend class PhysicalDesign; private: PhysicalDesign design; PhysicalDefaultValueType defaultValue; PhysicalAttributeInitializerWithDefaultValue(PhysicalDesign design, PhysicalDefaultValueType defaultValue) : design(design), defaultValue(defaultValue) { }; public: PhysicalDesign getPhysicalDesign() { return design; } PhysicalDefaultValueType &getDefaultValue() { return defaultValue; } }; // end class // ----------------------------------------------------------------------------- template class PhysicalAttributeImplementation; // ----------------------------------------------------------------------------- template class PhysicalAttribute : public std::shared_ptr> { public: PhysicalAttribute() { } PhysicalAttribute(PhysicalAttributeInitializer initializer) { operator=(initializer); } void operator=(PhysicalAttributeInitializer initializer); template PhysicalAttribute(PhysicalAttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(PhysicalAttributeInitializerWithDefaultValue initializer); RsynPhysicalObjectExtension &operator[](RsynPhysicalObject obj); const RsynPhysicalObjectExtension &operator[](RsynPhysicalObject obj) const; }; // end class // ----------------------------------------------------------------------------- template class PhysicalAttributeBase { private: // [TODO] Make design and list const. PhysicalDesign clsPhysicalDesign; List<_PhysicalObject> *clsListPtr; _PhysicalObjectExtension clsDefaultValue; typename List<_PhysicalObject>::CreateElementCallbackHandler clsHandlerOnCreate; typename List<_PhysicalObject>::DestructorCallbackHandler clsListDestructorCallbackHandler; std::deque<_PhysicalObjectExtension> clsData; void accommodate(const Index index) { if (index >= clsData.size()) { clsData.resize(index + 1, clsDefaultValue); } // end if } // end method protected: void setupCallbacks() { clsHandlerOnCreate = clsListPtr->addCreateCallback([&](const int index) { accommodate(clsListPtr->largestId()); }); // end method clsListDestructorCallbackHandler = clsListPtr->addDestructorEventCallback([&]() { clsListPtr = nullptr; }); // end method } // end method void load(PhysicalDesign design, List<_PhysicalObject> &list, _PhysicalObjectExtension defaultValue = _PhysicalObjectExtension()) { clsPhysicalDesign = design; clsListPtr = &list; clsDefaultValue = defaultValue; accommodate(clsListPtr->largestId()); setupCallbacks(); } // end method public: PhysicalAttributeBase() : clsPhysicalDesign(nullptr), clsListPtr(nullptr) { } // end constructor PhysicalAttributeBase(const PhysicalAttributeBase<_PhysicalObject, _PhysicalObjectReference, _PhysicalObjectExtension> &other) { operator=(other); } // end constructor PhysicalAttributeBase(PhysicalDesign design, List<_PhysicalObject> &list) { load(design, list); } // end constructor PhysicalAttributeBase<_PhysicalObject, _PhysicalObjectReference, _PhysicalObjectExtension> & operator=(const PhysicalAttributeBase<_PhysicalObject, _PhysicalObjectReference, _PhysicalObjectExtension> &other) { unload(); clsPhysicalDesign = other.clsPhysicalDesign; clsListPtr = other.clsListPtr; clsData = other.clsData; // When a layer gets copied, we need to setup new callbacks. setupCallbacks(); return *this; } // end method ~PhysicalAttributeBase() { unload(); } // end constructor void unload() { if (clsPhysicalDesign) { clsPhysicalDesign = nullptr; } // end if if (clsListPtr) { clsListPtr->deleteCreateCallback(clsHandlerOnCreate); clsListPtr->deleteDestructorCallback(clsListDestructorCallbackHandler); clsListPtr = nullptr; } // end if clsData.clear(); clsData.shrink_to_fit(); } // end method inline _PhysicalObjectExtension &operator[](_PhysicalObjectReference obj) { return clsData[clsPhysicalDesign.getId(obj)]; } inline const _PhysicalObjectExtension &operator[](_PhysicalObjectReference obj) const { return clsData[clsPhysicalDesign.getId(obj)]; } }; // end class //////////////////////////////////////////////////////////////////////////////// // PhysicalAttribute Layer: (Generic) - Internal Use Only //////////////////////////////////////////////////////////////////////////////// template class PhysicalAttributeImplementation { }; // end class //////////////////////////////////////////////////////////////////////////////// // PhysicalAttribute Layer: PhysicalRow //////////////////////////////////////////////////////////////////////////////// template class PhysicalAttributeImplementation : public Rsyn::PhysicalAttributeBase { public: PhysicalAttributeImplementation() { } PhysicalAttributeImplementation(PhysicalAttributeInitializer initializer) { operator=(initializer); } void operator=(PhysicalAttributeInitializer initializer) { PhysicalDesign design = initializer.getPhysicalDesign(); PhysicalAttributeBase::load(design, design.data->clsPhysicalRows); } // end operator template PhysicalAttributeImplementation(PhysicalAttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(PhysicalAttributeInitializerWithDefaultValue initializer) { PhysicalDesign design = initializer.getPhysicalDesign(); PhysicalAttributeBase::load(design, design.data->clsPhysicalRows, initializer.getDefaultValue()); } // end operator }; // end class //////////////////////////////////////////////////////////////////////////////// // PhysicalAttribute Layer: PhysicalLayer //////////////////////////////////////////////////////////////////////////////// template class PhysicalAttributeImplementation : public Rsyn::PhysicalAttributeBase { public: PhysicalAttributeImplementation() { } PhysicalAttributeImplementation(PhysicalAttributeInitializer initializer) { operator=(initializer); } void operator=(PhysicalAttributeInitializer initializer) { PhysicalDesign design = initializer.getPhysicalDesign(); PhysicalAttributeBase::load(design, design.data->clsPhysicalLayers); } // end operator template PhysicalAttributeImplementation(PhysicalAttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(PhysicalAttributeInitializerWithDefaultValue initializer) { PhysicalDesign design = initializer.getPhysicalDesign(); PhysicalAttributeBase::load(design, design.data->clsPhysicalLayers, initializer.getDefaultValue()); } // end operator }; // end class //////////////////////////////////////////////////////////////////////////////// // PhysicalAttribute Layer: PhysicalSpacing //////////////////////////////////////////////////////////////////////////////// template class PhysicalAttributeImplementation : public Rsyn::PhysicalAttributeBase { public: PhysicalAttributeImplementation() { } PhysicalAttributeImplementation(PhysicalAttributeInitializer initializer) { operator=(initializer); } void operator=(PhysicalAttributeInitializer initializer) { PhysicalDesign design = initializer.getPhysicalDesign(); PhysicalAttributeBase::load(design, design.data->clsPhysicalSpacing); } // end operator template PhysicalAttributeImplementation(PhysicalAttributeInitializerWithDefaultValue initializer) { operator=(initializer); } template void operator=(PhysicalAttributeInitializerWithDefaultValue initializer) { PhysicalDesign design = initializer.getPhysicalDesign(); PhysicalAttributeBase::load(design, design.data->clsPhysicalSpacing, initializer.getDefaultValue()); } // end operator }; // end class //////////////////////////////////////////////////////////////////////////////// // PhysicalAttribute //////////////////////////////////////////////////////////////////////////////// template inline void PhysicalAttribute::operator=(PhysicalAttributeInitializer initializer) { this->reset(new PhysicalAttributeImplementation(initializer)); } // end method template template inline void PhysicalAttribute::operator=(PhysicalAttributeInitializerWithDefaultValue initializer) { this->reset(new PhysicalAttributeImplementation(initializer)); } // end method template inline RsynPhysicalObjectExtension &PhysicalAttribute::operator[](RsynPhysicalObject obj) { return (*this)->operator[](obj); } // end method template inline const RsynPhysicalObjectExtension &PhysicalAttribute::operator[](RsynPhysicalObject obj) const { return (*this)->operator[](obj); } // end method } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/phy/infra/PhysicalObserver.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_PHYSICAL_OBSERVER_H #define RSYN_PHYSICAL_OBSERVER_H namespace Rsyn { class PhysicalDesignObserver { friend class Rsyn::PhysicalDesign; private: PhysicalDesign clsPhDesign; public: // Note: The observer will not be registered to receive notifications for // methods that it does not overwrite. Therefore, no runtime overhead for // handling undesired notifications. virtual void onPhysicalDesignDestruction() {} virtual void onPostNetRoutingChange(Rsyn::PhysicalNet physicalNet) {} virtual ~PhysicalDesignObserver() { if (clsPhDesign) clsPhDesign.unregisterObserver(this); } // end destructor }; // end class } // end namespace #endif /* RSYN_PHYSICALOBSERVER_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/LayerViaManagerData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalLayerViaManagerData.h * Author: jucemar * * Created on February 3, 2018, 9:17 AM */ #ifndef PHYSICALLAYERVIAMANAGERDATA_H #define PHYSICALLAYERVIAMANAGERDATA_H namespace Rsyn { class LayerViaManagerData : public PhysicalObject { public: std::map> clsVias; std::map> clsBottomVias; std::map> clsTopVias; LayerViaManagerData() = default; }; // end class } // end namespace #endif /* PHYSICALLAYERVIAMANAGERDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalDesign.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_PHYSICALDESIGN_PHYSICALDESIGNDATA_H #define RSYN_PHYSICALDESIGN_PHYSICALDESIGNDATA_H namespace Rsyn { class PhysicalDesignData : public PhysicalObject { friend class PhysicalDesign; public: Rsyn::Design clsDesign; Rsyn::Module clsModule; Rsyn::LayerViaManagerData clsLayerViaManager; std::list> callbackAddCreatePhysicalCell; std::list> callbackOnPreCellRemoveEvent; Rsyn::Attribute clsPhysicalLibraryPins; Rsyn::Attribute clsPhysicalPins; Rsyn::Attribute clsPhysicalInstances; Rsyn::Attribute clsPhysicalLibraryCells; Rsyn::Attribute clsPhysicalNets; Rsyn::List clsPhysicalRows; Rsyn::List clsPhysicalLayers; Rsyn::List clsPhysicalSpacing; std::vector clsPhysicalRegions; std::vector clsPhysicalGroups; std::vector clsPhysicalSites; std::vector clsPhysicalVias; std::vector clsPhysicalViaRuleBases; std::vector clsPhysicalViaRules; std::vector clsPhysicalViaRuleGenerates; std::vector clsPhysicalSpecialNets; std::vector clsPhysicalTracks; std::vector clsPhysicalGCell; std::vector clsPhysicalRoutingGrids; std::unordered_map clsMapPhysicalSites; std::unordered_map clsMapPhysicalRegions; std::unordered_map clsMapPhysicalGroups; std::unordered_map clsMapPhysicalSpecialNets; std::map> clsMapLayerToTracks; std::map clsMapLayerToRoutingGrid; //From LEF file std::unordered_map clsMapPhysicalLayers; std::unordered_map clsMapPhysicalVias; std::unordered_map clsMapPhysicalViaRuleBases; std::vector clsPhysicalRoutingLayerIndeces; //std::vector clsPhysicalSpacing; Rsyn::PhysicalDieData clsPhysicalDie; // total area of the circuit including core bound. DBU clsTotalAreas[NUM_PHYSICAL_TYPES]; int clsNumElements[NUM_PHYSICAL_TYPES]; int clsNumLayers[NUM_PHY_LAYER]; DBUxy clsHPWL; DBU clsDBUs[NUM_DBU]; // LEF and DEF data base units resolution and DEF/LEF multiplier factor bool clsLoadDesign : 1; bool clsEnablePhysicalPins : 1; bool clsEnableMergeRectangles : 1; bool clsEnableNetPinBoundaries : 1; Rsyn::Net clsClkNet; // Physical design mode PhysicalDesignMode clsMode = PhysicalDesignMode::ALL; //////////////////////////////////////////////////////////////////////////// // Observerss //////////////////////////////////////////////////////////////////////////// std::array, NUM_PHYSICAL_EVENTS> clsPhysicalObservers; PhysicalDesignData() : clsClkNet(nullptr), clsDesign(nullptr), clsModule(nullptr) { clsLoadDesign = false; clsEnablePhysicalPins = false; clsEnableMergeRectangles = false; clsEnableNetPinBoundaries = false; for (int index = 0; index < NUM_DBU; index++) { clsDBUs[index] = 0; } // end for for (int index = 0; index < NUM_PHYSICAL_TYPES; index++) { clsTotalAreas[index] = 0.0; clsNumElements[index] = 0; } // end for for (int index = 0; index < NUM_PHY_LAYER; index++) { clsNumLayers[index] = 0; } } // end constructor }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalDieData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalDieData.h * Author: jucemar * * Created on 4 de Fevereiro de 2017, 08:40 */ #ifndef PHYSICALDESIGN_PHYSICALDIEDATA_H #define PHYSICALDESIGN_PHYSICALDIEDATA_H namespace Rsyn { class PhysicalDieData { friend class PhysicalDesign; public: //! @brief Rectangular PhysicalDie Bounds in DBU units. Bounds clsBounds; //! @brief It constructs the default Bounds(DBUxy(0,0), DBUxy(0,0)). PhysicalDieData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALDIEDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalGCellData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef PHYSICALGCELLDATA_H #define PHYSICALGCELLDATA_H namespace Rsyn { class PhysicalGCellData { friend class PhysicalDesign; public: //! @brief Direction of the GCell //! HORIZONTAL is equal to Y in DEF and VERTICAL is equal to X in DEF PhysicalGCellDirection clsDirection; //! @brief Each GCELLGRID statement specifies the location of the first vertical (x) and first horizontal (y) track. Source: DEF Manual. DBU clsLocation = 0; //! @brief Specifies the number of columns in the grid if Direction is VERTICAL //! Specifies the number of rows in the grid if Direction is HORIZONTAL int clsNumTracks = 0; //! @brief Specifies the spacing between tracks. DBU clsStep = 0; //! @brief default constructor PhysicalGCellData() = default; }; // end class } // end namespace #endif /* PHYSICALGCELLDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalGroupData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalGroupData.h * Author: jucemar * * Created on 09 de Abril de 2017, 16:45 */ #ifndef PHYSICALDESIGN_PHYSICALGROUPDATA_H #define PHYSICALDESIGN_PHYSICALGROUPDATA_H namespace Rsyn { class PhysicalGroupData : public PhysicalObject { public: std::string clsName = Rsyn::getPhysicalInvalidName(); std::vector clsPatterns; // e.g. "name/*" Rsyn::PhysicalRegion clsRegion; PhysicalGroupData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALGROUPDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalInstanceData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalCellData.h * Author: jucemar * * Created on 12 de Setembro de 2016, 21:01 */ #ifndef PHYSICALDESIGN_PHYSICALINSTANCEDATA_H #define PHYSICALDESIGN_PHYSICALINSTANCEDATA_H namespace Rsyn { class PhysicalInstanceData { friend class PhysicalDesign; public: bool clsBlock : 1; bool clsPlaced : 1; bool clsPort : 1; bool clsHasLayerBounds : 1; // the bounds of a cell is defined by one of the layers. DBUxy clsInitialPos; // Initial position from global placement when in detailed placement has maximal displacement PhysicalLayer clsPortLayer; Rsyn::Instance clsInstance; PhysicalInstanceData() { clsBlock = false; clsPlaced = false; clsPort = false; clsHasLayerBounds = false; } // end constructor }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALINSTANCEDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalLayerData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalLayerData.h * Author: jucemar * * Created on 13 de Setembro de 2016, 19:09 */ #ifndef PHYSICALDESIGN_PHYSICALLAYERDATA_H #define PHYSICALDESIGN_PHYSICALLAYERDATA_H namespace Rsyn { class PhysicalLayerData : public PhysicalObject { public: lefiLayer* clsLayer = nullptr; DBU clsWidth = 0; int clsIndex = -1; int clsRelativeIndex = -1; Rsyn::PhysicalLayerType clsType = INVALID_PHY_LAYER_TYPE; std::string clsName = Rsyn::getPhysicalInvalidName(); Rsyn::PhysicalLayerData * clsLower = nullptr; Rsyn::PhysicalLayerData * clsUpper = nullptr; PhysicalLayerData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALLAYERDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalLibraryCellData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalLibraryCellData.h * Author: jucemar * * Created on 12 de Setembro de 2016, 22:08 */ #ifndef PHYSICALDESIGN_PHYSICALLIBRARYCELLDATA_H #define PHYSICALDESIGN_PHYSICALLIBRARYCELLDATA_H namespace Rsyn { class PhysicalLibraryCellData { public: lefiMacro* clsMacro = nullptr; PhysicalSite clsMacroSite; DBUxy clsSize; int clsLayerBoundIndex = -1; // The cell bound is defined by one of the layers. std::vector clsObs; Polygon clsPolygonBounds; Rsyn::PhysicalObstacle clsTopLayerObs; PhysicalLibraryCellData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALLIBRARYCELLDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalLibraryPinData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalLibraryPinData.h * Author: jucemar * * Created on 13 de Setembro de 2016, 21:04 */ #ifndef PHYSICALDESIGN_PHYSICALLIBRARYPINDATA_H #define PHYSICALDESIGN_PHYSICALLIBRARYPINDATA_H namespace Rsyn { class PhysicalLibraryPinData { public: Bounds clsLayerBound; // The layer bound is defined by one of the layer. PhysicalLibraryCell clsLibraryCell; PhysicalPinUse clsUse = PIN_INVALID_USE; PhysicalPinDirection clsDirection = PIN_INVALID_DIRECTION; // A pin may have several ports. However, each port is weakly connected to other. // It is assumed that they have high resistance among them. std::vector clsPhysicalPinGeometries; PhysicalLibraryPinData() = default; }; // class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALLIBRARYPINDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalNetData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalNetData.h * Author: jucemar * * Created on 15 de Setembro de 2016, 19:15 */ #ifndef RSYN_PHYSICAL_NET_DATA_H #define RSYN_PHYSICAL_NET_DATA_H namespace Rsyn { class PhysicalNetData { public: Bounds clsBounds; Rsyn::Net clsNet; Rsyn::Pin clsBoundPins[2][2]; PhysicalRouting clsRouting; PhysicalNetData() { clsBoundPins[LOWER][X] = nullptr; clsBoundPins[LOWER][Y] = nullptr; clsBoundPins[UPPER][X] = nullptr; clsBoundPins[UPPER][Y] = nullptr; } // end constructor }; // end class } // end class #endif ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalObject.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalObject.h * Author: jucemar * * Created on 12 de Setembro de 2016, 19:59 */ #ifndef PHYSICALDESIGN_PHYSICALOBJECT_H #define PHYSICALDESIGN_PHYSICALOBJECT_H namespace Rsyn { class PhysicalObject { public: //! @brief Unique identifier of the Physical Objects. //! @details It is used to avoid compare pointer when sorting physical objects. //! The id variable is protected from users access outside of Physical classes. PhysicalIndex id = INVALID_PHYSICAL_INDEX; PhysicalObject() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALOBJECT_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalObstacleData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalObstacleData.h * Author: jucemar * * Created on 13 de Setembro de 2016, 20:02 */ #ifndef PHYSICALDESIGN_PHYSICALOBSTACLEDATA_H #define PHYSICALDESIGN_PHYSICALOBSTACLEDATA_H namespace Rsyn { class PhysicalObstacleData : public PhysicalObject { public: Rsyn::PhysicalLayer clsLayer; std::vector clsBounds; PhysicalObstacleData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALOBSTACLEDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalPinData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPinData.h * Author: jucemar * * Created on 14 de Setembro de 2016, 21:24 */ #ifndef PHYSICALDESIGN_PHYSICALPINDATA_H #define PHYSICALDESIGN_PHYSICALPINDATA_H namespace Rsyn { class PhysicalPinData { public: DBUxy clsDisplacement; //! @details A pin may have several ports. However, each port is weakly connected to other. //! It is assumed that they have high resistance among them. std::vector clsPhysicalPinGeometries; PhysicalPinDirection clsDirection = PIN_INVALID_DIRECTION; Bounds clsLayerBound; // The pin bounds is defined by one of the layers PhysicalPinData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALPINDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalPinGeometryData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPinGeometryData.h * Author: jucemar * * Created on 13 de Setembro de 2016, 21:10 */ #ifndef PHYSICALDESIGN_PHYSICALPINGEOMETRYDATA_H #define PHYSICALDESIGN_PHYSICALPINGEOMETRYDATA_H namespace Rsyn { class PhysicalPinGeometryData : public PhysicalObject { public: //! @brief An enum PhysicalPinGeometryClass that determines the class of the PhysicalPinGeometry object. PhysicalPinGeometryClass clsPinPortClass = PINGEOMETRYCLASS_NONE; //! @brief PhysicalPinLayers associated to the PhysicalPinGeometry. std::vector clsPinLayers; //! @brief Default constructor. //! @details Users do not have access to this constructor. The reference to //! PhysicalPinGeometryData is a protected variable in PhysicalPinGeometry. PhysicalPinGeometryData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALPINGEOMETRYDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalPinLayerData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPinLayerData.h * Author: jucemar * * Created on 13 de Setembro de 2016, 21:16 */ #ifndef PHYSICALDESIGN_PHYSICALPINLAYERDATA_H #define PHYSICALDESIGN_PHYSICALPINLAYERDATA_H namespace Rsyn { class PhysicalPinLayerData : public PhysicalObject { public: std::vector clsBounds; std::vector clsPolygons; Rsyn::PhysicalLayer clsLibLayer; PhysicalPinLayerData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALPINLAYERDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalRegionData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalRegionData.h * Author: jucemar * * Created on 09 de Abril de 2017, 14:55 */ #ifndef PHYSICALDESIGN_PHYSICALREGIONDATA_H #define PHYSICALDESIGN_PHYSICALREGIONDATA_H namespace Rsyn { class PhysicalRegionData : public PhysicalObject { public: std::string clsName = Rsyn::getPhysicalInvalidName(); RegionType clsType = RegionType::INVALID; // FENCE or GUIDE std::vector clsBounds; PhysicalRegionData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALREGIONDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalRoutingGridData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalRoutingGridData.h * Author: jucemar * * Created on February 2, 2018, 9:00 PM */ #ifndef PHYSICALROUTINGGRIDDATA_H #define PHYSICALROUTINGGRIDDATA_H namespace Rsyn { class PhysicalRoutingGridData : public PhysicalObject { friend class PhysicalDesign; public: std::vector clsTracks; Rsyn::PhysicalLayer clsLayer; DBUxy clsSpacing; int clsNumTracks[2]; Bounds clsBounds; Rsyn::PhysicalRoutingGrid clsBottomRoutingGrid; Rsyn::PhysicalRoutingGrid clsTopRoutingGrid; PhysicalRoutingGridData() = default; }; // end class } // end namespace #endif /* PHYSICALROUTINGGRIDDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalRoutingPointData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalRoutingPointData.h * Author: jucemar * * Created on 23 de Maio de 2017, 20:27 */ #ifndef PHYSICALDESIGN_PHYSICALROUTINGPOINTDATA_H #define PHYSICALDESIGN_PHYSICALROUTINGPOINTDATA_H namespace Rsyn { class PhysicalRoutingPointData : public PhysicalObject { public: PhysicalVia clsVia; DBUxy clsPos; Bounds clsRectangle; DBU clsExtension = -1; PhysicalOrientation clsOrientation = ORIENTATION_N; // default routing point orientation bool clsHasRectangle : 1; bool clsHasMask : 1; bool clsHasVirtual : 1; PhysicalRoutingPointData() { clsHasRectangle = false; clsHasMask = false; clsHasVirtual = false; } // end constructor }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALROUTINGPOINTDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalRowData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalRowData.h * Author: jucemar * * Created on 14 de Setembro de 2016, 22:26 */ #ifndef PHYSICALDESIGN_PHYSICALROWDATA_H #define PHYSICALDESIGN_PHYSICALROWDATA_H namespace Rsyn { class PhysicalRowData : public PhysicalObject { public: Bounds clsBounds; PhysicalSite clsPhysicalSite; PhysicalOrientation clsSiteOrientation = Rsyn::PhysicalOrientation::ORIENTATION_INVALID; DBUxy clsOrigin; int clsNumSites[2] = {0, 0}; DBUxy clsStep; std::string clsRowName; PhysicalRowData() { clsRowName = Rsyn::getPhysicalInvalidName(); } // end constructor // these methods are required in several parts of Physical Design. // Therefore, they are provided by physical row data // another solution was to create a variable to store each information. inline DBU getWidth() const { return clsNumSites[X] * clsStep[X]; } // end method inline DBU getHeight() const { return clsNumSites[Y] * clsStep[Y]; } // end method }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALROWDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalSiteData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSiteData.h * Author: jucemar * * Created on 12 de Setembro de 2016, 22:44 */ #ifndef PHYSICALDESIGN_PHYSICALSITEDATA_H #define PHYSICALDESIGN_PHYSICALSITEDATA_H namespace Rsyn { class PhysicalSiteData : public PhysicalObject { public: Rsyn::PhysicalSiteClass clsSiteClass = INVALID_SITECLASS; DBUxy clsSize; std::string clsSiteName = Rsyn::getPhysicalInvalidName(); Rsyn::PhysicalSymmetry clsSymmetry = Rsyn::PhysicalSymmetry::SYMMETRY_INVALID; PhysicalSiteData() = default; }; // end namespace } // end namespace #endif /* PHYSICALDESIGN_PHYSICALSITEDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalSpacingData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSpacingData.h * Author: jucemar * * Created on 15 de Setembro de 2016, 18:55 */ #ifndef PHYSICALDESIGN_PHYSICALSPACINGDATA_H #define PHYSICALDESIGN_PHYSICALSPACINGDATA_H namespace Rsyn { class PhysicalSpacingData : public PhysicalObject { public: PhysicalLayer clsLayer1; PhysicalLayer clsLayer2; DBU clsDistance = 0; PhysicalSpacingData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALSPACINGDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalSpacingRuleData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSpacingRuleData.h * Author: jucemar * * Created on 17 de dezembro de 2017, 14:10 */ #ifndef PHYSICALDESIGN_PHYSICALSPACINGRULEDATA_H #define PHYSICALDESIGN_PHYSICALSPACINGRULEDATA_H namespace Rsyn { class PhysicalSpacingRuleData { public: DBU clsSpacing = 0; DBU clsEOL = 0; DBU clsEOLWithin = 0; PhysicalSpacingRuleData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALSPACINGRULEDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalSpacingTableData.h ================================================ /* * File: PhysicalSpacingTableData.h * Author: * * Created on 12/2/2018, 17:35 */ #ifndef PHYSICALDESIGN_PHYSICALSPACINGTABLEDATA_H #define PHYSICALDESIGN_PHYSICALSPACINGTABLEDATA_H namespace Rsyn { class PhysicalSpacingTableData { public: DBU clsParallelLength = 0; std::vector clsParallelWidth; std::vector clsParallelWidthSpacing; PhysicalSpacingTableData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALSPACINGTABLEDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalSpecialNetData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSpecialNetData.h * Author: jucemar * * Created on 23 de Maio de 2017, 20:23 */ #ifndef PHYSICALDESIGN_PHYSICALSPECIALNETDATA_H #define PHYSICALDESIGN_PHYSICALSPECIALNETDATA_H namespace Rsyn { class PhysicalSpecialNetData : public PhysicalObject { public: DefNetDscp clsNet; PhysicalSpecialNetData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALSPECIALNETDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalSpecialWireData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSpecialWireData.h * Author: jucemar * * Created on 23 de Maio de 2017, 21:08 */ #ifndef PHYSICALDESIGN_PHYSICALSPECIALWIREDATA_H #define PHYSICALDESIGN_PHYSICALSPECIALWIREDATA_H namespace Rsyn { class PhysicalSpecialWireData : public PhysicalObject { public: Rsyn::PhysicalLayer clsPhysicalLayer; DBU clsWireWidth; std::vector clsRoutingPoints; PhysicalSpecialWireData() = default; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALSPECIALWIREDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalTracksData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalTracksData.h * Author: jucemar * * Created on 24 de Maio de 2017, 21:47 */ #ifndef PHYSICALDESIGN_PHYSICALTRACKSDATA_H #define PHYSICALDESIGN_PHYSICALTRACKSDATA_H namespace Rsyn { class PhysicalTracksData : public PhysicalObject { public: PhysicalTrackDirection clsDirection = PhysicalTrackDirection::INVALID_PHY_TRACK_DIRECTION; DBU clsLocation = 0; DBU clsSpace = 0; int clsNumTracks = 0; std::vector clsLayers; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALTRACKSDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/PhysicalViaData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalViaData.h * Author: jucemar * * Created on 14 de Maio de 2017, 14:49 */ #ifndef PHYSICALDESIGN_PHYSICALVIADATA_H #define PHYSICALDESIGN_PHYSICALVIADATA_H namespace Rsyn { class PhysicalViaData : public PhysicalObject { public: bool clsIsDefault : 1; bool clsIsViaDesign : 1; bool clsHasViaRule : 1; bool clsHasRowCol : 1; bool clsHasOrigin : 1; bool clsHasOffset : 1; bool clsHasPattern : 1; bool clsHasCutResistance : 1; ViaType clsType = INVALID_VIA_TYPE; Rsyn::ViaRuleData * clsViaRuleData = nullptr; DBU clsCutSize [2] = {0, 0}; // xCutSize, yCutSize DBU clsSpacing [2] = {0, 0}; // xSpacing, ySpacing DBU clsEnclosure[NUM_VIA_LEVELS][2]; // bottomXEnclosure, bottomYEnclosure, topXEnclosure, topYEnclosure DBU clsOrigin[2] = {0, 0}; // xOrigin, yOrigin DBU clsOffset[NUM_VIA_LEVELS][2]; // bottomXOffset, bottomYOffset, topXOffset, topYOffset int clsNumRows = 0; int clsNumCols = 0; std::string clsPattern = ""; float clsCutResistance = 0.0; Rsyn::PhysicalLayerData *clsLayers[NUM_VIA_LAYERS]; // bottom, cut, top std::vector clsViaGeometries [NUM_VIA_LAYERS]; // bottom, cut, top std::string clsName; PhysicalViaData() { clsIsDefault = false; clsIsViaDesign = false; clsHasViaRule = false; clsHasRowCol = false; clsHasOrigin = false; clsHasOffset = false; clsHasPattern = false; clsHasCutResistance = false; } // end constructor }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALVIADATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/ViaGeometryData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: ViaGeometryData.h * Author: jucemar * * Created on November 12, 2018, 5:44 PM */ #ifndef RSYN_DATABASE_VIAGEOMETRYDATA_H #define RSYN_DATABASE_VIAGEOMETRYDATA_H namespace Rsyn { class ViaGeometryData : public PhysicalObject { public: Bounds clsBounds; int clsMaskNumber = -1; // Polygon }; // end class } // end namespace #endif /* RSYN_DATABASE_VIAGEOMETRYDATA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/data/ViaRuleData.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: ViaRule.h * Author: jucemar * * Created on November 12, 2018, 4:55 PM */ #ifndef RSYN_DATABASE_VIARULE_H #define RSYN_DATABASE_VIARULE_H namespace Rsyn { class ViaRuleData : public PhysicalObject { public: bool clsIsDefault : 1; bool clsIsGenerate : 1; bool clsHasCutResistance : 1; bool clsHasWidth [NUM_VIA_LEVELS]; int clsRelativeIndex = -1; Rsyn::PhysicalLayerData * clsLayers [NUM_VIA_LAYERS]; // top or bottom layer levels. Cut is only for generate type Rsyn::PhysicalLayerDirection clsLayerDirection [NUM_VIA_LEVELS]; // Directions for top or bottom layer levels. DBU clsWidth[NUM_VIA_LEVELS][NUM_VIA_RANGES]; // Specifies a wire width range for bottom and top layer levels. DBU clsEnclosure1 [NUM_VIA_LEVELS]; DBU clsEnclosure2 [NUM_VIA_LEVELS]; Bounds clsCutBounds; DBU clsCutSpacing [2] = {0, 0}; // xCutSpacing, yCutSpacing float clsCutResistance = 0.0; std::vector clsVias; // std::vector clsProperties; // TODO std::string clsName; // Via rule name void init() { clsIsDefault = false; clsIsGenerate = false; clsHasCutResistance = false; for(int i = 0; i < NUM_VIA_LAYERS; ++i) { clsLayers[i] = nullptr; } // end for for(int i = 0; i < NUM_VIA_LEVELS; ++i) { clsHasWidth[i] = false; clsLayerDirection[i] = UNKNOWN_PREFERRED_DIRECTION; for(int j = 0; j < NUM_VIA_RANGES; ++j) { clsWidth[i][j] = -std::numeric_limits::max(); } // end for } // end for } // end method ViaRuleData() = default; }; // end class } // end namespace #endif /* RSYN_DATABASE_VIARULE_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/LayerViaManager.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: LayerViaManager.h * Author: jucemar * * Created on February 3, 2018, 9:26 AM */ #ifndef LAYERVIAMANAGER_H #define LAYERVIAMANAGER_H namespace Rsyn { class LayerViaManager : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::LayerViaManager object with a pointer to Rsyn::LayerViaManagerData. LayerViaManager(LayerViaManagerData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::LayerViaManager object with a null pointer to Rsyn::LayerViaManagerData. LayerViaManager() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::LayerViaManager object with a null pointer to Rsyn::LayerViaManagerData. LayerViaManager(std::nullptr_t) : Proxy(nullptr) { } const std::vector & allVias(Rsyn::PhysicalLayer layer) const; const std::vector & allBottomVias(Rsyn::PhysicalLayer layer) const; const std::vector & allTopVias(Rsyn::PhysicalLayer layer) const; bool hasVias(Rsyn::PhysicalLayer layer) const; bool hasBottomVias(Rsyn::PhysicalLayer layer) const; bool hasTopVias(Rsyn::PhysicalLayer layer) const; }; // end class } // end namespace #endif /* LAYERVIAMANAGER_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalCell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalCell.h * Author: jucemar * * Created on 12 de Setembro de 2016, 21:04 */ #ifndef PHYSICALDESIGN_PHYSICALCELL_H #define PHYSICALDESIGN_PHYSICALCELL_H namespace Rsyn { class PhysicalCell : public PhysicalInstance { friend class PhysicalDesign; friend class PhysicalInstance; protected: PhysicalCell(PhysicalInstanceData * data) : PhysicalInstance(data) {} public: PhysicalCell() : PhysicalInstance(nullptr) {} PhysicalCell(std::nullptr_t): PhysicalInstance(nullptr) {} //! @brief Returns the cell associated to this physical cell. Rsyn::Cell getCell() const; //! @brief Returns true if cell is fixed. Otherwise, returns false. bool isFixed() const; //! @brief Returns true if cell is MACRO type. Otherwise, returns false. bool isMacroBlock() const; //! @brief Returns true if cell is placed. Otherwise, returns false. bool isPlaced() const; //! @brief Returns initial position of the cell. //! @details Initial position is defined in the circuit placement files. //! Otherwise, it is defined to the coordinate DBUxy(0,0); DBUxy getInitialPosition() const; //! @brief Returns initial position of the cell for the given dimension. //! @details Initial position is defined in the circuit placement files. //! Otherwise, it is defined to the coordinate DBUxy(0,0); DBU getInitialPosition(const Dimension dim) const; //! @brief Returns cell displacement. //! @details Cell displacement is the difference between the current position of the cell //! and the initial position of the cell. DBU getDisplacement() const; //! @brief Returns cell displacement. //! @details Cell displacement is the difference between the current position of the cell //! and the initial position of the cell. DBU getDisplacement(const Dimension dim) const; //! @brief Returns cell displacement for the given dimension. //! @details Cell displacement is the difference between the current position of the cell //! and the given position. DBU getDisplacement(const DBUxy pos) const; //! @brief Returns cell displacement to the given position and given dimension. //! @details Cell displacement is the difference between the current position of the cell //! and the given position in the given dimension. DBU getDisplacement(const DBU pos, const Dimension dim) const; //! @brief Returns cell displacement for the given dimension. //! @details Cell displacement is the difference between the current position of the cell //! and the given position. DBU getDisplacementFromCurrentPosition(const DBUxy pos) const; //! @brief Returns cell displacement to the given position and given dimension. //! @details Cell displacement is the difference between the current position of the cell //! and the given position in the given dimension. DBU getDisplacementFromCurrentPosition(const DBU pos, const Dimension dim) const; DBU getDisplacementFromInitialPosition(const DBUxy pos) const; DBU getDisplacementFromInitialPosition(const DBU pos, const Dimension dim) const; //! @brief Returns a transformation that allows one to transform the //! coordinates from the library cell space to the cell space. The //! transformation accounts for translation and the orientation of the cell. //! @param origin If set to true, the transform is created w.r.t (0, 0) and //! not the current cell position. PhysicalTransform getTransform(const bool origin = false) const; //! @brief Returns true if the cell boundaries is defined by a PhysicalLayer. Otherwise, returns false. //! @details Cell boundaries may be defined by some PhysicalLayer instead of rectangular Bounds. //! In the 2015 ICCAD contest, some macro have their boundaries defined by metal1 layer. bool hasLayerBounds() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALCELL_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalDesign.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef PHYSICALDESIGN_PHYSICALDESIGN_H #define PHYSICALDESIGN_PHYSICALDESIGN_H namespace Rsyn { class PhysicalDesign : public Proxy { friend class PhysicalService; template friend class PhysicalAttributeBase; template friend class PhysicalAttributeImplementation; protected: //! @brief Internal constructs a Rsyn::PhysicalDesign object with a pointer to the Rsyn::PhysicalDesignData. //! @details The data and methods in physical design are split into two different objects. //! One, the object that is passed as parameter to the methods contains only the methods implementation. //! while the data is inherent from a Proxy object that have a pointer to the object that stores data. PhysicalDesign(PhysicalDesignData * dsg) : Proxy(dsg) { } public: //! @brief Constructs a Rsyn::PhysicalDesign object with null pointer to the Rsyn::PhysicalDesignData. //! @details The data and methods in physical design are split into two different objects. //! One, the object that is passed as parameter to the methods contains only the methods implementation. //! while the data is inherent from a Proxy object that have a pointer to the object that stores data. PhysicalDesign() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalDesign object with null pointer to the Rsyn::PhysicalDesignData. //! @details The data and methods in physical design are split into two different objects. //! One, the object that is passed as parameter to the methods contains only the methods implementation. //! while the data is inherent from a Proxy object that have a pointer to the object that stores data. PhysicalDesign(std::nullptr_t) : Proxy(nullptr) { } //! @brief loading the technology library specified as LEF to the PhysicalDesign //! @param library is a reference to the descriptor of the technology library inspired in LEF architecture. void loadLibrary(const LefDscp & library); //! @brief loading the design specified as DEF format to the PhysicalDesign. //! @details PhysicalDesign stores the dimensions of design elements using LEF Database Units resolution. //! @param design is a DefDscp reference to the descriptor of the design inspired in DEF architecture. void loadDesign(const DefDscp & design); //! @brief Initializes the Rsyn::PhysicalDesignData, the attributes to the Rsyn::Design elements and control parameters. //! @param Rsyn::Json ¶ms may be: 1) "clsEnablePhysicalPins" true enables Rsyn::PhysicalPin, //! 2) "clsEnableMergeRectangles" true enables merging rectangle bounds to be merged. It does not work to bounds defined as polygon, and //! 3) "clsEnableNetPinBoundaries" true enables storing the pins (Rsyn::Pin) that defines the Bound box boundaries of the nets. //! 4) "clsContestMode" {NONE, ICCAD15} enables legacy support to the contest benchmark. void initPhysicalDesign(Rsyn::Design dsg, const Rsyn::Json ¶ms = {}); //! @brief Setting the net clock. Otherwise, it is defined as nullptr. void setClockNet(Rsyn::Net net); //! @brief Updating the Bound Box of all design nets. //! @param skipClockNet default is value false. Otherwise, the Bound Box of the clock network is skipped to update and is not added to total HPWL. void updateAllNetBounds(const bool skipClockNet = false); //! @brief Updating the Bound box of method parameter net of the Design. //! @param net A valid net of the Design. void updateNetBound(Rsyn::Net net); //! @brief Returns the Data base resolution. //! @param type //! @details type is an enum defined as: Rsyn::LIBRARY_DBU to technology library data base resolution, //! Rsyn::DESIGN_DBU to the design data base resolution, or //! Rsyn::MULT_FACTOR_DBU is the integer multiplier of the design data base and library data base resolutions //! (e.g. 2000 = 1000 * 2 -> DESIGN_DBU = LIBRARY_DBU * MULT_FACTOR_DBU). //! @return DBU data base resolution of the parameter type. DBU getDatabaseUnits(const DBUType type) const; //! @brief Converts micron value into library database units DBU convertMicronToLibraryDatabaseUnits(const double value) const; //! @brief Converts micron value into design database units DBU convertMicronToDesignDatabaseUnits(const double value) const; //! @brief Returning a DBUxy object that has total nets Bound Box HPWL for abscissa (X dimension in DBUxy) and ordinate (Y dimension in DBUxy). DBUxy getHPWL() const; //! @param dim It is an enum Dimension X or Y. //! @brief Returning total nets Bound Box HPWL for the parameter dim. DBU getHPWL(const Dimension dim) const; //! @brief It returns the number of elements of the parameter type //! @param type may be: //! 1) PHYSICAL_FIXED -> Returning total area of the fixed cells inside of core bounds. //! 2) PHYSICAL_MOVABLE -> Returning total area of the movable cells inside of core bounds. //! 3) PHYSICAL_BLOCK -> Returning total area of the block cells inside of the core bounds. //! 4) PHYSICAL_PORT -> Returning total area of the circuit ports. //! 5) PHYSICAL_PLACEABLE -> Returning total area of the rows. //! @return an integer number int getNumElements(const PhysicalType type) const; //! @brief It returns the total area from elements of the parameter type //! @param type may be: //! PHYSICAL_FIXED -> Returning total area of the fixed cells inside of core bounds //! PHYSICAL_MOVABLE -> Returning total area of the movable cells inside of core bounds //! PHYSICAL_BLOCK -> Returning total area of the block cells inside of the core bounds //! PHYSICAL_PORT -> Returning total area of the circuit ports //! PHYSICAL_PLACEABLE -> Returning total area of the rows //! @return The total area in DBU DBU getArea(const PhysicalType type) const; //! @brief Returns true if the Rsyn::PhysicalPin was enabled. Otherwise, it returns false. //! @details For some circuits is irrelevant to initialized Rsyn::PhysicalPin. It will only consume memory. bool isEnablePhysicalPins() const; //! @brief Returns true if the rectangles that defines the boundary were merged in a small set of them. //! @details For some circuits, e.g. 2015 ICCAD contest, the boundaries of macros are defined by a set of rectangles. //! They may be merged into a small set. bool isEnableMergeRectangles() const; //! @brief Returns true if the pins that define the Bound box boundaries of the nets were enabled to be stored. //! Otherwise, it returns false. //! @details For some circuits or some improvement algorithms //! is irrelevant to store the pins that defined the boundaries of the bound box of the net. //! It will only consume memory and runtime. bool isEnableNetPinBoundaries() const; //! @brief Rsyn::PhysicalLibraryPin related to the Rsyn::LibraryPin libPin. Rsyn::PhysicalLibraryPin getPhysicalLibraryPin(Rsyn::LibraryPin libPin) const; //! @brief Rsyn::PhysicalLibraryPin related to the Rsyn::Pin pin. Rsyn::PhysicalLibraryPin getPhysicalLibraryPin(Rsyn::Pin pin) const; //! @brief Rsyn::PhysicalLibraryCell related to the Rsyn::LibraryCell libCell. Rsyn::PhysicalLibraryCell getPhysicalLibraryCell(Rsyn::LibraryCell libCell) const; //! @brief Rsyn::PhysicalLibraryCell related to the Rsyn::Cell cell. Rsyn::PhysicalLibraryCell getPhysicalLibraryCell(Rsyn::Cell cell) const; //! @brief Update physical data of the Rsyn::PhysicalCell related to cell. void updatePhysicalCell(Rsyn::Cell cell); //! @brief Remove physical data of the Rsyn::PhysicalCell related to cell. void removePhysicalCell(Rsyn::Cell cell); //! @brief Rsyn::PhysicalCell related to the Rsyn::Cell cell Rsyn::PhysicalCell getPhysicalCell(Rsyn::Cell cell) const; //! @brief Rsyn::PhysicalCell related to the Rsyn::Pin pin Rsyn::PhysicalCell getPhysicalCell(Rsyn::Pin pin) const; //! @brief Rsyn::PhysicalInstance related to the Rsyn::Instance instance Rsyn::PhysicalInstance getPhysicalInstance(Rsyn::Instance instance) const; //! @brief Rsyn::PhysicalInstance related to the Rsyn::Pin pin Rsyn::PhysicalInstance getPhysicalInstance(Rsyn::Pin pin) const; //! @brief Rsyn::PhysicalPort related to the Rsyn::Port port Rsyn::PhysicalPort getPhysicalPort(Rsyn::Port port) const; //! @brief Rsyn::PhysicalPort related to the Rsyn::Pin pin Rsyn::PhysicalPort getPhysicalPort(Rsyn::Pin pin) const; //! @brief Rsyn::PhysicalModule related to the Rsyn::Module module Rsyn::PhysicalModule getPhysicalModule(Rsyn::Module module) const; //! @brief Rsyn::PhysicalModule related to the Rsyn::Pin pin Rsyn::PhysicalModule getPhysicalModule(Rsyn::Pin pin) const; //! @brief return total number of the movable physical cells. //! @return An integer that is the number of the movable physical cells. int getNumMovedCells() const; //! @brief Returns the object that store the physical data of the Rsyn::PhysicalDie. Rsyn::PhysicalDie getPhysicalDie() const; //! @brief if Rsyn::PhysicalPin was initialized, then returns a valid object. Otherwise, returns nullptr. //! @return Rsyn::PhysicalPin related to the Rsyn::Design Rsyn::Pin pin Rsyn::PhysicalPin getPhysicalPin(Rsyn::Pin pin) const; //! @brief Returns the pin displacement from its cell origen. //! @details Pin displacement is the distance from cell origen to the pin position inside of cell. //! The cell origin is the LOWER and LEFT corner. //! @return Pin displacement in a DBUxy. The distance unit is DBU. DBUxy getPinDisplacement(Rsyn::Pin pin) const; //! @brief Returns the pin position. The position is the summation of pin displacement and its cell position. DBUxy getPinPosition(Rsyn::Pin pin) const; //! @brief Returns the relaxed pin position. //! @details If pin is related to a physical cell, //! the pin position is the cell position. Otherwise, the pin position is the summation //! of the pin displacement and its physical cell position. DBUxy getRelaxedPinPosition(Rsyn::Pin pin) const; //! @brief Returns the pin displacement for abscissa or ordinate. //! @details Pin displacement is the distance from cell origen to the pin position inside of cell. //! The cell origin is the LOWER and LEFT corner. DBU getPinDisplacement(Rsyn::Pin pin, const Dimension dim) const; //! @brief Returns the pin position. The position is the summation of pin displacement and its cell position. DBU getPinPosition(Rsyn::Pin pin, const Dimension dim) const; //! @brief Returns the Rsyn::PhysicalNet object related to the net parameter. Rsyn::PhysicalNet getPhysicalNet(Rsyn::Net net) const; //! @brief Returns the Rsyn::PhysicalLayer object associated to the parameter layer name. Rsyn::PhysicalLayer getPhysicalLayerByName(const std::string & layerName); //! @brief Returns the Rsyn::PhysicalLayer object associated to the parameter layer index. //! @details The index is a integer from 0 to less than the number of layers. //! If the the index number is outside of the ranger, than a null reference is returned. Rsyn::PhysicalLayer getPhysicalLayerByIndex(const int index); //! @brief Returns the Rsyn::PhysicalLayer object associated to the parameter layer index. //! @details The index is a integer from 0 to less than the number of layers of the parameter type. //! If the the index number is outside of the ranger, than a null reference is returned. Rsyn::PhysicalLayer getPhysicalLayerByIndex(const Rsyn::PhysicalLayerType layerType, const int index); //! @brief Returns the Rsyn::PhysicalSite object associated to the parameter site name. Rsyn::PhysicalSite getPhysicalSiteByName(const std::string &siteName); //! @brief Returns the Rsyn::PhysicalRegion object associated to the parameter region name. Rsyn::PhysicalRegion getPhysicalRegionByName(const std::string &siteName); //! @brief Returns the Rsyn::PhysicalGroup object associated to the parameter group name. Rsyn::PhysicalGroup getPhysicalGroupByName(const std::string &siteName); //! @brief Returns the Rsyn::PhysicalVia object associated to the parameter vias name. Rsyn::PhysicalVia getPhysicalViaByName(const std::string &viaName); //! @brief Returns the Rsyn::PhysicalViaRuleBase object associated to the parameter via's name. Rsyn::PhysicalViaRuleBase getPhysicalViaRuleBaseByName(const std::string &viaName); //! @brief Returns the Rsyn::PhysicalViaRule object associated to the parameter via's name. Rsyn::PhysicalViaRule getPhysicalViaRuleByName(const std::string &viaName); //! @brief Returns the Rsyn::PhysicalViaRuleGenerate object associated to the parameter via's name. Rsyn::PhysicalViaRuleGenerate getPhysicalViaRuleGenerateByName(const std::string &viaName); //! @brief Returns the total number of layers. It is the summation of routing, overlap, cut, and so forth layers. int getNumLayers(const Rsyn::PhysicalLayerType type) const; int getNumLayers() const; //! @brief Returns a reference to the vector of PhysicalLayers. Range> allPhysicalLayers(); //! @brief Returns the total number of vias. std::size_t getNumPhysicalVias() const; //! @brief Returns a vector reference to the vector of PhysicalVias. const std::vector & allPhysicalVias() const; std::size_t getNumPhysicalTracks()const; int getNumPhysicalTracks(Rsyn::PhysicalLayer layer) const; const std::vector & allPhysicalTracks() const; const std::vector & allPhysicalTracks(Rsyn::PhysicalLayer layer) const; bool hasPhysicalTracks(Rsyn::PhysicalLayer layer) const; const std::vector& allPhysicalGCell() const; const std::vector & allPhysicalRoutingGrids() const; Rsyn::PhysicalRoutingGrid getPhysicalRoutingGrid(Rsyn::PhysicalLayer layer) const; bool hasPhysicalRoutingGrid(Rsyn::PhysicalLayer layer) const; int getNumPhysicalRoutingGrids() const; //! @brief check if the orientations are equivalent based on symmetry. bool checkEquivalentOrientations(Rsyn::PhysicalSymmetry symmetry, Rsyn::PhysicalOrientation orient1, Rsyn::PhysicalOrientation orient2) const; //! @brief Returns the total number of spacing objects. std::size_t getNumPhysicalSpacing() const; //! @brief Returns a reference to the vector of PhysicalSpacing. Range> allPhysicalSpacing() const; //! @brief Returns the total number of region objects. std::size_t getNumPhysicalRegions() const; //! @brief Returns a reference to the range list of PhysicalRegion. std::vector & allPhysicalRegions() const; //! @brief Returns the total number of group objects. std::size_t getNumPhysicalGroups() const noexcept; //! @brief Returns a reference to the range list of PhysicalGroup. std::vector & allPhysicalGroups() const; //! @brief Returns the total number of physical special nets. std::size_t getNumPhysicalSpecialNets() const noexcept; //! @brief Returns a constant reference to a vector of physical special nets. std::vector & allPhysicalSpecialNets() const; //! @brief Returns the row height. It is assumed all rows have the same height. //! The row height of the first row is returned. //I'm assuming all rows have the same height. DBU getRowHeight() const; //! @brief Returns the row site width. It is assumed all rows have the same site width. //! The row site width of the first row is returned. DBU getRowSiteWidth() const; //! @brief Returns the total number of row objects. std::size_t getNumRows() const; //! @brief Iterates over all Physical Rows. Range> allPhysicalRows(); //! @brief Returns the LayersViasManager //! @comment Given a layer is possible to get all vias which connect to the bottom or top routing layers. Rsyn::LayerViaManager getLayerViaManager() const; protected: //! @brief initializes the Rsyn::PhysicalSite objects into Rsyn::PhysicalDesign. void addPhysicalSite(const LefSiteDscp & site); //! @brief initializes the Rsyn::PhysicalLayer objects into Rsyn::PhysicalDesign. Rsyn::PhysicalLayerData * addPhysicalLayer(lefiLayer* layer, Rsyn::PhysicalLayerData * lower); //! @brief initializes the Rsyn::PhysicalVia objects into Rsyn::PhysicalDesign. void addPhysicalVia(const LefViaDscp & via); //! @brief initializes the Rsyn::PhysicalViaRule objects void addPhysicalViaRule(const LefViaRuleDscp & via); //! @brief initializes the Rsyn::PhysicalLibraryCell objects into Rsyn::PhysicalDesign. Rsyn::LibraryCell addPhysicalLibraryCell(const LefMacroDscp& macro); //! @brief initializes the Rsyn::PhysicalLibraryPin objects of the library cell into //! Rsyn::PhysicalDesign. void addPhysicalLibraryPin(Rsyn::LibraryCell libCell, const LefPinDscp& lefPin); //! @brief initializes the Rsyn::PhysicalInstance object as Rsyn::PhysicalCell into Rsyn::PhysicalDesign. void addPhysicalCell(Rsyn::Instance cell, const DefComponentDscp& component); //! @brief initializes the Rsyn::PhysicalInstance object as Rsyn::PhysicalPort into Rsyn::PhysicalDesign. void addPhysicalPort(Rsyn::Instance cell, const DefPortDscp& port); //! @brief initializes the Rsyn::PhysicalRow objects into Rsyn::PhysicalDesign. void addPhysicalRow(const DefRowDscp& defRow); //! @brief initializes the Rsyn::PhysicalRegion objects into Rsyn::PhysicalDesign. void addPhysicalRegion(const DefRegionDscp& defRegion); //! @brief initializes the Rsyn::PhysicalGroup objects into Rsyn::PhysicalDesign. void addPhysicalGroup(const DefGroupDscp& defGroup); //! @brief Initializes Rsyn::PhysicalNetObject into Ryn::PhysicalDesign. //! @warning Only initializes routed wires. public: // Temporary for the contest debug void addPhysicalNet(const DefNetDscp & netDscp); protected: //! @brief Initializes Rsyn::PhysicalSpecialNet into Ryn::PhysicalDesign. void addPhysicalSpecialNet(const DefNetDscp & specialNet); //! @brief Adds a track. void addPhysicalTracks(const DefTrackDscp &track); //! @brief Inits routing grid void initRoutingGrid(); //! @brief Adds a gcell. void addPhysicalGCell(const DefGcellGridDscp &gcell); //! @brief Adds design via. void addPhysicalDesignVia(const DefViaDscp & via); //! @brief initializes the Rsyn::PhysicalSpacing objects into Rsyn::PhysicalDesign. void addPhysicalSpacing(const LefSpacingDscp & spacing); //! @brief initializes the Rsyn::PhysicalPin objects into Rsyn::PhysicalDesign. //! @todo Implements this method void addPhysicalPin(); //! @brief Merges the rectangles that defines the boundary in a small set of them. //! @details For some circuits, e.g. 2015 ICCAD contest, the boundaries of macros are defined by a set of rectangles. //! They may be merged into a small set. //! @warning works only for rectangles void mergeBounds(const std::vector & source, std::vector & target, const Dimension dim = X); //! @brief inits the manager of the layers and vias. void initLayerViaManager(); private: //! @brief Returns the Rsyn::PhysicalRow unique identifier. PhysicalIndex getId(Rsyn::PhysicalRow phRow) const; //! @brief Returns the Rsyn::PhysicalLayer unique identifier. PhysicalIndex getId(Rsyn::PhysicalLayer phLayer) const; //! @brief Returns the Rsyn::PhysicalSpacing unique identifier. PhysicalIndex getId(Rsyn::PhysicalSpacing spacing) const; public: //! @details Creates the physical object to handle the physical object extensions. //! The extension maps the physical object to a null reference. PhysicalAttributeInitializer createPhysicalAttribute(); //! @details Creates the physical object to handle the physical object extensions. //! The extension maps the physical object to the default parameter data. template PhysicalAttributeInitializerWithDefaultValue createPhysicalAttribute(const DefaultPhysicalValueType &defaultValue); public: //! @brief typedef for callback to the moved instances. typedef std::function PostInstanceMovedCallback; //! @brief list of registered call backs. typedef std::list>::iterator PostInstanceMovedCallbackHandler; //////////////////////////////////////////////////////////////////////////// // Placement //////////////////////////////////////////////////////////////////////////// //! @brief places the Rsyn::PhysicalCell at defined position. //! @warning Caution when using dontNotifyObservers. //! We can use it when you may expect the move to be rolled back, but it is //! not, recall to mark the cell as dirty. void placeCell(Rsyn::PhysicalCell physicalCell, const DBU x, const DBU y, Rsyn::PhysicalOrientation orient = ORIENTATION_INVALID, const bool dontNotifyObservers = false); //! @brief places the Rsyn::PhysicalCell at defined position. //! @warning Caution when using dontNotifyObservers. //! We can use it when you may expect the move to be rolled back, but it is //! not, recall to mark the cell as dirty. void placeCell(Rsyn::Cell cell, const DBU x, const DBU y, Rsyn::PhysicalOrientation orient = ORIENTATION_INVALID, const bool dontNotifyObservers = false); //! @brief places the Rsyn::PhysicalCell at defined position. //! @warning Caution when using dontNotifyObservers. //! We can use it when you may expect the move to be rolled back, but it is //! not, recall to mark the cell as dirty. void placeCell(Rsyn::PhysicalCell physicalCell, const DBUxy pos, Rsyn::PhysicalOrientation orient = ORIENTATION_INVALID, const bool dontNotifyObservers = false); //! @brief places the Rsyn::PhysicalCell at defined position. //! @warning Caution when using dontNotifyObservers. //! We can use it when you may expect the move to be rolled back, but it is //! not, recall to mark the cell as dirty. void placeCell(Rsyn::Cell cell, const DBUxy pos, Rsyn::PhysicalOrientation orient = ORIENTATION_INVALID, const bool dontNotifyObservers = false); //Place Port Rsyn::PhysicalOrientation checkOrientation(Rsyn::PhysicalPort physicalPort, const DBU x, const DBU y); DBUxy checkPosition(const DBU x, const DBU y); bool getPhysicalPortByName(std::string name, Rsyn::PhysicalPort &phPort); void placePort(Rsyn::PhysicalPort physicalPort, const DBU x, const DBU y, Rsyn::PhysicalOrientation orient = ORIENTATION_INVALID, const bool disableSnapping = false, const bool dontNotifyObservers = false); void placePort(Rsyn::Port port, const DBU x, const DBU y, Rsyn::PhysicalOrientation orient = ORIENTATION_INVALID, const bool disableSnapping = false, const bool dontNotifyObservers = false); void placePort(Rsyn::PhysicalPort physicalPort, const DBUxy pos, Rsyn::PhysicalOrientation orient = ORIENTATION_INVALID, const bool disableSnapping = false, const bool dontNotifyObservers = false); void placePort(Rsyn::Port port, const DBUxy pos, Rsyn::PhysicalOrientation orient = ORIENTATION_INVALID, const bool disableSnapping = false, const bool dontNotifyObservers = false); //! @brief set cell orientation. //! @warning Caution when using dontNotifyObservers. //! We can use it when you may expect the move to be rolled back, but it is //! not, recall to mark the cell as dirty. void setCellOrientation(Rsyn::PhysicalCell physicalCell, Rsyn::PhysicalOrientation orient, const bool dontNotifyObservers = false); //! @brief set cell orientation. //! @warning Caution when using dontNotifyObservers. //! We can use it when you may expect the move to be rolled back, but it is //! not, recall to mark the cell as dirty. void setCellOrientation(Rsyn::Cell cell, Rsyn::PhysicalOrientation orient, const bool dontNotifyObservers = false); void flipCell(Rsyn::PhysicalCell physicalCell, const bool dontNotifyObservers = false); void flipCell(Rsyn::Cell cell, const bool dontNotifyObservers = false); //! @brief Explicitly notify observer that a cell was moved. This is only necessary //! if "dontNotifyObservers = true" in "placeCell" methods. //! @todo Remove void notifyInstancePlaced(Rsyn::Instance instance, Rsyn::DesignObserver *ignoreObserver = nullptr); //////////////////////////////////////////////////////////////////////////// // Routing //////////////////////////////////////////////////////////////////////////// void setNetRouting(Rsyn::Net net, const PhysicalRouting &routing); void clearNetRouting(Rsyn::Net net); const PhysicalRouting &getNetRouting(Rsyn::Net net) const; bool isNetRouted(Rsyn::Net net) const; //////////////////////////////////////////////////////////////////////////// // Notifications //////////////////////////////////////////////////////////////////////////// public: //! @brief Registers an observer to be notified about changes in the //! netlist. template void registerObserver(T *observer); //! @brief Unregisters an observer so it will no longer receives //! notifications about changes in the netlist. void unregisterObserver(PhysicalDesignObserver *observer); }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALDESIGN_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalDie.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalDie.h * Author: jucemar * * Created on 4 de Fevereiro de 2017, 08:45 */ #ifndef PHYSICALDESIGN_PHYSICALDIE_H #define PHYSICALDESIGN_PHYSICALDIE_H namespace Rsyn { class PhysicalDie : public Proxy { friend class PhysicalDesign; protected: PhysicalDie(PhysicalDieData * data) : Proxy(data) {} public: //! @brief Default constructor. Rectangular bounds are initialized to Bounds(DBUxy(0,0), DBUxy(0,0)). //! PhysicalDieData pointer is initialized to nullptr. //! @note Die is assumed to be a rectangle. It does not support die defined as a polygon. PhysicalDie() {} //! @brief PhysicalDie(std::nullptr_t) {} //! @brief Returns the coordinate (x,y) of the boundary Rsyn::LOWER or Rsyn::UPPER of the die. DBUxy getCoordinate(const Boundary bound) const; //! @brief Returns the coordinate X or Y of the boundary Rsyn::LOWER or Rsyn::UPPER of the die. DBU getCoordinate(const Boundary bound, const Dimension dim) const; //! @brief Returns constant reference to Bounds objects. const Bounds & getBounds() const; //! @brief Returns the dimension length for abscissa (X) or ordinate (Y). DBU getLength(const Dimension dim) const; //! @brief Returns the coordinate X or Y of the boundary LOWER or UPPER of the die. DBUxy getPosition(const Boundary boundary = LOWER) const; //! @brief Returns the central position (X, Y) in DBU units of the die bounds. DBUxy getCenterPosition() const; //! @brief Returns total area of the PhysicalDie Bounds. DBU getArea() const; }; //end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALDIE_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalGCell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef PHYSICALGCELL_H #define PHYSICALGCELL_H namespace Rsyn { class PhysicalGCell : public Proxy { friend class PhysicalDesign; protected: PhysicalGCell(PhysicalGCellData * data) : Proxy(data) {} public: //! @brief Default constructor. //! PhysicalGCellData pointer is initialized to nullptr. PhysicalGCell() {} //! @brief PhysicalGCell(std::nullptr_t) {} //! @brief Returns GCell direction Rsyn::PhysicalGCellDirection getDirection() const; //! @brief If direction is vertical, then numTracks means the number of columns //! If direction is Horizontal, then numTracks means the number of rows int getNumTracks() const; //! @brief If direction is Horizontal, then location is Y value. //! If direction is vertical, then location is X value. DBU getLocation() const; //! @brief Returns the spacing between GCell tracks. DBU getStep() const; }; // end class } // end namespace #endif /* PHYSICALGCELL_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalGroup.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalGroup.h * Author: jucemar * * Created on 09 de Abril de 2017, 16:45 */ #ifndef PHYSICALDESIGN_PHYSICALGROUP_H #define PHYSICALDESIGN_PHYSICALGROUP_H namespace Rsyn { class PhysicalGroup : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalGroup object with a pointer to Rsyn::PhysicalGroupData. PhysicalGroup(PhysicalGroupData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalGroup object with a null pointer to Rsyn::PhysicalGroupData. PhysicalGroup() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalGroup object with a null pointer to Rsyn::PhysicalGroupData. PhysicalGroup(std::nullptr_t) : Proxy(nullptr) { } //! @brief Returns region's name const std::string & getName() const; //! @brief Returns the PhysicalRegion object associated to PhysicalGroup. Rsyn::PhysicalRegion getPhysicalRegion() const; //! @brief Returns the constant reference to the Region patters vector. const std::vector & allPatterns() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALGROUP_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalInstance.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalInstance.h * Author: jucemar * * Created on 4 de Outubro de 2016, 13:22 */ #ifndef PHYSICALDESIGN_PHYSICALINSTANCE_H #define PHYSICALDESIGN_PHYSICALINSTANCE_H namespace Rsyn { class PhysicalInstance : public Proxy { friend class PhysicalDesign; protected: //! @brief Constructs a Rsyn::PhysicalInstance object with a pointer to Rsyn::PhysicalInstanceData. PhysicalInstance(PhysicalInstanceData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalInstance object with a null pointer to Rsyn::PhysicalInstanceData. PhysicalInstance() {} //! @brief Constructs a Rsyn::PhysicalInstance object with a null pointer to Rsyn::PhysicalInstanceData. PhysicalInstance(std::nullptr_t) {} //! @brief Returns the Instance associated to PhysicalInstance Rsyn::Instance getInstance() const; //! @brief Returns the name of this instance. const std::string &getName() const; //! @brief Returns the instance area in DBU. DBU getArea() const; //! @brief Returns the central point of the PhysicalInstance boundaries. DBUxy getCenter() const; //! @brief Returns the central position of the PhysicalInstance boundaries for the given dimension. DBU getCenter(const Dimension dim) const; //! @brief Returns the x position of the instance. DBU getX() const; //! @brief Returns the y position of the instance. DBU getY() const; //! @brief Returns the Instance height. It is the length of PhysicalInstance boundaries is Y dimension. DBU getHeight() const; //! @brief Returns the Instance width. It is the length of PhysicalInstance boundaries is X dimension. DBU getWidth() const; //! @brief Returns the length of PhysicalInstance boundaries for given dimension DBU getSize(const Dimension dimension) const; //! @brief Returns the length of PhysicalInstance boundaries. //! In X is the length for abscissa (width) while in Y is the length for ordinate (height). DBUxy getSize() const; //! @brief Returns the left-lower PhysicalInstance point that is defined as its position. DBUxy getPosition() const; //! @brief Returns the left-lower PhysicalInstance point for the given dimension //! that is defined as its position. DBU getPosition(const Dimension dim) const; //! @brief Returns the PhysicalInstance point for the given boundary (LOWER or UPPER). DBUxy getCoordinate(const Boundary bound) const; //! @brief Returns the PhysicalInstance point for the given boundary (LOWER or UPPER) and dimension (X or Y). DBU getCoordinate(const Boundary bound, const Dimension dim) const; //! @brief Returns the orientation of the cell. PhysicalOrientation getOrientation() const; //! @brief Returns the bound box Bounds that defines the limits of PhysicalInstance. const Bounds &getBounds() const; Rsyn::PhysicalCell asPhysicalCell() const; // Mateus and Isadora @ 2018/03/19 // Maybe it should be moved to PhysicalInstanceData? // Used in map-like data structures. friend bool operator<(const PhysicalInstance &left, const PhysicalInstance &right) { // [IMPORTANT] We don't use the pointer (e) directly to avoid // non-determinism behavior. Note that the pointer address may change // from execution to execution and hence the mapping function may return // elements in different order leading to different results. return left.getInstance() < right.getInstance(); } // end method }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALINSTANCE_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalLayer.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalLayer.h * Author: jucemar * * Created on 13 de Setembro de 2016, 19:12 */ #ifndef PHYSICALDESIGN_PHYSICALLAYER_H #define PHYSICALDESIGN_PHYSICALLAYER_H namespace Rsyn { class PhysicalLayer : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; friend class PhysicalViaGeometry; friend class PhysicalViaRuleBase; friend class PhysicalViaRule; friend class PhysicalViaRuleGenerate; friend class PhysicalVia; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalLayer object with a pointer to Rsyn::PhysicalLayerData. PhysicalLayer(PhysicalLayerData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalLayer object with a null pointer to Rsyn::PhysicalLayerData. PhysicalLayer() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalLayer object with a null pointer to Rsyn::PhysicalLayerData. PhysicalLayer(std::nullptr_t) : Proxy(nullptr) {} //! @brief Returns the Rsyn::PhysicalLayer layer. lefiLayer* getLayer() const; //! @brief Returns the Rsyn::PhysicalLayer name. std::string getName() const; //! @brief Returns the layer type (ROUTING, CUT, OVERLAP, MASTERSLICE, or IMPLANT). Rsyn::PhysicalLayerType getType() const; //! @brief Returns the layer width in DBU. DBU getWidth() const; //! @brief Returns the layer index w.r.t to all physical layers. It starts //! from 0 that is the bottom layer //! @note If you need an index relative to the layer type, see //! getRelativeIndex(). int getIndex() const; //! @brief Returns the relative layer index w.r.t. the layers of same type. int getRelativeIndex() const; Rsyn::PhysicalLayer getPhysicalLayerLower() const; Rsyn::PhysicalLayer getPhysicalLayerUpper() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALLAYER_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalLibraryCell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalLibraryCell.h * Author: jucemar * * Created on 12 de Setembro de 2016, 22:10 */ #ifndef PHYSICALDESIGN_PHYSICALLIBRARYCELL_H #define PHYSICALDESIGN_PHYSICALLIBRARYCELL_H namespace Rsyn { class PhysicalLibraryCell : public Proxy { friend class PhysicalDesign; protected: //! @brief Constructs a Rsyn::PhysicalLibraryCell object with a pointer to Rsyn::PhysicalLibraryCellData. PhysicalLibraryCell(PhysicalLibraryCellData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalLibraryCell object with a null pointer to Rsyn::PhysicalLibraryCellData. PhysicalLibraryCell() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalLibraryCell object with a null pointer to Rsyn::PhysicalLibraryCellData. PhysicalLibraryCell(std::nullptr_t) : Proxy(nullptr) {} //! @brief Returns the PhysicalLibraryCell macro. lefiMacro* getMacro() const; //! @brief Returns the PhysicalLibraryCell size. //! @brief In dimension X is the PhysicalLibraryCell width while in Y is the PhysicalLibraryCell height. DBUxy getSize() const; //! @brief Returns a DBU type that represents the PhysicalLibraryCell width. DBU getWidth() const; //! @brief Returns a DBU type that represents the PhysicalLibraryCell height. DBU getHeight() const; //! @brief Returns a DBU type that represents the PhysicalLibraryCell length in Dimension parameter dim. DBU getLength(const Dimension dim) const; //! @brief Returns the library cell bounds. Bounds getBounds() const; //! @brief Returns true if the PhysicalLibraryCell has defined rectangular obstacle Bounds. bool hasLayerObstacles() const; bool hasObstacles() const; //! @brief Returns PhysicalSite object related to the PhysicalLibraryCell. Rsyn::PhysicalSite getSite() const; //! @breif Returns true if there is a top layer obstacle. The top layer obs is the highest metal layer blockage. bool hasTopLayerObstacle() const; //! @breif Returns the top layer obstacle. The top layer obs is the highest metal layer blockage. Rsyn::PhysicalObstacle getTopLayerObstracle() const; //! @brief Returns a constant vector reference to PhysicalObstacle objects that //! represent the metal layers blocked in the top of the PhysicalLibraryCell. const std::vector & allObstacles() const ; //! @brief Returns the total number of metal layer (PhysicalObstacle) blocked in the top of the PhysicalLibraryCell. std::size_t getNumObstacles() const; //! @brief Returns the number of cell layer boundaries. //! @details In 2015 ICCAD contest, the boundaries for some macros are defined by one of the PhysicalLayer, //! i.e., the PhysicalLibaryCellboundaries are defined by metal1 boundaries. //! return 0 if the cell boundaries is not defined by one of layer metal. //! Otherwise returns the number of rectangles that composes the cell boundary //! @warning This method affects 2015 ICCAD contest benchmark. std::size_t getNumPhysicalCellLayerBoundaries() const; //! @brief Returns the PhysicalObstacle that defines the cell boundary for 2015 ICCAD contest benchmark. //! @details In 2015 ICCAD contest, the boundaries for some macros are defined by one of the PhysicalLayer, //! i.e., the PhysicalLibaryCellboundaries are defined by metal1 boundaries. //! @warning This method affects 2015 ICCAD contest benchmark. Rsyn::PhysicalObstacle getLayerObstacles() const; //! @brief Returns a transformation that allows one to transform the //! coordinates according to a cell orientation. PhysicalTransform getTransform(const Rsyn::PhysicalOrientation &orientation) const; //! @brief Returns a constant reference vector to all Bounds that defines the cell boundary for 2015 ICCAD contest benchmark. //! @details In 2015 ICCAD contest, the boundaries for some macros are defined by one of the PhysicalLayer, //! i.e., the PhysicalLibaryCellboundaries are defined by metal1 boundaries. //! @warning This method affects 2015 ICCAD contest benchmark. const std::vector & allLayerObstacles() const; bool hasPolygonBoundaries() const; const Polygon & getPolygonBoundaries() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALLIBRARYCELL_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalLibraryPin.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalLibraryPin.h * Author: jucemar * * Created on 13 de Setembro de 2016, 21:06 */ #ifndef PHYSICALDESIGN_PHYSICALLIBRARYPIN_H #define PHYSICALDESIGN_PHYSICALLIBRARYPIN_H namespace Rsyn { class PhysicalLibraryPin : public Proxy { friend class PhysicalDesign; protected: //! @brief Constructs a Rsyn::PhysicalLibraryPin object with a pointer to Rsyn::PhysicalLibraryPinData. PhysicalLibraryPin(PhysicalLibraryPinData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalLibraryPin object with a null pointer to Rsyn::PhysicalLibraryPinData. PhysicalLibraryPin() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalLibraryPin object with a null pointer to Rsyn::PhysicalLibraryPinData. PhysicalLibraryPin(std::nullptr_t) : Proxy(nullptr) {} //! @brief REturns the physical library cell of this pin. PhysicalLibraryCell getPhysicalLibraryCell() const; //! @brief Returns the pin rectangular boundaries defined at 2015 ICCAD contest. Bounds getICCADBounds(); //! @brief Returns the pin rectangular boundaries reference defined at 2015 ICCAD contest. const Bounds & getICCADBounds() const; //! @brief Returns a vector reference to PhysicalPinGeometry objects related to the PhysicalLibraryPin. std::vector & allPinGeometries(); //! @brief Returns a constant vector reference to PhysicalPinGeometry objects related to the PhysicalLibraryPin. const std::vector & allPinGeometries() const; //! @brief Returns an integer number that is the total number of PhysicalPinGeometry related to the PhysicalLibraryPin. std::size_t getNumPinGeometries() const; //! @brief Returns true if PhysicalLibraryPin has PhysicalPinGeometry objects. Otherwise, returns false. bool hasPinGeometries() const; //! @brief Returns true if PhysicalLibraryPin has no PhysicalPinGeometry objects. Otherwise, returns false. bool isEmptyPinGeometries() const; //! @brief Returns an enum indicating the pin direction. PhysicalPinDirection getPinDirection() const; //! @brief Returns an enum of PhysicalPinUse that gives the PhysicalPin usage type. PhysicalPinUse getUse() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALLIBRARYPIN_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalModule.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalModule.h * Author: jucemar * * Created on 4 de Outubro de 2016, 20:34 */ #ifndef PHYSICALDESIGN_PHYSICALMODULE_H #define PHYSICALDESIGN_PHYSICALMODULE_H namespace Rsyn { class PhysicalModule : public PhysicalInstance { friend class PhysicalDesign; protected: //! @brief Constructs a Rsyn::PhysicalModule object with a pointer to Rsyn::PhysicalInstanceData. PhysicalModule(PhysicalInstanceData * data) : PhysicalInstance(data) {} public: //! @brief Constructs a Rsyn::PhysicalModule object with a null pointer to Rsyn::PhysicalInstanceData. PhysicalModule() : PhysicalInstance(nullptr) {} //! @brief Constructs a Rsyn::PhysicalModule object with a null pointer to Rsyn::PhysicalInstanceData. PhysicalModule(std::nullptr_t) : PhysicalInstance(nullptr) {} }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALMODULE_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalNet.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalNet.h * Author: jucemar * * Created on 15 de Setembro de 2016, 19:16 */ #ifndef RSYN_PHYSICAL_NET_H #define RSYN_PHYSICAL_NET_H namespace Rsyn { class PhysicalNet : public Proxy { friend class PhysicalDesign; protected: //! @brief Constructs a Rsyn::PhysicalNet object with a pointer to Rsyn::PhysicalNetData. PhysicalNet(PhysicalNetData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalNet object with a null pointer to Rsyn::PhysicalNetData. PhysicalNet() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalNet object with a null pointer to Rsyn::PhysicalNetData. PhysicalNet(std::nullptr_t) : Proxy(nullptr) {} //! @brief Returns the net associated to this physical net. Rsyn::Net getNet() const; //! @brief Returns the name of the physical net. std::string getName() const; //! @brief Returns the semi perimeter of the Bound Box from PhysicalNet. //! @details In X is the length of net Bound Box for abscissa and in Y is //! the length of net Bound Box for ordinate. DBUxy getHPWL() const; //! @brief Returns the length of the Bound Box from PhysicalNet in the given dimension. DBU getHPWL(const Dimension dim); //! @brief Returns a constant reference to the bound box of the PhysicalNet. //! @details Bound box units is DBU. Its boundary limits are defined by the two most //! distant each other pins for each dimension. const Bounds & getBounds() const; //! @brief Returns the point coordinate of the net bound box. The points that //! determine the Bounds are left-lower and upper-right. DBUxy getCoordinate(const Boundary bound) const ; //! @brief Returns the point coordinate for the given dimension of the net bound box. //! The points that determine the Bounds are left-lower and upper-right. DBU getCoordinate(const Boundary bound, const Dimension dim) const; //! @brief Return the PhysicalPin object that determines the boundary of PhysicalNet //! in one of its demensions. Rsyn::Pin getPinBoundary(const Boundary bound, const Dimension dim) const; //! @brief Returns the physical routing of this net. const PhysicalRouting &getRouting() const; //! @brief Returns true if the net is routed (has a non-empty routing). bool isRouted() const; }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalObstacle.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalObstacle.h * Author: jucemar * * Created on 13 de Setembro de 2016, 20:08 */ #ifndef PHYSICALDESIGN_PHYSICALOBSTACLE_H #define PHYSICALDESIGN_PHYSICALOBSTACLE_H namespace Rsyn { class PhysicalObstacle : public Proxy < PhysicalObstacleData > { friend class PhysicalDesign; friend class PhysicalDesignData; protected: //! @brief Constructs a Rsyn::PhysicalObstacle object with a pointer to Rsyn::PhysicalObstacleData. PhysicalObstacle(PhysicalObstacleData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalObstacle object with a null pointer to Rsyn::PhysicalObstacleData. PhysicalObstacle() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalObstacle object with a null pointer to Rsyn::PhysicalObstacleData. PhysicalObstacle(std::nullptr_t) : Proxy(nullptr) {} //! @brief Returns the Rsyn::PhysicalLayer object related to the current Rsyn::PhysicalObstacle. Rsyn::PhysicalLayer getLayer() const; //! @brief Returns the vector of rectangular Bounds in the Rsyn::PhysicalObstacle. const std::vector & allBounds() const; //! @brief Returns the total number of rectangular Bounds in the Rsyn::PhysicalObstacle. std::size_t getNumObs() const; //! @brief Returns true if Rsyn::PhysicalObstacle has a Rsyn::PhysicalLayer object defined. //! Otherwise, returns false. bool hasLayer() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALOBSTACLE_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalPin.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPin.h * Author: jucemar * * Created on 14 de Setembro de 2016, 21:26 */ #ifndef PHYSICALDESIGN_PHYSICALPIN_H #define PHYSICALDESIGN_PHYSICALPIN_H namespace Rsyn { class PhysicalPin : public Proxy { friend class PhysicalDesign; protected: //! @brief Constructs a Rsyn::PhysicalPin object with a pointer to Rsyn::PhysicalPinData. PhysicalPin(PhysicalPinData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalPin object with a null pointer to Rsyn::PhysicalPinData. PhysicalPin() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalPin object with a null pointer to Rsyn::PhysicalPinData. PhysicalPin(std::nullptr_t) : Proxy(nullptr) {} //! @brief Returns the pin displacement. //! @details The displacement are independent to abscissa (X) and ordinate (X). //! The origin to compute pin displacement is the Left-Lower cell point and it is assumed to be (0,0). //! @warning It was assumed the pin has a fixed position in the cell. DBUxy getDisplacement () const; //! @brief Returns the pin displacement to the Dimension parameter dim. //! @details The displacement are independent to abscissa (X) and ordinate (X). //! The origin to compute pin displacement is the Left-Lower cell point and it is assumed to be (0,0). //! @warning It was assumed the pin has a fixed position in the cell. DBU getDisplacement(const Dimension dim); //! @brief Returns a vector reference to PhysicalPinGeometry objects related to PhysicalPin. std::vector & allPinGeometries(); //! @brief Returns a constant vector reference to PhysicalPinGeometry objects related to PhysicalPin. const std::vector & allPinGeometries() const; //! @brief Returns the total number of PhysicalPinGeometry objects related to PhysicalPin. std::size_t getNumPinGeometries() const; //! @brief Returns true if PhysicalPin has PhysicalPinGeometry objects. Otherwise, returns false. bool hasPinGeometries() const; //! @brief Returns true if PhysicalPin has no PhysicalPinGeometry objects. Otherwise, returns false. bool isEmptyPinGeometries() const; //! @brief Returns an enum of PhysicalPinDirection that gives the PhysicalPin direction. PhysicalPinDirection getDirection () const; //! @brief Returns a constant reference to the Bounds object that defines the PhysicalPin boundaries. //! it is is defined by one of the layer. const Bounds & getLayerBounds() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALPIN_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalPinGeometry.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPinGeometry.h * Author: jucemar * * Created on 13 de Setembro de 2016, 21:13 */ #ifndef PHYSICALDESIGN_PHYSICALPINGEOMETRY_H #define PHYSICALDESIGN_PHYSICALPINGEOMETRY_H namespace Rsyn { class PhysicalPinGeometry : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; protected: //! @brief Constructs a Rsyn::PhysicalPinGeometry object with a pointer to Rsyn::PhysicalPinGeometryData. PhysicalPinGeometry(PhysicalPinGeometryData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalPinGeometry object with a null pointer to Rsyn::PhysicalPinGeometryData. PhysicalPinGeometry() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalPinGeometry object with a null pointer to Rsyn::PhysicalPinGeometryData. PhysicalPinGeometry(std::nullptr_t) : Proxy(nullptr) {} //! @brief Returns the PhysicalPinGeometryClass type of the PhysicalPinLayer. //! @details A PhysicalPinGeometryClass may be: 1) PINGEOMETRYCLASS_NONE (default), 2) PINGEOMETRYCLASS_CORE, or PINGEOMETRYCLASS_BUMP. Rsyn::PhysicalPinGeometryClass getPinGeometryClass() const; //! @brief Returns true if a PhysicalPinLayer was associated to the PhysicalPinGeometry. //! Otherwise, returns false. bool hasPinLayer() const ; //! @brief Returns the number if pin layers std::size_t getNumPinLayers() const; //! @brief Returns the PhysicalPinLayers associated to the PhysicalPinGeometry. const std::vector & allPinLayers() const; //! @brief Returns the lower pin layer. It is sorted by physical layer. //! If a pin layer is not defined, than returns a physical pin layer with nullptr data Rsyn::PhysicalPinLayer getLowerPinLayer() const; //! @brief Returns the upper pin layer. It is sorted by physical layer. //! If a pin layer is not defined, than returns a physical pin layer with nullptr data Rsyn::PhysicalPinLayer getUpperPinLayer() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALPINGEOMETRY_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalPinLayer.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPinLayer.h * Author: jucemar * * Created on 13 de Setembro de 2016, 21:19 */ #ifndef PHYSICALDESIGN_PHYSICALPINLAYER_H #define PHYSICALDESIGN_PHYSICALPINLAYER_H namespace Rsyn { class PhysicalPinLayer : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; protected: //! @brief Constructs a Rsyn::PhysicalPinLayer object with a pointer to Rsyn::PhysicalPinLayerData. PhysicalPinLayer(PhysicalPinLayerData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalPinLayer object with a null pointer to Rsyn::PhysicalPinLayerData. PhysicalPinLayer() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalPinLayer object with a null pointer to Rsyn::PhysicalPinLayerData. PhysicalPinLayer(std::nullptr_t) : Proxy(nullptr) {} //! @brief Returns the vector reference of rectangular bounds to the Rsyn::PhysicalPinLayer. const std::vector & allBounds() const; //! @brief Returns the vector reference of polygons to the PhysicalPinLayer. const std::vector & allPolygons() const; //! @brief Returns the Rsyn::PhysicalLayer object related to the Rsyn::PhysicalPinLayer. Rsyn::PhysicalLayer getLayer() const; //! @brief Returns the total number of rectangular Bounds that defines Rsyn::PhysicalPinLayer std::size_t getNumBounds() const; //! @brief Returns the total number of Polygons that defines Rsyn::PhysicalPinLayer std::size_t getNumPolygons() const; //! @brief Returns true if the Rsyn::PhysicalPinLayer has rectangular Bounds. //! Otherwise, returns false. bool hasRectangleBounds() const; //! @brief Returns true if the Rsyn::PhysicalPinLayer has Polygons. //! Otherwise, returns false. bool hasPolygonBounds() const; //! @brief Returns true if the Rsyn::PhysicalPinLayer has no rectangular Bounds. //! Otherwise, returns false. bool isRectangleBoundsEmpty() const; //! @brief Returns true if the Rsyn::PhysicalPinLayer has no Polygons. //! Otherwise, returns false. bool isPolygonBoundsEmpty() const; //! @brief Returns true if a Rsyn::PhysicalLayer object is associated to the Rsyn::PhysicalPinLayer. //! Otherwise, returns false. bool hasLayer() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALPINLAYER_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalPort.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPort.h * Author: jucemar * * Created on 4 de Outubro de 2016, 13:23 */ #ifndef PHYSICALDESIGN_PHYSICALPORT_H #define PHYSICALDESIGN_PHYSICALPORT_H namespace Rsyn { class PhysicalPort : public PhysicalInstance { friend class PhysicalDesign; protected: //! @brief Constructs a Rsyn::PhysicalPort object with a pointer to Rsyn::PhysicalInstanceData. PhysicalPort(PhysicalInstanceData * data) : PhysicalInstance(data) {} public: //! @brief Constructs a Rsyn::PhysicalPort object with a null pointer to Rsyn::PhysicalInstanceData. PhysicalPort() : PhysicalInstance(nullptr) {} //! @brief Constructs a Rsyn::PhysicalPort object with a null pointer to Rsyn::PhysicalInstanceData. PhysicalPort(std::nullptr_t) : PhysicalInstance(nullptr) {} // Methods for physical cell when a circuit pin (port) is mapped to it // In the Rsyn the circuit pins (ports) and cells are the same object. Therefore, // in the mapping to physical object they must be the same object. //! @brief Returns the object of the layer associated to the PhysicalPort PhysicalLayer getLayer() const; //! @brief Returns true if the PhysicalPort has an associated layer. Otherwise, returns false. bool hasLayer() const; PhysicalOrientation getOrientation() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALPORT_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalRegion.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalRegion.h * Author: jucemar * * Created on 09 de Abril de 2017, 14:55 */ #ifndef PHYSICALDESIGN_PHYSICALREGION_H #define PHYSICALDESIGN_PHYSICALREGION_H namespace Rsyn { class PhysicalRegion : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalRegion object with a pointer to Rsyn::PhysicalRegionData. PhysicalRegion(PhysicalRegionData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalRegion object with a null pointer to Rsyn::PhysicalRegionData. PhysicalRegion() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalRegion object with a null pointer to Rsyn::PhysicalRegionData. PhysicalRegion(std::nullptr_t) : Proxy(nullptr) { } //! @brief Returns region's name const std::string & getName() const; //! @brief Returns region's type that may be FENCE or GUIDE. RegionType getType() const; //! @brief Returns the constant reference to the boundaries vector. const std::vector & allBounds() const; //! @brief Returns total number of boundaries. std::size_t getNumBounds() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALREGION_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalRoutingGrid.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalRoutingGrid.h * Author: jucemar * * Created on February 2, 2018, 9:01 PM */ #ifndef RSYN_PHYSICAL_ROUTING_GRID_H #define RSYN_PHYSICAL_ROUTING_GRID_H namespace Rsyn { class PhysicalRoutingGrid : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalRoutingGrid object with a pointer to Rsyn::PhysicalRoutingGridData. PhysicalRoutingGrid(PhysicalRoutingGridData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalRoutingGrid object with a null pointer to Rsyn::PhysicalRoutingGridData. PhysicalRoutingGrid() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalRoutingGrid object with a null pointer to Rsyn::PhysicalRoutingGridData. PhysicalRoutingGrid(std::nullptr_t) : Proxy(nullptr) { } Rsyn::PhysicalLayer getLayer() const; const std::vector & allTracks() const; const Bounds & getBounds() const; DBUxy getPosition() const; DBU getPosition(const Dimension dim) const; DBUxy getSpacing() const; DBU getSpacing(const Dimension dim) const; int getNumTracks(const Dimension dim) const; int getNumRows() const; int getNumCols() const; int getNumTracks() const; int getRow(const DBU posY, const RoundingStrategy roudingStrategy = ROUND_NEAREST, const bool clamp = false) const; int getCol(const DBU posX, const RoundingStrategy roudingStrategy = ROUND_NEAREST, const bool clamp = false) const; DBUxy getPosition(const int col, const int row) const; DBUxy getSnappedPosition(const DBUxy pos, const RoundingStrategy roudingStrategy = ROUND_NEAREST, const bool clamp = false) const; DBU getRowPosition(const int row) const; DBU getRowMaxPosition() const; DBU getColPosition(const int col) const; DBU getColMaxPosition() const; DBUxy getTrackMaxPosition() const; DBU getTrackMaxPosition(const Dimension dim) const; Rsyn::PhysicalRoutingGrid getBottomRoutingGrid() const; Rsyn::PhysicalRoutingGrid getTopRoutingGrid() const; bool hasBottomRoutingGrid() const; bool hasTopRoutingGrid() const; DBUxy getGridMinPosition() const; DBUxy getGridMaxPosition() const; DBUxy getTrackMinPosition(const PhysicalLayerDirection dir, const int index) const; DBUxy getTrackMaxPosition(const PhysicalLayerDirection dir, const int index) const; }; // end class } // end namespace #endif /* PHYSICALROUTINGGRID_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalRoutingPoint.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalRoutingPoint.h * Author: jucemar * * Created on 23 de Maio de 2017, 20:32 */ #ifndef PHYSICALDESIGN_PHYSICALROUTINGPOINT_H #define PHYSICALDESIGN_PHYSICALROUTINGPOINT_H namespace Rsyn { class PhysicalRoutingPoint : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; protected: //! @brief Constructs a Rsyn::PhysicalRoutingPoint object with a pointer to Rsyn::PhysicalRoutingPointData. PhysicalRoutingPoint(PhysicalRoutingPointData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalRoutingPoint object with a null pointer to Rsyn::PhysicalRoutingPointData. PhysicalRoutingPoint() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalRoutingPoint object with a null pointer to Rsyn::PhysicalRoutingPointData. PhysicalRoutingPoint(std::nullptr_t) : Proxy(nullptr) { } DBUxy getPosition() const; DBU getPosition(const Dimension dim) const; DBU getExtension() const; Rsyn::PhysicalVia getVia() const; /*! @details "RECT ( deltax1 deltay1 deltax2 deltay2 ) Indicates that a rectangle is created from the previous ( x y ) routing point using the delta values. The RECT values leave the current point and layer unchanged." Source: LEf/DEf Reference Manual 5.8 */ const Bounds & getRectangle() const; bool hasExtension() const; bool hasRectangle() const; bool hasVia() const; }; // end class // ----------------------------------------------------------------------------- class PhysicalRoutingPointPair { friend class PhysicalWireSegment; public: PhysicalRoutingPoint getSource() const {return clsSourcePoint;} PhysicalRoutingPoint getTarget() const {return clsTargetPoint;} DBUxy getExtendedSourcePosition() const {return clsExtendedSourcePosition;} DBUxy getExtendedTargetPosition() const {return clsExtendedTargetPosition;} private: PhysicalRoutingPoint clsSourcePoint; PhysicalRoutingPoint clsTargetPoint; DBUxy clsExtendedSourcePosition; DBUxy clsExtendedTargetPosition; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALROUTINGPOINT_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalRow.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalRow.h * Author: jucemar * * Created on 14 de Setembro de 2016, 22:29 */ #ifndef PHYSICALDESIGN_PHYSICALROW_H #define PHYSICALDESIGN_PHYSICALROW_H namespace Rsyn { class PhysicalRow : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalRow object with a pointer to Rsyn::PhysicalRowData. PhysicalRow(PhysicalRowData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalRow object with a null pointer to Rsyn::PhysicalRowData. PhysicalRow() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalRow object with a null pointer to Rsyn::PhysicalRowData. PhysicalRow(std::nullptr_t) : Proxy(nullptr) {} //! @brief Returns the Rsyn::PhysicalRow name. std::string getName() const; //! @brief Returns the Rsyn::PhysicalRow site name. std::string getSiteName() const; //! @brief Returns the Rsyn::PhysicalRow width in DBU. DBU getWidth() const; //! @brief Returns the Rsyn::PhysicalRow height in DBU. DBU getHeight() const ; //! @brief Returns the Rsyn::PhysicalRow lower-left X or Y point. DBU getOrigin(const Dimension dim) const; //! @brief Returns the Rsyn::PhysicalRow lower-left point. DBUxy getOrigin() const; //! @brief Returns the Rsyn::PhysicalRow step length for X or Y. DBU getStep(const Dimension dim) const; //! @brief Returns the Rsyn::PhysicalRow step length. In X is the width while in Y is the height. DBUxy getStep() const; //! @brief Returns the total number of sites in the Rsyn::PhsyicalRow int getNumSites(const Dimension dim) const ; //! @brief Returns the Rsyn::PhysicalSite object. Rsyn::PhysicalSite getPhysicalSite() const; //! @brief Returns the site width in DBU. DBU getSiteWidth() const ; //! @brief Returns the site height in DBU. DBU getSiteHeight() const; //! @brief Returns the coordinate point in the left-lower (LOWER parameter) or right-upper (UPPER parameter) corner. DBUxy getCoordinate(const Boundary bound) const; //! @brief Returns the coordinate point in the left-lower (LOWER parameter) or right-upper (UPPER parameter) corner //! and for X or Y dimensions. DBU getCoordinate(const Boundary bound, const Dimension dim) const ; //! @brief Returns the rectangular Bounds of the Rsyn:PhsyicalRow. const Bounds &getBounds() const; //! @brief Returns the Rsyn::PhysicalOrientation of th eRsyn::PhysicalRow. //! @details Rsyn::PhysicalOrientation may be: 1) ORIENTATION_N, 2) ORIENTATION_E, //! 3) ORIENTATION_S, 4) ORIENTATION_W, 5) ORIENTATION_FN, 6) ORIENTATION_FE, //! 7) ORIENTATION_FS, or 8) ORIENTATION_FW. Rsyn::PhysicalOrientation getSiteOrientation() const ; //! @brief Returns the Rsyn::PhysicalSymmetry of Rsyn::PhysicalRow. //! @details Rsyn::PhysicalSymmetry may be: 1) SYMMETRY_X, or 2) SYMMETRY_Y. Rsyn::PhysicalSymmetry getSymmetry() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALROW_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalSite.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSite.h * Author: jucemar * * Created on 12 de Setembro de 2016, 22:47 */ #ifndef PHYSICALDESIGN_PHYSICALSITE_H #define PHYSICALDESIGN_PHYSICALSITE_H namespace Rsyn { class PhysicalSite : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; protected: //! @brief Constructs a Rsyn::PhysicalSite object with a pointer to Rsyn::PhysicalSiteData. PhysicalSite(PhysicalSiteData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalSite object with a null pointer to Rsyn::PhysicalSiteData. PhysicalSite() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalSite object with a null pointer to Rsyn::PhysicalSiteData. PhysicalSite(std::nullptr_t) : Proxy(nullptr) {} //! @brief Returns the Rsyn::PhysicalSite name. std::string getName() const; //! @brief Returns the Rsyn::PhysicalSit class. //! @param Rsyn::PhysicalSiteClass may be 1) PAD or 2) CORE. Rsyn::PhysicalSiteClass getClass() const; //! @brief Returns the site size. In X is the width and in Y is the height. DBUxy getSize() const; //! @brief Returns the site width. DBU getWidth() const; //! @brief Returns the site heigth. DBU getHeight() const; //! @brief Returns site width if Dimension is X. Otherwise, returns the site height. DBU getLength(const Dimension dim) const; //! @brief Returns the site symmetry Rsyn::PhysicalSymmetry getSymmetry() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALSITE_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalSpacing.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSpacing.h * Author: jucemar * * Created on 15 de Setembro de 2016, 18:56 */ #ifndef PHYSICALDESIGN_PHYSICALSPACING_H #define PHYSICALDESIGN_PHYSICALSPACING_H namespace Rsyn { class PhysicalSpacing : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalSpacing object with a pointer to Rsyn::PhysicalSpacingData. PhysicalSpacing(PhysicalSpacingData * data) : Proxy(data) {} public: //! @brief Constructs a Rsyn::PhysicalSpacing object with a null pointer to Rsyn::PhysicalSpacingData. PhysicalSpacing() : Proxy(nullptr) {} //! @brief Constructs a Rsyn::PhysicalSpacing object with a null pointer to Rsyn::PhysicalSpacingData. PhysicalSpacing(std::nullptr_t) : Proxy(nullptr) {} //! @brief Returns the first Rsyn::PhysicalLayer object. Rsyn::PhysicalLayer getLayer1() const; //! @brief Returns the second Rsyn::PhysicalLayer object. Rsyn::PhysicalLayer getLayer2() const; //! @brief Returns the distance in DBU DBU getDistance() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALSPACING_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalSpecialNet.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSpecialNet.h * Author: jucemar * * Created on 23 de Maio de 2017, 20:58 */ #ifndef PHYSICALDESIGN_PHYSICALSPECIALNET_H #define PHYSICALDESIGN_PHYSICALSPECIALNET_H namespace Rsyn { class PhysicalSpecialNet : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; protected: //! @brief Constructs a Rsyn::PhysicalSpecialNet object with a pointer to Rsyn::PhysicalSpecialNetData. PhysicalSpecialNet(PhysicalSpecialNetData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalSpecialNet object with a null pointer to Rsyn::PhysicalSpecialNetData. PhysicalSpecialNet() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalSpecialNet object with a null pointer to Rsyn::PhysicalSpecialNetData. PhysicalSpecialNet(std::nullptr_t) : Proxy(nullptr) { } const DefNetDscp & getNet() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALSPECIALNET_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalSpecialWire.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSpecialWire.h * Author: jucemar * * Created on 23 de Maio de 2017, 21:11 */ #ifndef PHYSICALDESIGN_PHYSICALSPECIALWIRE_H #define PHYSICALDESIGN_PHYSICALSPECIALWIRE_H namespace Rsyn { class PhysicalSpecialWire : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; protected: //! @brief Constructs a Rsyn::PhysicalSpecialWire object with a pointer to Rsyn::PhysicalSpecialWireData. PhysicalSpecialWire(PhysicalSpecialWireData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalSpecialWire object with a null pointer to Rsyn::PhysicalSpecialWireData. PhysicalSpecialWire() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalSpecialWire object with a null pointer to Rsyn::PhysicalSpecialWireData. PhysicalSpecialWire(std::nullptr_t) : Proxy(nullptr) { } Rsyn::PhysicalLayer getPhysicalLayer(); DBU getWireWidth() const; const std::vector & allRoutingPoints() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALSPECIALWIRE_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalTracks.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalTracks.h * Author: jucemar * * Created on 24 de Maio de 2017, 21:51 */ #ifndef PHYSICALDESIGN_PHYSICALTRACKS_H #define PHYSICALDESIGN_PHYSICALTRACKS_H namespace Rsyn { class PhysicalTracks : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalTracks object with a pointer to Rsyn::PhysicalTracksData. PhysicalTracks(PhysicalTracksData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalTracks object with a null pointer to Rsyn::PhysicalTracksData. PhysicalTracks() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalTracks object with a null pointer to Rsyn::PhysicalTracksData. PhysicalTracks(std::nullptr_t) : Proxy(nullptr) { } PhysicalTrackDirection getDirection() const; DBU getLocation() const; DBU getSpace() const; int getNumberOfTracks() const; std::size_t getNumberOfLayers() const; const std::vector & allLayers() const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALTRACKS_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalVia.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalVia.h * Author: jucemar * * Created on 14 de Maio de 2017, 15:03 */ #ifndef PHYSICALDESIGN_PHYSICALVIA_H #define PHYSICALDESIGN_PHYSICALVIA_H namespace Rsyn { class PhysicalVia : public Proxy { friend class PhysicalDesign; friend class PhysicalDesignData; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalVia object with a pointer to Rsyn::PhysicalViaData. PhysicalVia(PhysicalViaData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalVia object with a null pointer to Rsyn::PhysicalViaData. PhysicalVia() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalVia object with a null pointer to Rsyn::PhysicalViaData. PhysicalVia(std::nullptr_t) : Proxy(nullptr) { } //! @brief Returns via name const std::string & getName() const; //! @brief returns the top layer of the via Rsyn::PhysicalLayer getTopLayer() const; //! @brief returns the cut layer of the via Rsyn::PhysicalLayer getCutLayer() const; //! @brief returns the bottom layer of the via Rsyn::PhysicalLayer getBottomLayer() const; //! @brief returns the respective layer Rsyn::PhysicalLayer getLayer(const PhysicalViaLayerType type) const; bool isViaDesign() const; bool isViaRule() const; bool isViaGeometry() const; bool hasViaRule() const; bool hasRowCol() const; bool hasOrigin() const; bool hasOffset() const; bool hasPattern() const; ViaType getViaType() const; Rsyn::PhysicalViaRuleBase getViaRule() const; DBU getCutSize(const Dimension dim) const; DBU getSpacing(const Dimension dim) const; DBU getEnclosure(const ViaLevel level, const Dimension dim) const; DBU getOrigin(const Dimension dim) const; DBU getOffset(const ViaLevel level, const Dimension dim) const; int getNumRows() const; int getNumCols() const; const std::string & getPattern() const; const std::vector & allBottomGeometries() const; const std::vector & allCutGeometries() const; const std::vector & allTopGeometries() const; const std::vector & allGeometries(const PhysicalViaLayerType layer) const; }; // end class } // end namespace #endif /* PHYSICALDESIGN_PHYSICALVIA_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalViaGeometry.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalViaGeometry.h * Author: jucemar * * Created on November 12, 2018, 5:52 PM */ #ifndef RSYN_DATABASE_PHYSICALVIAGEOMETRY_H #define RSYN_DATABASE_PHYSICALVIAGEOMETRY_H namespace Rsyn { class PhysicalViaGeometry : public Proxy { friend class PhysicalDesign; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalViaGeometry object with a pointer to Rsyn::ViaGeometryData. PhysicalViaGeometry(ViaGeometryData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalViaGeometry object with a null pointer to Rsyn::ViaGeometryData. PhysicalViaGeometry() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalViaGeometry object with a null pointer to Rsyn::ViaGeometryData. PhysicalViaGeometry(std::nullptr_t) : Proxy(nullptr) { } const Bounds & getBounds() const; int getMaskNumber() const; }; // end class } // end namespace #endif /* RSYN_DATABASE_PHYSICALVIAGEOMETRY_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalViaRule.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalViaRule.h * Author: jucemar * * Created on November 12, 2018, 5:53 PM */ #ifndef RSYN_DATABASE_PHYSICALVIARULE_H #define RSYN_DATABASE_PHYSICALVIARULE_H namespace Rsyn { class PhysicalViaRule : public PhysicalViaRuleBase { friend class PhysicalDesign; friend class PhysicalViaRuleBase; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalViaRule object with a pointer to Rsyn::ViaRuleData. PhysicalViaRule(ViaRuleData * data) : PhysicalViaRuleBase(data) { } public: //! @brief Constructs a Rsyn::PhysicalViaRule object with a null pointer to Rsyn::ViaRuleData. PhysicalViaRule() : PhysicalViaRuleBase(nullptr) { } //! @brief Constructs a Rsyn::PhysicalViaRule object with a null pointer to Rsyn::ViaRuleData. PhysicalViaRule(std::nullptr_t) : PhysicalViaRuleBase(nullptr) { } //! @brief Returns the via rule relative index int getRelativeIndex() const; //! @brief Returns the top or bottom routing layers in the via rule. Rsyn::PhysicalLayer getLayer(const Rsyn::ViaLevel level) const; //! @brief Returns the top or bottom routing layer directions in the via rule. Rsyn::PhysicalLayerDirection getLayerDirection(const Rsyn::ViaLevel level) const; //! @brief Returns all cut layers defined in via rule. const std::vector & allVias() const; }; // end class } // end namespace #endif /* RSYN_DATABASE_PHYSICALVIARULE_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalViaRuleBase.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalViaRuleBase.h * Author: jucemar * * Created on November 13, 2018, 3:37 PM */ #ifndef RSYN_DATABASE_PHYSICALVIARULEBASE_H #define RSYN_DATABASE_PHYSICALVIARULEBASE_H namespace Rsyn { class PhysicalViaRuleBase : public Proxy { friend class PhysicalDesign; friend class PhysicalVia; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalViaRule object with a pointer to Rsyn::ViaRuleData. PhysicalViaRuleBase(ViaRuleData * data) : Proxy(data) { } public: //! @brief Constructs a Rsyn::PhysicalViaRule object with a null pointer to Rsyn::ViaRuleData. PhysicalViaRuleBase() : Proxy(nullptr) { } //! @brief Constructs a Rsyn::PhysicalViaRule object with a null pointer to Rsyn::ViaRuleData. PhysicalViaRuleBase(std::nullptr_t) : Proxy(nullptr) { } //! @brief Returns the via rule base index int getIndex() const; //! @brief Returns the via rule base as via rule generate PhysicalViaRule asViaRule() const; //! @brief Returns the via rule base as via rule generate PhysicalViaRuleGenerate asViaRuleGenerate() const; //! @brief Returns if via rule base is only via rule bool isViaRule() const; //! @brief Returns if the via rule is generate bool isViaRuleGenerate() const; //! @brief Returns the via rule name const std::string & getName() const; //! @brief Returns the min and max range of the top or bottom routing layer directions in the via rule has been defined. bool hasWidth(const Rsyn::ViaLevel level) const; //! @brief Returns the min and max range of the top or bottom routing layer directions in the via rule. DBU getWidth(const Rsyn::ViaLevel level, const Rsyn::ViaRange range) const; }; // end class } // end namespace #endif /* RSYN_DATABASE_PHYSICALVIARULEBASE_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/decl/PhysicalViaRuleGenerate.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalViaGenerate.h * Author: jucemar * * Created on November 12, 2018, 5:53 PM */ #ifndef RSYN_DATABASE_PHYSICALVIAGENERATE_H #define RSYN_DATABASE_PHYSICALVIAGENERATE_H namespace Rsyn { class PhysicalViaRuleGenerate : public PhysicalViaRuleBase { friend class PhysicalDesign; friend class PhysicalViaRuleBase; RSYN_FRIEND_OF_GENERIC_LIST_COLLECTION; protected: //! @brief Constructs a Rsyn::PhysicalViaRuleGenerate object with a pointer to Rsyn::ViaRuleGenerateData. PhysicalViaRuleGenerate(ViaRuleData * data) : PhysicalViaRuleBase(data) { } public: //! @brief Constructs a Rsyn::PhysicalViaRuleGenerate object with a null pointer to Rsyn::ViaRuleGenerateData. PhysicalViaRuleGenerate() : PhysicalViaRuleBase(nullptr) { } //! @brief Constructs a Rsyn::PhysicalViaRuleGenerate object with a null pointer to Rsyn::ViaRuleGenerateData. PhysicalViaRuleGenerate(std::nullptr_t) : PhysicalViaRuleBase(nullptr) { } //! @brief Returns the via rule relative index int getRelativeIndex() const; //! @brief Returns if the via rule generate can be used to regular routing bool isDefault() const; //! @brief Returns the via rule generate layer. It can be bottom, top or cut layer types Rsyn::PhysicalLayer getLayer(const Rsyn::PhysicalViaLayerType layer) const; DBU getEnclosure1(const Rsyn::ViaLevel level) const; DBU getEnclosure2(const Rsyn::ViaLevel level) const; Bounds getCutBounds() const; DBU getCutSpacing(const Dimension dim) const; bool hasCutResistance() const; float getCutResistance() const; private: }; // end class } // end namespace #endif /* PHYSICALVIAGENERATE_H */ ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/LayerViaManager.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: LayerViaManager.h * Author: jucemar * * Created on February 3, 2018, 9:31 AM */ namespace Rsyn { inline const std::vector & LayerViaManager::allVias(Rsyn::PhysicalLayer layer) const { return data->clsVias[layer]; } // end method // ----------------------------------------------------------------------------- inline const std::vector & LayerViaManager::allBottomVias(Rsyn::PhysicalLayer layer) const { return data->clsBottomVias[layer]; } // end method // ----------------------------------------------------------------------------- inline const std::vector & LayerViaManager::allTopVias(Rsyn::PhysicalLayer layer) const { return data->clsTopVias[layer]; } // end method // ----------------------------------------------------------------------------- inline bool LayerViaManager::hasVias(Rsyn::PhysicalLayer layer) const { if(layer == nullptr) return false; if(layer.getType() != Rsyn::PhysicalLayerType::ROUTING) return false; const std::vector & vias = data->clsVias[layer]; return vias.size() > 0; } // end method // ----------------------------------------------------------------------------- inline bool LayerViaManager::hasBottomVias(Rsyn::PhysicalLayer layer) const { if(layer == nullptr) return false; if(layer.getType() != Rsyn::PhysicalLayerType::ROUTING) return false; const std::vector & vias = data->clsBottomVias[layer]; return vias.size() > 0; } // end method // ----------------------------------------------------------------------------- inline bool LayerViaManager::hasTopVias(Rsyn::PhysicalLayer layer) const { if(layer == nullptr) return false; if(layer.getType() != Rsyn::PhysicalLayerType::ROUTING) return false; const std::vector & vias = data->clsTopVias[layer]; return vias.size() > 0; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalCell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ namespace Rsyn { // ----------------------------------------------------------------------------- inline Rsyn::Cell PhysicalCell::getCell() const { return data->clsInstance.asCell(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalCell::isFixed() const { return data->clsInstance.isFixed(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalCell::isMacroBlock() const { return data->clsInstance.isMacroBlock(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalCell::isPlaced() const { return data->clsPlaced; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalCell::getInitialPosition() const { return data->clsInitialPos; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalCell::getInitialPosition(const Dimension dim) const { return data->clsInitialPos[dim]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalCell::getDisplacement() const { const DBUxy pos = getPosition(); const DBUxy initial = getInitialPosition(); return std::abs(pos[X] - initial[X]) + std::abs(pos[Y] - initial[Y]); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalCell::getDisplacement(const Dimension dim) const { const DBU pos = getPosition(dim); const DBU initial = getInitialPosition(dim); return std::abs(initial - pos); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalCell::getDisplacement(const DBUxy pos) const { const DBUxy lower = getPosition(); return std::abs(lower[X] - pos[X]) + std::abs(lower[Y] - pos[Y]); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalCell::getDisplacement(const DBU pos, const Dimension dim) const { const DBU lower = getPosition(dim); return std::abs(lower - pos); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalCell::getDisplacementFromCurrentPosition(const DBUxy pos) const { const DBUxy lower = getPosition(); return std::abs(lower[X] - pos[X]) + std::abs(lower[Y] - pos[Y]); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalCell::getDisplacementFromCurrentPosition(const DBU pos, const Dimension dim) const { const DBU lower = getPosition(dim); return std::abs(lower - pos); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalCell::getDisplacementFromInitialPosition(const DBUxy pos) const { const DBUxy lower = getInitialPosition(); return std::abs(lower[X] - pos[X]) + std::abs(lower[Y] - pos[Y]); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalCell::getDisplacementFromInitialPosition(const DBU pos, const Dimension dim) const { const DBU lower = getInitialPosition(dim); return std::abs(lower - pos); } // end method // ----------------------------------------------------------------------------- inline PhysicalTransform PhysicalCell::getTransform(const bool origin) const { return getInstance().getTransform(origin); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalCell::hasLayerBounds() const { return data->clsHasLayerBounds; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalDesign.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ #include namespace Rsyn { // ----------------------------------------------------------------------------- void PhysicalDesign::loadLibrary(const LefDscp & library) { if (!data) { std::cout << "ERROR: Physical Design was not configured!\n" << "Please call first initPhysicalDesign!" << std::endl; return; } // end if if (library.clsLefUnitsDscp.clsHasDatabase) { if (getDatabaseUnits(LIBRARY_DBU) == 0) { data->clsDBUs[LIBRARY_DBU] = library.clsLefUnitsDscp.clsDatabase; } else { if (getDatabaseUnits(LIBRARY_DBU) != library.clsLefUnitsDscp.clsDatabase) { std::cout << "WARNING: Stored LEF database units " << getDatabaseUnits(LIBRARY_DBU) << " is not equal to LEF database units defined in Library " << library.clsLefUnitsDscp.clsDatabase << ".\n"; std::cout << "WARNING: Lef library elements were NOT initialized!\n"; return; } // end if } // end if-else } // end if // Initializing physical sites data->clsPhysicalSites.reserve(library.clsLefSiteDscps.size()); for (const LefSiteDscp & lefSite : library.clsLefSiteDscps) { addPhysicalSite(lefSite); } // end for // Initializing physical layers data->clsPhysicalLayers.reserve(library.clsLefLayer.size()); Rsyn::PhysicalLayerData * lower = nullptr; for (lefiLayer* lefLayer : library.clsLefLayer) { lower = addPhysicalLayer(lefLayer, lower); } // end for // Initializing physical vias data->clsPhysicalVias.reserve(library.clsLefViaDscps.size()); for (const LefViaDscp & via : library.clsLefViaDscps) { addPhysicalVia(via); } // end for // Initialize rule and generate physical vias const int numViaRules = library.clsLefViaRuleDscps.size(); data->clsPhysicalViaRuleBases.reserve(numViaRules); data->clsPhysicalViaRules.reserve(numViaRules); data->clsPhysicalViaRuleGenerates.reserve(numViaRules); for (const LefViaRuleDscp & viaRuleDscp : library.clsLefViaRuleDscps) { addPhysicalViaRule(viaRuleDscp); } // end for data->clsPhysicalViaRules.shrink_to_fit(); data->clsPhysicalViaRuleGenerates.shrink_to_fit(); // initializing physical spacing for (const LefSpacingDscp & spc : library.clsLefSpacingDscps) { addPhysicalSpacing(spc); } // end for // initializing physical cells (LEF macros) for (const LefMacroDscp & macro : library.clsLefMacroDscps) { // Adding Physical Library cell to Physical Layer Rsyn::LibraryCell libCell = addPhysicalLibraryCell(macro); // Adding Physical Library pins to Physical Layer for (const LefPinDscp &lpin : macro.clsPins) { addPhysicalLibraryPin(libCell, lpin); } // end for } // end for } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::loadDesign(const DefDscp & design) { if (data->clsLoadDesign) { std::cout << "WARNING: Design was already loaded. Skipping ... \n"; return; } // end if data->clsLoadDesign = true; // Adding Library cell to Physical Layer data->clsDBUs[DESIGN_DBU] = design.clsDatabaseUnits; data->clsPhysicalDie.clsBounds = design.clsDieBounds; if (getDatabaseUnits(LIBRARY_DBU) % getDatabaseUnits(DESIGN_DBU) != 0) { std::cout << "ERROR: Invalid DEF database units " << getDatabaseUnits(DESIGN_DBU) << " (LEF database units: " << getDatabaseUnits(LIBRARY_DBU) << ").\n"; std::cout << "DEF design units should be lower or equal to LEF design units and must have a integer multiple. Physical design was not initialized!\n"; return; } // end if // This operation always results in an integer number factor. // LEF/DEF specifications prohibit division that results in a real number factor. data->clsDBUs[MULT_FACTOR_DBU] = getDatabaseUnits(LIBRARY_DBU) / getDatabaseUnits(DESIGN_DBU); // Adding design defined vias std::size_t numVias = data->clsPhysicalVias.size() + design.clsVias.size(); data->clsPhysicalVias.reserve(numVias); for (const DefViaDscp & via : design.clsVias) { addPhysicalDesignVia(via); } // end for // initializing physical cells (DEF Components) for (const DefComponentDscp & component : design.clsComps) { // Adding Physical cell to Physical Layer Rsyn::Cell cell = data->clsDesign.findCellByName(component.clsName); if (!cell) { throw Exception("Cell " + component.clsName + " not found.\n"); } // end if addPhysicalCell(cell, component); } // end for // Initializing circuit ports for (const DefPortDscp & pin_port : design.clsPorts) { // Adding Library cell to Physical Layer Rsyn::Port cell = data->clsDesign.findPortByName(pin_port.clsName); if (!cell) { throw Exception("Port " + pin_port.clsName + " not found.\n"); } // end if addPhysicalPort(cell, pin_port); } // end for //Initializing circuit rows and defining circuit bounds Rsyn::PhysicalModule phModule = getPhysicalModule(data->clsModule); Bounds & bounds = phModule->clsInstance->clsBounds; bounds[LOWER].apply(+std::numeric_limits::max()); bounds[UPPER].apply(-std::numeric_limits::max()); data->clsPhysicalRows.reserve(design.clsRows.size()); // reserving space for rows for (const DefRowDscp & defRow : design.clsRows) { addPhysicalRow(defRow); } // end for data->clsMapPhysicalRegions.reserve(design.clsRegions.size()); data->clsPhysicalRegions.reserve(design.clsRegions.size()); for (const DefRegionDscp & defRegion : design.clsRegions) addPhysicalRegion(defRegion); data->clsMapPhysicalGroups.reserve(design.clsGroups.size()); data->clsPhysicalGroups.reserve(design.clsGroups.size()); for (const DefGroupDscp & defGroup : design.clsGroups) addPhysicalGroup(defGroup); for (const DefNetDscp & net : design.clsNets) addPhysicalNet(net); data->clsPhysicalSpecialNets.reserve(design.clsSpecialNets.size()); for (const DefNetDscp & specialNet : design.clsSpecialNets) addPhysicalSpecialNet(specialNet); data->clsPhysicalTracks.reserve(design.clsTracks.size()); for (const DefTrackDscp & track : design.clsTracks) addPhysicalTracks(track); initRoutingGrid(); initLayerViaManager(); // only to keep coherence in the design; data->clsNumElements[PHYSICAL_PORT] = data->clsDesign.getNumInstances(Rsyn::PORT); data->clsPhysicalGCell.reserve(design.clsGcellGrids.size()); for (const DefGcellGridDscp & gcell : design.clsGcellGrids) { addPhysicalGCell(gcell); } // end for } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::initPhysicalDesign(Rsyn::Design dsg, const Rsyn::Json ¶ms) { if (data) { std::cout << "ERROR: design already set.\nSkipping initialize Physical Design\n"; return; } // end if this->data = new PhysicalDesignData(); if (!params.is_null()) { data->clsEnablePhysicalPins = params.value("clsEnablePhysicalPins", data->clsEnablePhysicalPins); data->clsEnableMergeRectangles = params.value("clsEnableMergeRectangles", data->clsEnableMergeRectangles); data->clsEnableNetPinBoundaries = params.value("clsEnableNetPinBoundaries", data->clsEnableNetPinBoundaries); data->clsMode = getPhysicalDesignModeType(params.value("clsPhysicalDesignMode", "ALL")); } // end if data->clsDesign = dsg; data->clsModule = dsg.getTopModule(); data->clsPhysicalInstances = dsg.createAttribute(); data->clsPhysicalLibraryCells = dsg.createAttribute(); data->clsPhysicalLibraryPins = dsg.createAttribute(); if (data->clsEnablePhysicalPins) data->clsPhysicalPins = dsg.createAttribute(); data->clsPhysicalNets = dsg.createAttribute(); // Initialize data of top module. PhysicalInstanceData &phTopModule = data->clsPhysicalInstances[dsg.getTopModule()]; phTopModule.clsInstance = dsg.getTopModule(); } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::updateAllNetBounds(const bool skipClockNet) { if (skipClockNet && data->clsClkNet) { Rsyn::PhysicalNet phNet = getPhysicalNet(data->clsClkNet); data->clsHPWL -= phNet.getHPWL(); } // end if for (Rsyn::Net net : data->clsModule.allNets()) { //skipping clock network if (skipClockNet && (data->clsClkNet == net)) continue; updateNetBound(net); } // end for } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::updateNetBound(Rsyn::Net net) { // net has not pins. The boundaries are defined by default to 0. if (net.getNumPins() == 0) return; PhysicalNetData &phNet = data->clsPhysicalNets[net]; Bounds &bound = phNet.clsBounds; data->clsHPWL -= bound.computeLength(); // remove old net wirelength bound[UPPER].apply(-std::numeric_limits::max()); bound[LOWER].apply(+std::numeric_limits::max()); const bool updatePinBound = data->clsEnableNetPinBoundaries; for (Rsyn::Pin pin : net.allPins()) { DBUxy pos = getPinPosition(pin); // upper x corner pos if (pos[X] >= bound[UPPER][X]) { bound[UPPER][X] = pos[X]; if (updatePinBound) phNet.clsBoundPins[UPPER][X] = pin; } // end if // lower x corner pos if (pos[X] <= bound[LOWER][X]) { bound[LOWER][X] = pos[X]; if (updatePinBound) phNet.clsBoundPins[LOWER][X] = pin; } // end if // upper y corner pos if (pos[Y] >= bound[UPPER][Y]) { bound[UPPER][Y] = pos[Y]; if (updatePinBound) phNet.clsBoundPins[UPPER][Y] = pin; } // end if // lower y corner pos if (pos[Y] <= bound[LOWER][Y]) { bound[LOWER][Y] = pos[Y]; if (updatePinBound) phNet.clsBoundPins[LOWER][Y] = pin; } // end if } // end for data->clsHPWL += bound.computeLength(); // update hpwl } // end method // ----------------------------------------------------------------------------- // Adding the new Site parameter to PhysicalDesign data structure. void PhysicalDesign::addPhysicalSite(const LefSiteDscp & site) { std::unordered_map::iterator it = data->clsMapPhysicalSites.find(site.clsName); if (it != data->clsMapPhysicalSites.end()) { std::cout << "WARNING: Site " << site.clsName << " was already defined. Skipping ...\n"; return; } // end if // Adding new lib site data->clsPhysicalSites.push_back(PhysicalSite(new PhysicalSiteData())); PhysicalSite phSite = data->clsPhysicalSites.back(); data->clsMapPhysicalSites[site.clsName] = data->clsPhysicalSites.size() - 1; phSite->id = data->clsPhysicalSites.size() - 1; phSite->clsSiteName = site.clsName; double2 size = site.clsSize; size.scale(static_cast (getDatabaseUnits(LIBRARY_DBU))); phSite->clsSize[X] = static_cast (std::round(size[X])); phSite->clsSize[Y] = static_cast (std::round(size[Y])); phSite->clsSiteClass = Rsyn::getPhysicalSiteClass(site.clsSiteClass); phSite->clsSymmetry = Rsyn::getPhysicalSymmetry(site.clsSymmetry); } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalLayerData * PhysicalDesign::addPhysicalLayer(lefiLayer* layer, Rsyn::PhysicalLayerData * lower) { const std::string name(layer->name()); std::unordered_map::iterator it = data->clsMapPhysicalLayers.find(name); if (it != data->clsMapPhysicalLayers.end()) { std::cout << "WARNING: Layer " << name << " was already defined. Skipping ...\n"; // TODO -> return the pointer to the phLayerData of already defined physical layer. return nullptr; } // end if DBU libDBU = getDatabaseUnits(LIBRARY_DBU); Element *element = data->clsPhysicalLayers.create(); Rsyn::PhysicalLayerData * phLayer = &(element->value); phLayer->clsLayer = layer; phLayer->id = data->clsPhysicalLayers.lastId(); phLayer->clsName = name; const Rsyn::PhysicalLayerType type = Rsyn::getPhysicalLayerType(layer->type()); phLayer->clsType = type; phLayer->clsWidth = static_cast (std::round(layer->width() * libDBU)); phLayer->clsRelativeIndex = data->clsNumLayers[type]; data->clsMapPhysicalLayers[name] = phLayer->id; data->clsNumLayers[type]++; if (lower) { lower->clsUpper = phLayer; phLayer->clsLower = lower; } // end if if (type == Rsyn::PhysicalLayerType::ROUTING) data->clsPhysicalRoutingLayerIndeces.push_back(phLayer->id); return phLayer; } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalVia(const LefViaDscp & via) { std::unordered_map::iterator it = data->clsMapPhysicalVias.find(via.clsName); if (it != data->clsMapPhysicalVias.end()) { std::cout << "WARNING: Via " << via.clsName << " was already defined. Skipping ...\n"; return; } // end if // Adding new via data->clsMapPhysicalVias[via.clsName] = data->clsPhysicalVias.size(); data->clsPhysicalVias.push_back(PhysicalVia(new PhysicalViaData())); PhysicalVia phVia = data->clsPhysicalVias.back(); phVia->id = data->clsPhysicalVias.size() - 1; phVia->clsName = via.clsName; phVia->clsIsDefault = via.clsIsDefault; phVia->clsIsViaDesign = false; phVia->clsHasViaRule = via.clsHasViaRule; if (via.clsHasViaRule) { Rsyn::PhysicalViaRuleBase phViaRuleBase = getPhysicalViaRuleBaseByName(via.clsViaRuleName); phVia->clsViaRuleData = phViaRuleBase.data; phVia->clsCutSize[X] = convertMicronToLibraryDatabaseUnits(via.clsXCutSize); phVia->clsCutSize[Y] = convertMicronToLibraryDatabaseUnits(via.clsYCutSize); phVia->clsSpacing[X] = convertMicronToLibraryDatabaseUnits(via.clsXCutSpacing); phVia->clsSpacing[Y] = convertMicronToLibraryDatabaseUnits(via.clsYCutSpacing); phVia->clsEnclosure[BOTTOM_VIA_LEVEL][X] = convertMicronToLibraryDatabaseUnits(via.clsXBottomEnclosure); phVia->clsEnclosure[TOP_VIA_LEVEL][Y] = convertMicronToLibraryDatabaseUnits(via.clsYBottomEnclosure); phVia->clsEnclosure[BOTTOM_VIA_LEVEL][X] = convertMicronToLibraryDatabaseUnits(via.clsXTopEnclosure); phVia->clsEnclosure[TOP_VIA_LEVEL][Y] = convertMicronToLibraryDatabaseUnits(via.clsYTopEnclosure); Rsyn::PhysicalLayer bottom = getPhysicalLayerByName(via.clsBottomLayer); Rsyn::PhysicalLayer cut = getPhysicalLayerByName(via.clsCutLayer); Rsyn::PhysicalLayer top = getPhysicalLayerByName(via.clsTopLayer); phVia->clsLayers[BOTTOM_VIA_LAYER] = bottom.data; phVia->clsLayers[CUT_VIA_LAYER] = cut.data; phVia->clsLayers[TOP_VIA_LAYER] = top.data; if (via.clsHasRowCol) { phVia->clsHasRowCol = true; phVia->clsNumRows = via.clsNumCutRows; phVia->clsNumCols = via.clsNumCutCols; } // end if if (via.clsHasOrigin) { phVia->clsHasOrigin = true; phVia->clsOrigin[X] = convertMicronToLibraryDatabaseUnits(via.clsXOrigin); phVia->clsOrigin[Y] = convertMicronToLibraryDatabaseUnits(via.clsYOrigin); } // end if if (via.clsHasOffset) { phVia->clsHasOffset = true; phVia->clsOffset[BOTTOM_VIA_LEVEL][X] = convertMicronToLibraryDatabaseUnits(via.clsXBottomOffset); phVia->clsOffset[TOP_VIA_LEVEL][Y] = convertMicronToLibraryDatabaseUnits(via.clsYBottomOffset); phVia->clsOffset[BOTTOM_VIA_LEVEL][X] = convertMicronToLibraryDatabaseUnits(via.clsXTopOffset); phVia->clsOffset[TOP_VIA_LEVEL][Y] = convertMicronToLibraryDatabaseUnits(via.clsYTopOffset); } // end if } else { if (via.clsHasResistance) { phVia->clsHasCutResistance = true; phVia->clsCutResistance = via.clsCutResistance; } // end if std::vector> layers; for (const std::pair < std::string, std::deque < LefViaGeometryDscp>> &geoPair : via.clsGeometries) { const std::string & layerName = geoPair.first; Rsyn::PhysicalLayer layer = getPhysicalLayerByName(layerName); assert(layer); layers.push_back(std::make_tuple(layer.getIndex(), layer.data)); } // end for std::sort(layers.begin(), layers.end()); // assert(layers.size() == NUM_VIA_LAYERS); for (int i = 0; i < NUM_VIA_LAYERS; i++) { PhysicalLayerData * layerData = std::get<1>(layers[i]); phVia->clsLayers[i] = layerData; std::vector & viaGeos = phVia->clsViaGeometries[i]; auto iterator = via.clsGeometries.find(layerData->clsName); const std::deque & geoDscps = iterator->second; viaGeos.reserve(geoDscps.size()); for (const LefViaGeometryDscp & geoDscp : geoDscps) { viaGeos.push_back(Rsyn::PhysicalViaGeometry(new ViaGeometryData())); Rsyn::PhysicalViaGeometry viaGeo = viaGeos.back(); viaGeo->id = viaGeos.size() -1; const DoubleRectangle & doubleRect = geoDscp.clsBounds; Bounds & bds = viaGeo->clsBounds; bds[LOWER][X] = convertMicronToLibraryDatabaseUnits(doubleRect[LOWER][X]); bds[LOWER][Y] = convertMicronToLibraryDatabaseUnits(doubleRect[LOWER][Y]); bds[UPPER][X] = convertMicronToLibraryDatabaseUnits(doubleRect[UPPER][X]); bds[UPPER][Y] = convertMicronToLibraryDatabaseUnits(doubleRect[UPPER][Y]); } // end for } // end for } // end if-else } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalViaRule(const LefViaRuleDscp & via) { std::unordered_map::iterator it = data->clsMapPhysicalViaRuleBases.find(via.clsName); if (it != data->clsMapPhysicalViaRuleBases.end()) { std::cout << "WARNING: Via Rule " << via.clsName << " was already defined. Skipping ...\n"; return; } // end if // Adding new lib site data->clsMapPhysicalViaRuleBases[via.clsName] = data->clsPhysicalViaRuleBases.size(); data->clsPhysicalViaRuleBases.push_back(PhysicalViaRuleBase(new ViaRuleData())); PhysicalViaRuleBase phViaRuleBase = data->clsPhysicalViaRuleBases.back(); phViaRuleBase->init(); phViaRuleBase->id = data->clsPhysicalViaRuleBases.size() - 1; phViaRuleBase->clsName = via.clsName; // get index for the routing and cut layers. std::set layerIds; int cutLayerId; for (int i = 0; i < via.clsLayers.size(); i++) { const LefViaRuleLayerDscp & viaLayerDscp = via.clsLayers[i]; Rsyn::PhysicalLayer viaLayer = getPhysicalLayerByName(viaLayerDscp.clsName); if (viaLayer.getType() == Rsyn::PhysicalLayerType::CUT) { cutLayerId = i; } else { layerIds.insert(i); } // end if } // end for // Routing layers const LefViaRuleLayerDscp & viaLayerDscp0 = via.clsLayers[*layerIds.begin()]; const LefViaRuleLayerDscp & viaLayerDscp1 = via.clsLayers[*layerIds.rbegin()]; Rsyn::PhysicalLayer layer0 = getPhysicalLayerByName(viaLayerDscp0.clsName); Rsyn::PhysicalLayer layer1 = getPhysicalLayerByName(viaLayerDscp1.clsName); PhysicalViaLayerType layerType0 = BOTTOM_VIA_LAYER; PhysicalViaLayerType layerType1 = TOP_VIA_LAYER; ViaLevel layerLevel0 = BOTTOM_VIA_LEVEL; ViaLevel layerLevel1 = TOP_VIA_LEVEL; if (layer0.getRelativeIndex() > layer1.getRelativeIndex()) { layerType0 = TOP_VIA_LAYER; layerLevel0 = TOP_VIA_LEVEL; layerType1 = BOTTOM_VIA_LAYER; layerLevel1 = BOTTOM_VIA_LEVEL; } // end if if (viaLayerDscp0.clsHasWidth) { phViaRuleBase->clsHasWidth[layerLevel0] = true; phViaRuleBase->clsWidth[layerLevel0][ViaRange::VIA_RANGE_MIN] = convertMicronToLibraryDatabaseUnits(viaLayerDscp0.clsMinWidth); phViaRuleBase->clsWidth[layerLevel0][ViaRange::VIA_RANGE_MAX] = convertMicronToLibraryDatabaseUnits(viaLayerDscp0.clsMaxWidth); } // end if if (viaLayerDscp1.clsHasWidth) { phViaRuleBase->clsHasWidth[layerLevel1] = true; phViaRuleBase->clsWidth[layerLevel1][ViaRange::VIA_RANGE_MIN] = convertMicronToLibraryDatabaseUnits(viaLayerDscp1.clsMinWidth); phViaRuleBase->clsWidth[layerLevel1][ViaRange::VIA_RANGE_MAX] = convertMicronToLibraryDatabaseUnits(viaLayerDscp1.clsMaxWidth); } // end if if (!via.clsIsGenerate) { phViaRuleBase->clsIsGenerate = false; phViaRuleBase->clsRelativeIndex = data->clsPhysicalViaRules.size(); data->clsPhysicalViaRules.push_back(Rsyn::PhysicalViaRule(phViaRuleBase.data)); phViaRuleBase->clsLayers[layerLevel0] = layer0.data; phViaRuleBase->clsLayers[layerLevel1] = layer1.data; phViaRuleBase->clsLayerDirection[layerLevel0] = viaLayerDscp0.clsIsHorizontal ? PhysicalLayerDirection::HORIZONTAL : PhysicalLayerDirection::VERTICAL; phViaRuleBase->clsLayerDirection[layerLevel1] = viaLayerDscp1.clsIsHorizontal ? PhysicalLayerDirection::HORIZONTAL : PhysicalLayerDirection::VERTICAL; if (!via.clsVias.empty()) { phViaRuleBase->clsVias.reserve(via.clsVias.size()); for (const std::string & viaName : via.clsVias) { Rsyn::PhysicalVia phVia = getPhysicalViaByName(viaName); if (phVia == nullptr) { std::cout << "Via " << viaName << " is not defined in library. Skipping ...\n"; continue; } // end if phViaRuleBase->clsVias.push_back(phVia); } // end for } // end if } else { phViaRuleBase->clsIsGenerate = true; phViaRuleBase->clsIsDefault = via.clsIsDefault; phViaRuleBase->clsRelativeIndex = data->clsPhysicalViaRuleGenerates.size(); data->clsPhysicalViaRuleGenerates.push_back(Rsyn::PhysicalViaRuleGenerate(phViaRuleBase.data)); // cut layer const LefViaRuleLayerDscp & cutLayerDscp = via.clsLayers[cutLayerId]; Rsyn::PhysicalLayer cutLayer = getPhysicalLayerByName(cutLayerDscp.clsName); phViaRuleBase->clsLayers[CUT_VIA_LAYER] = cutLayer.data; DoubleRectangle doubleRect = cutLayerDscp.clsRect; Bounds & bds = phViaRuleBase->clsCutBounds; bds[LOWER][X] = convertMicronToLibraryDatabaseUnits(doubleRect[LOWER][X]); bds[LOWER][Y] = convertMicronToLibraryDatabaseUnits(doubleRect[LOWER][Y]); bds[UPPER][X] = convertMicronToLibraryDatabaseUnits(doubleRect[UPPER][X]); bds[UPPER][Y] = convertMicronToLibraryDatabaseUnits(doubleRect[UPPER][Y]); phViaRuleBase->clsCutSpacing[X] = convertMicronToLibraryDatabaseUnits(cutLayerDscp.clsXSpacing); phViaRuleBase->clsCutSpacing[Y] = convertMicronToLibraryDatabaseUnits(cutLayerDscp.clsYSpacing); if (cutLayerDscp.clsHasResistance) { phViaRuleBase->clsHasCutResistance = true; phViaRuleBase->clsCutResistance = cutLayerDscp.clsCutResistance; } // end if phViaRuleBase->clsLayers[layerType0] = layer0.data; phViaRuleBase->clsLayers[layerType1] = layer1.data; phViaRuleBase->clsEnclosure1[layerLevel0] = convertMicronToLibraryDatabaseUnits(viaLayerDscp0.clsEnclosure1); phViaRuleBase->clsEnclosure1[layerLevel1] = convertMicronToLibraryDatabaseUnits(viaLayerDscp1.clsEnclosure1); phViaRuleBase->clsEnclosure2[layerLevel0] = convertMicronToLibraryDatabaseUnits(viaLayerDscp0.clsEnclosure2); phViaRuleBase->clsEnclosure2[layerLevel1] = convertMicronToLibraryDatabaseUnits(viaLayerDscp1.clsEnclosure2); } // end if-else } // end method // ----------------------------------------------------------------------------- Rsyn::LibraryCell PhysicalDesign::addPhysicalLibraryCell(const LefMacroDscp& macro) { const std::string& name = macro.clsMacro->name(); Rsyn::LibraryCell lCell = data->clsDesign.findLibraryCellByName(name); if (!lCell) { throw Exception("Library Cell " + name + " not found.\n"); } // end if Rsyn::PhysicalLibraryCellData &phlCell = data->clsPhysicalLibraryCells[lCell]; phlCell.clsMacro = macro.clsMacro; double2 size(macro.clsMacro->sizeX(), macro.clsMacro->sizeY()); size.scale(static_cast (getDatabaseUnits(LIBRARY_DBU))); phlCell.clsSize[X] = static_cast (std::round(size[X])); phlCell.clsSize[Y] = static_cast (std::round(size[Y])); // Initializing obstacles in the physical library cell phlCell.clsObs.reserve(macro.clsObs.size()); for (const LefObsDscp &libObs : macro.clsObs) { PhysicalObstacle phObs(new PhysicalObstacleData()); // Guilherme Flach - 2016/11/04 - micron to dbu std::vector scaledBounds; scaledBounds.reserve(libObs.clsBounds.size()); for (DoubleRectangle doubleRect : libObs.clsBounds) { // Jucemar Monteiro - 2017/05/20 - Avoiding cast round errors. doubleRect.scaleCoordinates(static_cast (getDatabaseUnits(LIBRARY_DBU))); scaledBounds.push_back(Bounds()); Bounds & bds = scaledBounds.back(); bds[LOWER][X] = static_cast (std::round(doubleRect[LOWER][X])); bds[LOWER][Y] = static_cast (std::round(doubleRect[LOWER][Y])); bds[UPPER][X] = static_cast (std::round(doubleRect[UPPER][X])); bds[UPPER][Y] = static_cast (std::round(doubleRect[UPPER][Y])); } // end for phlCell.clsObs.push_back(phObs); // if (macro.clsMacroName == "bufx2" || macro.clsMacroName == "BUFX2") { // std::cout << "----#Obstacles: " << macro.clsObs.size() << "\n"; // std::cout << "" << macro.clsObs[0].clsBounds.size() << "\n"; // } if (data->clsEnableMergeRectangles && libObs.clsBounds.size() > 1) { std::vector bounds; mergeBounds(scaledBounds, bounds); phObs->clsBounds.reserve(bounds.size()); for (Bounds & rect : bounds) { //rect.scaleCoordinates(data->clsDesignUnits); phObs->clsBounds.push_back(rect); } // end for } else { phObs->clsBounds = scaledBounds; } // end if-else phObs->clsLayer = getPhysicalLayerByName(libObs.clsMetalLayer); // Mateus - 2018/03/11 - Defensive programming to avoid crashes in ICCAD15 benchmarks. if (!phObs->clsLayer) continue; phObs->id = phlCell.clsObs.size() - 1; // Hard code. After implementing mapping structure in Rsyn, remove this line. if (libObs.clsMetalLayer.compare("metal1") == 0) { phlCell.clsLayerBoundIndex = phlCell.clsObs.size() - 1; } // end if Rsyn::PhysicalObstacle topPhObs = phlCell.clsTopLayerObs; if (topPhObs != nullptr) { if (topPhObs.getLayer().getIndex() < phObs->clsLayer.getIndex()) phlCell.clsTopLayerObs = phObs; } else { phlCell.clsTopLayerObs = phObs; } } // end for // adding physical library cell boundaries defined as a polygon // benchmarks of ICCAD contest define some macro boundaries as metal 1 blockages if (phlCell.clsLayerBoundIndex >= 0) { PhysicalObstacle phObs = phlCell.clsObs[phlCell.clsLayerBoundIndex]; if (phObs.getNumObs() > 1) { // if boundaries are defined by a rectangle. Then boundaries number is one because it is rectangle. DBUxy lower, upper; const Bounds & fst = phObs.allBounds().front(); lower = fst[LOWER]; upper = fst[UPPER]; upper[Y] = lower[Y]; std::list upperPoints; upperPoints.push_back(upper); phlCell.clsPolygonBounds.addPoint(lower[X], lower[Y]); for (const Bounds & bds : phObs.allBounds()) { DBUxy lowPt = bds[LOWER]; DBUxy uppPt = bds[UPPER]; if (lowPt[X] != lower[X]) { phlCell.clsPolygonBounds.addPoint(lower[X], lowPt[Y]); lower = lowPt; phlCell.clsPolygonBounds.addPoint(lower[X], lower[Y]); } // end if if (uppPt[X] != upper[X]) { upperPoints.push_front(DBUxy(upper[X], lowPt[Y])); upper = uppPt; upper[Y] = lowPt[Y]; upperPoints.push_front(upper); } // en if } // end for upperPoints.push_front(phObs.allBounds().back()[UPPER]); phlCell.clsPolygonBounds.addPoint(phObs.allBounds().back()[LOWER][X], phObs.allBounds().back()[UPPER][Y]); for (DBUxy point : upperPoints) { phlCell.clsPolygonBounds.addPoint(point[X], point[Y]); } // end for } // end if } // end if return lCell; } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalLibraryPin(Rsyn::LibraryCell libCell, const LefPinDscp& lefPin) { Rsyn::LibraryPin rsynLibraryPin = libCell.getLibraryPinByName(lefPin.clsPinName); if (!rsynLibraryPin) { throw Exception("Pin '" + lefPin.clsPinName + "' not found in library cell '" + libCell.getName() + "'.\n"); } // end if Rsyn::PhysicalLibraryPinData &phyPin = data->clsPhysicalLibraryPins[rsynLibraryPin]; phyPin.clsLibraryCell = getPhysicalLibraryCell(libCell); phyPin.clsDirection = Rsyn::getPhysicalPinDirection(lefPin.clsPinDirection); phyPin.clsUse = Rsyn::getPhysicalPinUseType(lefPin.clsPinUse); //Assuming that the pin has only one port. phyPin.clsPhysicalPinGeometries.reserve(lefPin.clsPorts.size()); for (const LefPortDscp & lefPort : lefPin.clsPorts) { phyPin.clsPhysicalPinGeometries.push_back(PhysicalPinGeometry(new PhysicalPinGeometryData())); PhysicalPinGeometry phPinPort = phyPin.clsPhysicalPinGeometries.back(); phPinPort->id = phyPin.clsPhysicalPinGeometries.size() - 1; phyPin.clsLayerBound[LOWER] = DBUxy(std::numeric_limits::max(), std::numeric_limits::max()); phyPin.clsLayerBound[UPPER] = DBUxy(std::numeric_limits::min(), std::numeric_limits::min()); phPinPort->clsPinLayers.reserve(lefPort.clsLefPortGeoDscp.size()); for (const LefPortGeometryDscp & lefPortGeo : lefPort.clsLefPortGeoDscp) { phPinPort->clsPinLayers.push_back(PhysicalPinLayer(new PhysicalPinLayerData())); PhysicalPinLayer phPinLayer = phPinPort->clsPinLayers.back(); phPinLayer->id = phPinPort->clsPinLayers.size() - 1; phPinLayer->clsLibLayer = getPhysicalLayerByName(lefPortGeo.clsMetalName); //ICCAD 2015 contest pin bounds definition if (!lefPortGeo.clsBounds.empty()) { phPinLayer->clsBounds.reserve(lefPortGeo.clsBounds.size()); for (DoubleRectangle doubleRect : lefPortGeo.clsBounds) { doubleRect.scaleCoordinates(static_cast (getDatabaseUnits(LIBRARY_DBU))); phPinLayer->clsBounds.push_back(Bounds()); Bounds & bds = phPinLayer->clsBounds.back(); bds[LOWER][X] = static_cast (std::round(doubleRect[LOWER][X])); bds[LOWER][Y] = static_cast (std::round(doubleRect[LOWER][Y])); bds[UPPER][X] = static_cast (std::round(doubleRect[UPPER][X])); bds[UPPER][Y] = static_cast (std::round(doubleRect[UPPER][Y])); phyPin.clsLayerBound[LOWER][X] = std::min(phyPin.clsLayerBound[LOWER][X], bds[LOWER][X]); phyPin.clsLayerBound[LOWER][Y] = std::min(phyPin.clsLayerBound[LOWER][Y], bds[LOWER][Y]); phyPin.clsLayerBound[UPPER][X] = std::max(phyPin.clsLayerBound[UPPER][X], bds[UPPER][X]); phyPin.clsLayerBound[UPPER][Y] = std::max(phyPin.clsLayerBound[UPPER][Y], bds[UPPER][Y]); } // end for } // end if if (!lefPortGeo.clsLefPolygonDscp.empty()) { phyPin.clsLayerBound[LOWER] = DBUxy(std::numeric_limits::max(), std::numeric_limits::max()); phyPin.clsLayerBound[UPPER] = DBUxy(std::numeric_limits::min(), std::numeric_limits::min()); phPinLayer->clsPolygons.reserve(lefPortGeo.clsLefPolygonDscp.size()); for (const LefPolygonDscp & poly : lefPortGeo.clsLefPolygonDscp) { phPinLayer->clsPolygons.resize(phPinLayer->clsPolygons.size() + 1); Polygon &polygon = phPinLayer->clsPolygons.back(); for (double2 point : poly.clsPolygonPoints) { point.scale(static_cast (getDatabaseUnits(LIBRARY_DBU))); DBUxy pt(static_cast (std::round(point[X])), static_cast (std::round(point[Y]))); polygon.addPoint(pt[X], pt[Y]); phyPin.clsLayerBound[LOWER][X] = std::min(phyPin.clsLayerBound[LOWER][X], pt[X]); phyPin.clsLayerBound[LOWER][Y] = std::min(phyPin.clsLayerBound[LOWER][Y], pt[Y]); phyPin.clsLayerBound[UPPER][X] = std::max(phyPin.clsLayerBound[UPPER][X], pt[X]); phyPin.clsLayerBound[UPPER][Y] = std::max(phyPin.clsLayerBound[UPPER][Y], pt[Y]); } // end for } // end for } // end if } // end for if (phPinPort.getNumPinLayers() > 1) { std::sort(phPinPort->clsPinLayers.begin(), phPinPort->clsPinLayers.end(), [](PhysicalPinLayer phPinLayer0, PhysicalPinLayer phPinLayer1) { Rsyn::PhysicalLayer phLayer0 = phPinLayer0.getLayer(); Rsyn::PhysicalLayer phLayer1 = phPinLayer1.getLayer(); return phLayer0.getIndex() < phLayer1.getIndex(); }); // end sort } // end if } // end for } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalCell(Rsyn::Instance cell, const DefComponentDscp& component) { PhysicalLibraryCellData &phLibCell = data->clsPhysicalLibraryCells[cell.asCell().getLibraryCell()]; // TODO: assuming instance is a cell PhysicalInstanceData & physicalCell = data->clsPhysicalInstances[cell]; physicalCell.clsInstance = cell; Rsyn::InstanceTag tag = data->clsDesign.getTag(cell); tag.setFixed(component.clsIsFixed); const bool isBlock = !strcmp(phLibCell.clsMacro->macroClass(), "BLOCK"); const bool isRing = !strcmp(phLibCell.clsMacro->macroClass(), "RING"); tag.setMacroBlock(isBlock || isRing); if (component.clsIsFixed) { if (phLibCell.clsLayerBoundIndex > -1) { PhysicalObstacle obs = phLibCell.clsObs[phLibCell.clsLayerBoundIndex]; data->clsNumElements[PHYSICAL_FIXEDBOUNDS] += obs->clsBounds.size(); } else { data->clsNumElements[PHYSICAL_FIXEDBOUNDS]++; } // end if-else data->clsNumElements[PHYSICAL_FIXED]++; } // end if physicalCell.clsPlaced = component.clsIsPlaced; physicalCell.clsBlock = isBlock; if (physicalCell.clsBlock) data->clsNumElements[PHYSICAL_BLOCK]++; if (cell.isMovable()) data->clsNumElements[PHYSICAL_MOVABLE]++; physicalCell.clsHasLayerBounds = phLibCell.clsLayerBoundIndex > -1; physicalCell.clsInstance->clsOrientation = getPhysicalOrientation(component.clsOrientation); const DBU width = phLibCell.clsSize[X]; const DBU height = phLibCell.clsSize[Y]; DBUxy pos = component.clsPos; physicalCell.clsInitialPos = pos; pos[X] += width; pos[Y] += height; physicalCell.clsInstance->clsBounds.updatePoints(physicalCell.clsInitialPos, pos); DBU area = width * height; if (physicalCell.clsBlock) data->clsTotalAreas[PHYSICAL_BLOCK] += area; if (cell.isFixed()) { if (cell.isPort()) data->clsTotalAreas[PHYSICAL_PORT] += area; else data->clsTotalAreas[PHYSICAL_FIXED] += area; } else { data->clsTotalAreas[PHYSICAL_MOVABLE] += area; } // end if-else } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalPort(Rsyn::Instance cell, const DefPortDscp& port) { PhysicalInstanceData & physicalGate = data->clsPhysicalInstances[cell]; physicalGate.clsPortLayer = getPhysicalLayerByName(port.clsLayerName); physicalGate.clsInstance = cell; physicalGate.clsInstance->clsOrientation = getPhysicalOrientation(port.clsOrientation); physicalGate.clsInstance->clsBounds = port.clsLayerBounds; physicalGate.clsInstance->clsPortPos = port.clsPos; physicalGate.clsPort = true; Rsyn::InstanceTag tag = data->clsDesign.getTag(cell); // TODO Getting from port descriptor if it is fixed. tag.setFixed(true); tag.setMacroBlock(false); } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalRow(const DefRowDscp& defRow) { PhysicalSite phSite = getPhysicalSiteByName(defRow.clsSite); if (!phSite) throw Exception("Site " + defRow.clsSite + " was not find for row " + defRow.clsName); // Creates a new cell in the data structure. PhysicalRowData * phRowData = &(data->clsPhysicalRows.create()->value); // TODO: awful phRowData->id = data->clsPhysicalRows.lastId(); phRowData->clsRowName = defRow.clsName; phRowData->clsPhysicalSite = phSite; phRowData->clsSiteOrientation = Rsyn::getPhysicalOrientation(defRow.clsOrientation); phRowData->clsOrigin = defRow.clsOrigin; phRowData->clsStep[X] = phSite.getWidth(); phRowData->clsStep[Y] = phSite.getHeight(); phRowData->clsNumSites[X] = defRow.clsNumX; phRowData->clsNumSites[Y] = defRow.clsNumY; phRowData->clsBounds[LOWER][X] = defRow.clsOrigin[X]; phRowData->clsBounds[LOWER][Y] = defRow.clsOrigin[Y]; phRowData->clsBounds[UPPER][X] = defRow.clsOrigin[X] + phRowData->getWidth(); phRowData->clsBounds[UPPER][Y] = defRow.clsOrigin[Y] + phRowData->getHeight(); Rsyn::PhysicalModule phModule = getPhysicalModule(data->clsModule); Bounds & bounds = phModule->clsInstance->clsBounds; bounds[LOWER] = min(bounds[LOWER], phRowData->clsBounds[LOWER]); bounds[UPPER] = max(bounds[UPPER], phRowData->clsBounds[UPPER]); data->clsTotalAreas[PHYSICAL_PLACEABLE] += phRowData->clsBounds.computeArea(); } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalRegion(const DefRegionDscp& defRegion) { data->clsPhysicalRegions.push_back(PhysicalRegion(new PhysicalRegionData())); Rsyn::PhysicalRegion phRegion = data->clsPhysicalRegions.back(); phRegion->id = data->clsPhysicalRegions.size() - 1; phRegion->clsName = defRegion.clsName; phRegion->clsType = Rsyn::getPhysicalRegionType(defRegion.clsType); phRegion->clsBounds = defRegion.clsBounds; data->clsMapPhysicalRegions[defRegion.clsName] = phRegion->id; } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalGroup(const DefGroupDscp& defGroup) { data->clsPhysicalGroups.push_back(PhysicalGroup(new PhysicalGroupData())); Rsyn::PhysicalGroup phGroup = data->clsPhysicalGroups.back(); phGroup->id = data->clsPhysicalGroups.size() - 1; phGroup->clsName = defGroup.clsName; phGroup->clsPatterns = defGroup.clsPatterns; phGroup->clsRegion = getPhysicalRegionByName(defGroup.clsRegion); data->clsMapPhysicalGroups[defGroup.clsName] = phGroup->id; } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalNet(const DefNetDscp & netDscp) { Rsyn::Net net = data->clsDesign.findNetByName(netDscp.clsName); PhysicalNetData & netData = data->clsPhysicalNets[net]; Rsyn::PhysicalRouting & routing = netData.clsRouting; netData.clsNet = net; for (const DefWireDscp & wireDscp : netDscp.clsWires) { for (const DefWireSegmentDscp & segmentDscp : wireDscp.clsWireSegments) { Rsyn::PhysicalLayer physicalLayer = getPhysicalLayerByName(segmentDscp.clsLayerName); int numPoints = segmentDscp.clsRoutingPoints.size(); Rsyn::PhysicalRoutingWire wire; for (const DefRoutingPointDscp & point : segmentDscp.clsRoutingPoints) { if (point.clsHasRectangle) { Bounds bds = point.clsRect; bds.translate(point.clsPos); routing.addRect(physicalLayer, bds); } else if (point.clsHasVia) { DBUxy pos = segmentDscp.clsRoutingPoints.back().clsPos; Rsyn::PhysicalVia physicalVia = getPhysicalViaByName(point.clsViaName); routing.addVia(physicalVia, pos); } // end if-else if (numPoints > 1) { wire.addRoutingPoint(point.clsPos); } // end if } // end for // it is a wire if (numPoints > 1) { wire.setLayer(physicalLayer); const DefRoutingPointDscp & source = segmentDscp.clsRoutingPoints.front(); const DefRoutingPointDscp & target = segmentDscp.clsRoutingPoints.back(); if (source.clsHasExtension) wire.setSourceExtension(source.clsExtension); if (target.clsHasExtension) wire.setTargetExtension(target.clsExtension); if (segmentDscp.clsRoutedWidth > 0) { wire.setWidth(segmentDscp.clsRoutedWidth); } // end if routing.addWire(wire); } // end if } // end for } // end for } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalSpecialNet(const DefNetDscp & specialNet) { data->clsPhysicalSpecialNets.push_back(PhysicalSpecialNet(new PhysicalSpecialNetData())); Rsyn::PhysicalSpecialNet phSpecialNet = data->clsPhysicalSpecialNets.back(); phSpecialNet->id = data->clsPhysicalSpecialNets.size() - 1; data->clsMapPhysicalSpecialNets[specialNet.clsName] = data->clsPhysicalSpecialNets.size() - 1; phSpecialNet->clsNet = specialNet; } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalTracks(const DefTrackDscp &track) { data->clsPhysicalTracks.push_back(PhysicalTracks(new PhysicalTracksData())); Rsyn::PhysicalTracks phTrack = data->clsPhysicalTracks.back(); phTrack->id = data->clsPhysicalTracks.size() - 1; phTrack->clsDirection = Rsyn::getPhysicalTrackDirectionDEF(track.clsDirection); phTrack->clsLocation = track.clsLocation; phTrack->clsNumTracks = track.clsNumTracks; phTrack->clsSpace = track.clsSpace; phTrack->clsLayers.reserve(track.clsLayers.size()); for (const std::string & layerName : track.clsLayers) { Rsyn::PhysicalLayer phLayer = getPhysicalLayerByName(layerName); if (phLayer) { phTrack->clsLayers.push_back(phLayer); std::vector & trackLayer = data->clsMapLayerToTracks[phLayer]; trackLayer.push_back(phTrack); } // end if } // end for } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::initRoutingGrid() { for (Rsyn::PhysicalTracks track : allPhysicalTracks()) { for (Rsyn::PhysicalLayer phLayer : track.allLayers()) { if (data->clsMapLayerToRoutingGrid.find(phLayer) == data->clsMapLayerToRoutingGrid.end()) { data->clsPhysicalRoutingGrids.push_back(PhysicalRoutingGrid(new PhysicalRoutingGridData())); data->clsMapLayerToRoutingGrid[phLayer] = data->clsPhysicalRoutingGrids.back(); } // end if Rsyn::PhysicalRoutingGrid routingGrid = data->clsMapLayerToRoutingGrid[phLayer]; routingGrid->clsLayer = phLayer; routingGrid->clsTracks.push_back(track); } // end for } // end for // to use std::sort algorithm, the operator int() const in Proxy must be public. Otherwise, there is a compiler error data->clsPhysicalRoutingGrids.clear(); for (Rsyn::PhysicalLayer layer : allPhysicalLayers()) { if (!hasPhysicalRoutingGrid(layer)) continue; PhysicalRoutingGrid routing = data->clsMapLayerToRoutingGrid[layer]; data->clsPhysicalRoutingGrids.push_back(routing); } // end for Rsyn::PhysicalRoutingGrid bottom; for (Rsyn::PhysicalRoutingGrid routing : allPhysicalRoutingGrids()) { for (Rsyn::PhysicalTracks track : routing.allTracks()) { if (track.getDirection() == Rsyn::TRACK_HORIZONTAL) { routing->clsBounds[LOWER][Y] = track->clsLocation; routing->clsNumTracks[Y] = track->clsNumTracks; routing->clsSpacing[Y] = track->clsSpace; } else if (track.getDirection() == Rsyn::TRACK_VERTICAL) { routing->clsBounds[LOWER][X] = track->clsLocation; routing->clsNumTracks[X] = track->clsNumTracks; routing->clsSpacing[X] = track->clsSpace; } else { std::cout << "ERROR: Invalid track direction " << track.getDirection() << "\n"; } // end if-else } // end for routing->clsBounds[UPPER][X] = routing->clsBounds[LOWER][X] + (routing->clsSpacing[X] * (routing->clsNumTracks[X] - 1)); routing->clsBounds[UPPER][Y] = routing->clsBounds[LOWER][Y] + (routing->clsSpacing[Y] * (routing->clsNumTracks[Y] - 1)); routing->clsBottomRoutingGrid = bottom; if (bottom != nullptr) bottom->clsTopRoutingGrid = routing; bottom = routing; } // end for } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalGCell(const DefGcellGridDscp &gcell) { data->clsPhysicalGCell.push_back(PhysicalGCell(new PhysicalGCellData())); PhysicalGCell phyGCell = data->clsPhysicalGCell.back(); phyGCell->clsLocation = gcell.clsX; phyGCell->clsNumTracks = gcell.clsXNum; phyGCell->clsStep = gcell.clsXStep; phyGCell->clsDirection = gcell.clsMacro == "X" ? PhysicalGCellDirection::VERTICAL : PhysicalGCellDirection::HORIZONTAL; } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalDesignVia(const DefViaDscp & via) { std::unordered_map::iterator it = data->clsMapPhysicalVias.find(via.clsName); if (it != data->clsMapPhysicalVias.end()) { std::cout << "WARNING: Via " << via.clsName << " was already defined. Skipping ...\n"; return; } // end if // Adding new via data->clsMapPhysicalVias[via.clsName] = data->clsPhysicalVias.size(); data->clsPhysicalVias.push_back(PhysicalVia(new PhysicalViaData())); PhysicalVia phVia = data->clsPhysicalVias.back(); phVia->id = data->clsPhysicalVias.size() - 1; phVia->clsName = via.clsName; phVia->clsIsDefault = false; // only available in lef via phVia->clsHasCutResistance = false; // only available in lef via phVia->clsIsViaDesign = true; phVia->clsHasViaRule = via.clsHasViaRule; if (via.clsHasViaRule) { Rsyn::PhysicalViaRuleBase phViaRuleBase = getPhysicalViaRuleBaseByName(via.clsViaRuleName); phVia->clsHasViaRule = true; phVia->clsType = VIA_RULE_TYPE; phVia->clsViaRuleData = phViaRuleBase.data; phVia->clsCutSize[X] = via.clsXCutSize; phVia->clsCutSize[Y] = via.clsYCutSize; phVia->clsSpacing[X] = via.clsXCutSpacing; phVia->clsSpacing[Y] = via.clsYCutSpacing; phVia->clsEnclosure[BOTTOM_VIA_LEVEL][X] = via.clsXBottomEnclosure; phVia->clsEnclosure[BOTTOM_VIA_LEVEL][Y] = via.clsYBottomEnclosure; phVia->clsEnclosure[TOP_VIA_LEVEL][X] = via.clsXTopEnclosure; phVia->clsEnclosure[TOP_VIA_LEVEL][Y] = via.clsYTopEnclosure; Rsyn::PhysicalLayer bottom = getPhysicalLayerByName(via.clsBottomLayer); Rsyn::PhysicalLayer cut = getPhysicalLayerByName(via.clsCutLayer); Rsyn::PhysicalLayer top = getPhysicalLayerByName(via.clsTopLayer); phVia->clsLayers[BOTTOM_VIA_LAYER] = bottom.data; phVia->clsLayers[CUT_VIA_LAYER] = cut.data; phVia->clsLayers[TOP_VIA_LAYER] = top.data; if (via.clsHasRowCol) { phVia->clsHasRowCol = true; phVia->clsNumRows = via.clsNumCutRows; phVia->clsNumCols = via.clsNumCutCols; } // end if if (via.clsHasOrigin) { phVia->clsHasOrigin = true; phVia->clsOrigin[X] = via.clsXOffsetOrigin; phVia->clsOrigin[Y] = via.clsYOffsetOrigin; } // end if if (via.clsHasOffset) { phVia->clsHasOffset = true; phVia->clsOffset[BOTTOM_VIA_LEVEL][X] = via.clsXBottomOffset; phVia->clsOffset[BOTTOM_VIA_LEVEL][Y] = via.clsYBottomOffset; phVia->clsOffset[TOP_VIA_LEVEL][X] = via.clsXTopOffset; phVia->clsOffset[TOP_VIA_LEVEL][Y] = via.clsYTopOffset; } // end if if (via.clsHasPattern) { phVia->clsHasPattern = true; phVia->clsPattern = via.clsPattern; } // end if } else { phVia->clsHasViaRule = false; phVia->clsType = VIA_GEOMETRY_TYPE; std::vector> layers; for (const std::pair < std::string, std::deque < DefViaGeometryDscp>> &geoPair : via.clsGeometries) { const std::string & layerName = geoPair.first; Rsyn::PhysicalLayer layer = getPhysicalLayerByName(layerName); // assert(layer); layers.push_back(std::make_tuple(layer.getIndex(), layer.data)); } // end for std::sort(layers.begin(), layers.end()); // assert(layers.size() == NUM_VIA_LAYERS); for (int i = 0; i < NUM_VIA_LAYERS; i++) { PhysicalLayerData * layerData = std::get<1>(layers[i]); phVia->clsLayers[i] = layerData; std::vector & viaGeos = phVia->clsViaGeometries[i]; auto iterator = via.clsGeometries.find(layerData->clsName); const std::deque & geoDscps = iterator->second; viaGeos.reserve(geoDscps.size()); for (const DefViaGeometryDscp & geoDscp : geoDscps) { viaGeos.push_back(Rsyn::PhysicalViaGeometry(new ViaGeometryData())); Rsyn::PhysicalViaGeometry viaGeo = viaGeos.back(); viaGeo->id = viaGeos.size() -1; const DoubleRectangle & doubleRect = geoDscp.clsBounds; Bounds & bds = viaGeo->clsBounds; bds[LOWER][X] = doubleRect[LOWER][X]; bds[LOWER][Y] = doubleRect[LOWER][Y]; bds[UPPER][X] = doubleRect[UPPER][X]; bds[UPPER][Y] = doubleRect[UPPER][Y]; } // end for } // end for } // end if-else } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::addPhysicalSpacing(const LefSpacingDscp & spacing) { Element *element = data->clsPhysicalSpacing.create(); Rsyn::PhysicalSpacingData * phSpacing = &(element->value); phSpacing->id = data->clsPhysicalSpacing.lastId(); phSpacing->clsLayer1 = getPhysicalLayerByName(spacing.clsLayer1); phSpacing->clsLayer2 = getPhysicalLayerByName(spacing.clsLayer2); phSpacing->clsDistance = static_cast (std::round(spacing.clsDistance * getDatabaseUnits(LIBRARY_DBU))); } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalLayer PhysicalDesign::getPhysicalLayerByIndex(const int index) { const int numLayers = data->clsPhysicalLayers.size(); if (index < 0 || index >= numLayers) return PhysicalLayer(nullptr); Element * phLayerDataElement = data->clsPhysicalLayers.get(index); return PhysicalLayer(&phLayerDataElement->value); } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalLayer PhysicalDesign::getPhysicalLayerByIndex(const Rsyn::PhysicalLayerType layerType, const int index) { if (index < 0) return PhysicalLayer(nullptr); int numLayers; int layerId; Element * phLayerDataElement; switch (layerType) { case PhysicalLayerType::ROUTING: numLayers = data->clsPhysicalRoutingLayerIndeces.size(); if (index >= numLayers) return PhysicalLayer(nullptr); layerId = data->clsPhysicalRoutingLayerIndeces[index]; phLayerDataElement = data->clsPhysicalLayers.get(layerId); return PhysicalLayer(&phLayerDataElement->value); break; default: std::cout << "TODO " << layerType << "\n"; return PhysicalLayer(nullptr); } // end switch } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::updatePhysicalCell(Rsyn::Cell cell) { PhysicalInstanceData & phCell = data->clsPhysicalInstances[cell.asCell()]; PhysicalLibraryCellData &phLibCell = data->clsPhysicalLibraryCells[cell.asCell().getLibraryCell()]; // TODO: assuming instance is a cell const DBU width = phLibCell.clsSize[X]; const DBU height = phLibCell.clsSize[Y]; const DBUxy pos = phCell.clsInstance->clsBounds[LOWER]; DBU area = (width * height) - phCell.clsInstance->clsBounds.computeArea(); if (!strcmp(phLibCell.clsMacro->macroClass(), "BLOCK")) data->clsTotalAreas[PHYSICAL_BLOCK] += area; if (cell.isFixed()) { if (cell.isPort()) data->clsTotalAreas[PHYSICAL_PORT] += area; else data->clsTotalAreas[PHYSICAL_FIXED] += area; } else { data->clsTotalAreas[PHYSICAL_MOVABLE] += area; } // end if-else phCell.clsInstance->clsBounds.updatePoints(pos, DBUxy(pos[X] + width, pos[Y] + height)); } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::removePhysicalCell(Rsyn::Cell cell) { PhysicalInstanceData & physicalCell = data->clsPhysicalInstances[cell.asCell()]; DBU area = physicalCell.clsInstance->clsBounds.computeArea(); if (physicalCell.clsBlock) data->clsTotalAreas[PHYSICAL_BLOCK] -= area; if (cell.isFixed()) { if (cell.isPort()) data->clsTotalAreas[PHYSICAL_PORT] -= area; else data->clsTotalAreas[PHYSICAL_FIXED] -= area; } else { data->clsTotalAreas[PHYSICAL_MOVABLE] -= area; } // end if-else } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::mergeBounds(const std::vector & source, std::vector & target, const Dimension dim) { target.reserve(source.size()); std::set stripes; const Dimension reverse = REVERSE_DIMENSION[dim]; DBUxy lower, upper; lower[reverse] = +std::numeric_limits::max(); upper[reverse] = -std::numeric_limits::max(); for (const Bounds & bound : source) { stripes.insert(bound[LOWER][dim]); stripes.insert(bound[UPPER][dim]); lower[reverse] = std::min(bound[LOWER][reverse], lower[reverse]); upper[reverse] = std::max(bound[UPPER][reverse], upper[reverse]); } // end for lower[dim] = *stripes.begin(); stripes.erase(0); for (DBU val : stripes) { upper[dim] = val; Bounds stripe(lower, upper); DBU low, upp; bool firstMatch = true; for (const Bounds & rect : source) { if (!rect.overlap(stripe)) { if (!firstMatch) { Bounds merged = stripe; merged[LOWER][reverse] = low; merged[UPPER][reverse] = upp; target.push_back(merged); firstMatch = true; } // end if continue; } // end if if (firstMatch) { low = rect[LOWER][reverse]; upp = rect[UPPER][reverse]; firstMatch = false; } else { if (upp == rect[LOWER][reverse]) { upp = rect[UPPER][reverse]; } // end if } // end if-else } // end for if (!firstMatch) { Bounds merged = stripe; merged[LOWER][reverse] = low; merged[UPPER][reverse] = upp; target.push_back(merged); firstMatch = true; } // end if lower[dim] = val; } // end for } // end method // ----------------------------------------------------------------------------- void PhysicalDesign::initLayerViaManager() { for (PhysicalVia via : allPhysicalVias()) { Rsyn::PhysicalLayer bottom = via.getBottomLayer(); Rsyn::PhysicalLayer top = via.getTopLayer(); std::vector &bottomAll = data->clsLayerViaManager.clsVias[bottom]; std::vector &bottomTop = data->clsLayerViaManager.clsTopVias[bottom]; bottomAll.push_back(via); bottomTop.push_back(via); std::vector &topAll = data->clsLayerViaManager.clsVias[top]; std::vector &topBottom = data->clsLayerViaManager.clsBottomVias[top]; topAll.push_back(via); topBottom.push_back(via); } // end for } // end method // ----------------------------------------------------------------------------- bool PhysicalDesign::checkEquivalentOrientations(Rsyn::PhysicalSymmetry symmetry, Rsyn::PhysicalOrientation orient1, Rsyn::PhysicalOrientation orient2) const { std::cout << "TODO " << __func__ << " at " << __FILE__ << "\n"; // if(Rsyn::isPhysicalSymmetryX(symmetry)) { // return orient1 == Rsyn::ORIENTATION_N || // } // end if return false; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalDesign.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace Rsyn { // ----------------------------------------------------------------------------- inline void PhysicalDesign::setClockNet(Rsyn::Net net) { data->clsClkNet = net; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDesign::getDatabaseUnits(const DBUType type) const { return data->clsDBUs[type]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDesign::convertMicronToLibraryDatabaseUnits(const double value) const { return static_cast (std::round(value * getDatabaseUnits(LIBRARY_DBU))); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDesign::convertMicronToDesignDatabaseUnits(const double value) const { return static_cast (std::round(value * getDatabaseUnits(DESIGN_DBU))); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalDesign::getHPWL() const { return data->clsHPWL; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDesign::getHPWL(const Dimension dim) const { return data->clsHPWL[dim]; }// end method // ----------------------------------------------------------------------------- inline int PhysicalDesign::getNumElements(PhysicalType type) const { return data->clsNumElements[type]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDesign::getArea(const PhysicalType type) const { return data->clsTotalAreas[type]; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalDesign::isEnablePhysicalPins() const { return data->clsEnablePhysicalPins; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalDesign::isEnableMergeRectangles() const { return data->clsEnableMergeRectangles; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalDesign::isEnableNetPinBoundaries() const { return data->clsEnableNetPinBoundaries; } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::addPhysicalPin() { std::cout << "TODO " << __func__ << "\n"; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayer PhysicalDesign::getPhysicalLayerByName(const std::string & layerName) { std::unordered_map::iterator element = data->clsMapPhysicalLayers.find(layerName); if (element == data->clsMapPhysicalLayers.end()) return nullptr; const int id = element->second; Element * phLayerDataElement = data->clsPhysicalLayers.get(id); return PhysicalLayer(&phLayerDataElement->value); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalSite PhysicalDesign::getPhysicalSiteByName(const std::string & siteName) { std::unordered_map::iterator it = data->clsMapPhysicalSites.find(siteName); return it != data->clsMapPhysicalSites.end() ? data->clsPhysicalSites[it->second] : nullptr; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalRegion PhysicalDesign::getPhysicalRegionByName(const std::string &siteName) { std::unordered_map::iterator it = data->clsMapPhysicalRegions.find(siteName); if (it == data->clsMapPhysicalRegions.end()) return nullptr; return data->clsPhysicalRegions[it->second]; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalGroup PhysicalDesign::getPhysicalGroupByName(const std::string &siteName) { std::unordered_map::iterator it = data->clsMapPhysicalGroups.find(siteName); if (it == data->clsMapPhysicalGroups.end()) return nullptr; return data->clsPhysicalGroups[it->second]; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalVia PhysicalDesign::getPhysicalViaByName(const std::string &viaName) { std::unordered_map::iterator it = data->clsMapPhysicalVias.find(viaName); if (it == data->clsMapPhysicalVias.end()) return nullptr; return data->clsPhysicalVias[it->second]; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalViaRuleBase PhysicalDesign::getPhysicalViaRuleBaseByName(const std::string &viaName) { std::unordered_map::iterator it = data->clsMapPhysicalViaRuleBases.find(viaName); if (it == data->clsMapPhysicalVias.end()) return nullptr; return data->clsPhysicalViaRuleBases[it->second]; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalViaRule PhysicalDesign::getPhysicalViaRuleByName(const std::string &viaName) { Rsyn::PhysicalViaRuleBase viaRuleBase = getPhysicalViaRuleBaseByName(viaName); if (viaRuleBase == nullptr) { return nullptr; } // end if return viaRuleBase.isViaRule() ? viaRuleBase.asViaRule() : nullptr; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalViaRuleGenerate PhysicalDesign::getPhysicalViaRuleGenerateByName(const std::string &viaName) { Rsyn::PhysicalViaRuleBase viaRuleBase = getPhysicalViaRuleBaseByName(viaName); if (viaRuleBase == nullptr) { return nullptr; } // end if return viaRuleBase.isViaRuleGenerate() ? viaRuleBase.asViaRuleGenerate() : nullptr; } // end method // ----------------------------------------------------------------------------- inline int PhysicalDesign::getNumLayers(const Rsyn::PhysicalLayerType type) const { return data->clsNumLayers[type]; } // end method // ----------------------------------------------------------------------------- inline int PhysicalDesign::getNumLayers() const { return data->clsPhysicalLayers.size(); } // end method // ----------------------------------------------------------------------------- inline Range> PhysicalDesign::allPhysicalLayers() { return ListCollection(data->clsPhysicalLayers); } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalDesign::getNumPhysicalVias() const { return data->clsPhysicalVias.size(); } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalDesign::allPhysicalVias() const { return data->clsPhysicalVias; } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalDesign::getNumPhysicalTracks()const { return data->clsPhysicalTracks.size(); } // end method // ----------------------------------------------------------------------------- inline int PhysicalDesign::getNumPhysicalTracks(Rsyn::PhysicalLayer layer) const { if (!hasPhysicalTracks(layer)) return 0; const std::vector & tracks = allPhysicalTracks(layer); return tracks.size(); } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalDesign::allPhysicalTracks() const { return data->clsPhysicalTracks; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalDesign::allPhysicalTracks(Rsyn::PhysicalLayer layer) const { return data->clsMapLayerToTracks[layer]; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalDesign::hasPhysicalTracks(Rsyn::PhysicalLayer layer) const { if (layer == nullptr) return false; if (layer.getType() != Rsyn::PhysicalLayerType::ROUTING) return false; if (data->clsMapLayerToTracks.find(layer) == data->clsMapLayerToTracks.end()) return false; const std::vector & tracks = allPhysicalTracks(layer); return tracks.size() > 0; } // end method // ----------------------------------------------------------------------------- inline const std::vector& PhysicalDesign::allPhysicalGCell() const { return data->clsPhysicalGCell; } // end method // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- inline const std::vector& PhysicalDesign::allPhysicalRoutingGrids() const { return data->clsPhysicalRoutingGrids; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalRoutingGrid PhysicalDesign::getPhysicalRoutingGrid(Rsyn::PhysicalLayer layer) const { if (layer && layer.getType() == Rsyn::PhysicalLayerType::ROUTING) { auto it = data->clsMapLayerToRoutingGrid.find(layer); if (it != data->clsMapLayerToRoutingGrid.end()) { return it->second; } // end if } // end if return nullptr; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalDesign::hasPhysicalRoutingGrid(Rsyn::PhysicalLayer layer) const { if (layer == nullptr) return false; if (layer.getType() != Rsyn::PhysicalLayerType::ROUTING) return false; if (data->clsMapLayerToRoutingGrid.find(layer) == data->clsMapLayerToRoutingGrid.end()) return false; return true; } // end method // ----------------------------------------------------------------------------- inline int PhysicalDesign::getNumPhysicalRoutingGrids() const { return data->clsPhysicalRoutingGrids.size(); } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalDesign::getNumPhysicalSpacing() const { return data->clsPhysicalSpacing.size(); } // end method // ----------------------------------------------------------------------------- inline Range> PhysicalDesign::allPhysicalSpacing() const { return ListCollection(data->clsPhysicalSpacing); } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalDesign::getNumPhysicalRegions() const { return data->clsPhysicalRegions.size(); } // end method // ----------------------------------------------------------------------------- inline std::vector & PhysicalDesign::allPhysicalRegions() const { return data->clsPhysicalRegions; } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalDesign::getNumPhysicalGroups() const noexcept { return data->clsPhysicalGroups.size(); } // end method // ----------------------------------------------------------------------------- inline std::vector & PhysicalDesign::allPhysicalGroups() const { return data->clsPhysicalGroups; } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalDesign::getNumPhysicalSpecialNets() const noexcept { return data->clsPhysicalSpecialNets.size(); } // end method // ----------------------------------------------------------------------------- inline std::vector & PhysicalDesign::allPhysicalSpecialNets() const { return data->clsPhysicalSpecialNets; } // end method // ----------------------------------------------------------------------------- //I'm assuming all rows have the same height. inline DBU PhysicalDesign::getRowHeight() const { return data->clsPhysicalRows.get(0)->value.getHeight(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDesign::getRowSiteWidth() const { return data->clsPhysicalRows.get(0)->value.clsPhysicalSite.getWidth(); } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalDesign::getNumRows() const { return data->clsPhysicalRows.size(); } // end method // ----------------------------------------------------------------------------- inline Range> PhysicalDesign::allPhysicalRows() { return ListCollection(data->clsPhysicalRows); } // end method // ----------------------------------------------------------------------------- inline Rsyn::LayerViaManager PhysicalDesign::getLayerViaManager() const { return LayerViaManager(&data->clsLayerViaManager); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLibraryPin PhysicalDesign::getPhysicalLibraryPin(Rsyn::LibraryPin libPin) const { return PhysicalLibraryPin(&data->clsPhysicalLibraryPins[libPin]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLibraryPin PhysicalDesign::getPhysicalLibraryPin(Rsyn::Pin pin) const { if (pin.getInstanceType() != Rsyn::CELL) return nullptr; return PhysicalLibraryPin(&data->clsPhysicalLibraryPins[pin.getLibraryPin()]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLibraryCell PhysicalDesign::getPhysicalLibraryCell(Rsyn::Cell cell) const { Rsyn::LibraryCell libCell = cell.getLibraryCell(); return PhysicalLibraryCell(&data->clsPhysicalLibraryCells[libCell]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLibraryCell PhysicalDesign::getPhysicalLibraryCell(Rsyn::LibraryCell libCell) const { return PhysicalLibraryCell(&data->clsPhysicalLibraryCells[libCell]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalCell PhysicalDesign::getPhysicalCell(Rsyn::Cell cell) const { return PhysicalCell(&data->clsPhysicalInstances[cell]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalCell PhysicalDesign::getPhysicalCell(Rsyn::Pin pin) const { Rsyn::Instance instance = pin.getInstance(); return instance.getType() == Rsyn::CELL ? getPhysicalCell(instance.asCell()) : nullptr; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalInstance PhysicalDesign::getPhysicalInstance(Rsyn::Instance instance) const { return PhysicalInstance(&data->clsPhysicalInstances[instance]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalInstance PhysicalDesign::getPhysicalInstance(Rsyn::Pin pin) const { return getPhysicalInstance(pin.getInstance()); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalPort PhysicalDesign::getPhysicalPort(Rsyn::Port port) const { return PhysicalPort(&data->clsPhysicalInstances[port]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalPort PhysicalDesign::getPhysicalPort(Rsyn::Pin pin) const { Rsyn::Instance instance = pin.getInstance(); return getPhysicalPort(instance.asPort()); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalModule PhysicalDesign::getPhysicalModule(Rsyn::Module module) const { return PhysicalModule(&data->clsPhysicalInstances[module]); } // end method // ----------------------------------------------------------------------------- inline int PhysicalDesign::getNumMovedCells() const { int count = 0; for (Rsyn::Instance instance : data->clsModule.allInstances()) { if (instance.getType() != Rsyn::CELL) continue; Rsyn::Cell cell = instance.asCell(); // TODO: hack, assuming that the instance is a cell Rsyn::PhysicalCell phCell = getPhysicalCell(cell); if (instance.isFixed() || instance.isMacroBlock()) continue; const DBUxy initialPos = phCell.getInitialPosition(); const DBUxy currentPos = phCell.getPosition(); if (initialPos[X] != currentPos[X] || initialPos[Y] != currentPos[Y]) count++; } // end for return count; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalModule PhysicalDesign::getPhysicalModule(Rsyn::Pin pin) const { Rsyn::Instance instance = pin.getInstance(); return getPhysicalModule(instance.asModule()); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalDie PhysicalDesign::getPhysicalDie() const { return PhysicalDie(&data->clsPhysicalDie); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalPin PhysicalDesign::getPhysicalPin(Rsyn::Pin pin) const { if (!data->clsEnablePhysicalPins) return nullptr; return PhysicalPin(&data->clsPhysicalPins[pin]); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalDesign::getPinDisplacement(Rsyn::Pin pin) const { Rsyn::Instance inst = pin.getInstance(); if (inst.getType() == Rsyn::CELL) { Rsyn::LibraryPin libPin = pin.getLibraryPin(); DBUxy displacement = data->clsPhysicalLibraryPins[libPin].clsLayerBound.computeCenter(); return displacement; } // end if return DBUxy(0, 0); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalDesign::getPinPosition(Rsyn::Pin pin) const { // Position may be defined if the instance has info. // I'm assuming the instance doesn't know what is its position. DBUxy pos; Rsyn::InstanceType type = pin.getInstanceType(); switch (type) { case Rsyn::CELL: pos = getPhysicalCell(pin).getPosition(); break; case Rsyn::MODULE: pos = getPhysicalModule(pin).getPosition(); break; case Rsyn::PORT: pos = getPhysicalPort(pin).getPosition(); break; default: pos.apply(std::numeric_limits::infinity()); std::cout << "WARNING: Position for " << pin.getFullName() << " was not defined for the instance type\n"; } // end switch return pos + getPinDisplacement(pin); } // end method // ----------------------------------------------------------------------------- // For pins of standard-cells, returns the cell position. For macro-blocks, // returns the pin position itself. inline DBUxy PhysicalDesign::getRelaxedPinPosition(Rsyn::Pin pin) const { // Position may be defined if the instance has info. // I'm assuming the instance doesn't know what is its position. DBUxy pos; Rsyn::InstanceType type = pin.getInstanceType(); Rsyn::PhysicalCell phCell; switch (type) { case Rsyn::CELL: phCell = getPhysicalCell(pin); pos = phCell.getPosition(); if (pin.isMacroBlockPin()) pos += getPinDisplacement(pin); break; case Rsyn::MODULE: pos = getPhysicalModule(pin).getPosition(); pos += getPinDisplacement(pin); break; case Rsyn::PORT: pos = getPhysicalPort(pin).getPosition(); pos += getPinDisplacement(pin); break; default: pos.apply(std::numeric_limits::infinity()); std::cout << "WARNING: Position for " << pin.getFullName() << " was not defined for the instance type\n"; } // end switch return pos; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDesign::getPinDisplacement(Rsyn::Pin pin, const Dimension dim) const { DBUxy disp = getPinDisplacement(pin); return disp[dim]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDesign::getPinPosition(Rsyn::Pin pin, const Dimension dim) const { DBUxy pos = getPinPosition(pin); return pos[dim]; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalNet PhysicalDesign::getPhysicalNet(Rsyn::Net net) const { return PhysicalNet(&data->clsPhysicalNets[net]); } // end method // ----------------------------------------------------------------------------- inline PhysicalIndex PhysicalDesign::getId(Rsyn::PhysicalRow phRow) const { return phRow->id; } // end method // ----------------------------------------------------------------------------- inline PhysicalIndex PhysicalDesign::getId(Rsyn::PhysicalLayer phLayer) const { return phLayer->id; } // end method // ----------------------------------------------------------------------------- inline PhysicalIndex PhysicalDesign::getId(Rsyn::PhysicalSpacing spacing) const { return spacing->id; } // end method //////////////////////////////////////////////////////////////////////////////// // Placement //////////////////////////////////////////////////////////////////////////////// inline PhysicalAttributeInitializer PhysicalDesign::createPhysicalAttribute() { return PhysicalAttributeInitializer(*this); } // end method // ----------------------------------------------------------------------------- template inline PhysicalAttributeInitializerWithDefaultValue PhysicalDesign::createPhysicalAttribute(const DefaultPhysicalValueType &defaultValue) { return PhysicalAttributeInitializerWithDefaultValue(*this, defaultValue); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalOrientation PhysicalDesign::checkOrientation(Rsyn::PhysicalPort physicalPort, const DBU x, const DBU y){ Rsyn::PhysicalDie die = getPhysicalDie(); Bounds dieBounds = die.getBounds(); DBU lowerXBound = dieBounds[LOWER][X]; DBU lowerYBound = dieBounds[LOWER][Y]; DBU upperXBound = dieBounds[UPPER][X]; DBU upperYBound = dieBounds[UPPER][Y]; if (x == lowerXBound){ if (y == upperYBound) return ORIENTATION_S; return ORIENTATION_E; } if (x == upperXBound){ if (y == lowerYBound) return ORIENTATION_N; return ORIENTATION_W; } if (y == lowerYBound) return ORIENTATION_N; if (y == upperYBound) return ORIENTATION_S; return physicalPort.getOrientation(); } // ----------------------------------------------------------------------------- inline DBUxy PhysicalDesign::checkPosition(const DBU x, const DBU y) { DBUxy newPosition(x, y); Rsyn::PhysicalDie die = getPhysicalDie(); Bounds dieBounds = die.getBounds(); DBU lowerXBound = dieBounds[LOWER][X]; DBU lowerYBound = dieBounds[LOWER][Y]; DBU upperXBound = dieBounds[UPPER][X]; DBU upperYBound = dieBounds[UPPER][Y]; int distToLowerX = std::abs(lowerXBound - x); int distToLowerY = std::abs(lowerYBound - y); int distToUpperX = std::abs(upperXBound - x); int distToUpperY = std::abs(upperYBound - y); int minX = std::min(distToLowerX, distToUpperX); int minY = std::min(distToLowerY, distToUpperY); int minDist = std::min(minX, minY); if (minDist == distToLowerX) { newPosition = DBUxy(lowerXBound, y); } else if (minDist == distToLowerY) { newPosition = DBUxy(x, lowerYBound); } else if (minDist == distToUpperX) { newPosition = DBUxy(upperXBound, y); } else if (minDist == distToUpperY) { newPosition = DBUxy(x, upperYBound); } // end if-else return newPosition; } // end method // ----------------------------------------------------------------------------- inline bool Rsyn::PhysicalDesign::getPhysicalPortByName(std::string name, Rsyn::PhysicalPort &phPort) { for (Rsyn::Port port : data->clsModule.allPorts()) { if (port.getName() == name) { phPort = getPhysicalPort(port); return true; } } return false; } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::placePort(Rsyn::PhysicalPort physicalPort, const DBU x, const DBU y, Rsyn::PhysicalOrientation orient, const bool disableSnapping, const bool dontNotifyObservers) { Rsyn::PhysicalOrientation newOrient; const bool moved = (x != physicalPort.getPosition(X)) || (y != physicalPort.getPosition(Y)); DBUxy finalPosition; if (disableSnapping) { finalPosition = DBUxy(x, y); } else { finalPosition = checkPosition(x, y); } // end if if (orient != ORIENTATION_INVALID) { newOrient = orient; } else { newOrient = checkOrientation(physicalPort, finalPosition[X], finalPosition[Y]); }// end if physicalPort->clsInstance->clsOrientation = newOrient; // Notify observers. if (moved) { physicalPort->clsInstance->clsPortPos.set(finalPosition[X], finalPosition[Y]); if (!dontNotifyObservers) { data->clsDesign.notifyInstancePlaced(physicalPort.getInstance()); } // end if } // end if } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::placePort(Rsyn::Port port, const DBU x, const DBU y, Rsyn::PhysicalOrientation orient, const bool disableSnapping, const bool dontNotifyObservers) { placePort(getPhysicalPort(port), x, y, orient, disableSnapping, dontNotifyObservers); } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::placePort(Rsyn::PhysicalPort physicalPort, const DBUxy pos, Rsyn::PhysicalOrientation orient, const bool disableSnapping, const bool dontNotifyObservers) { placePort(physicalPort, pos[X], pos[Y], orient, disableSnapping, dontNotifyObservers); } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::placePort(Rsyn::Port port, const DBUxy pos, Rsyn::PhysicalOrientation orient, const bool disableSnapping, const bool dontNotifyObservers) { placePort(getPhysicalPort(port), pos[X], pos[Y], orient, disableSnapping, dontNotifyObservers); } // end method // ----------------------------------------------------------------------------- // Caution when using dontNotifyObservers. // We can use it when you may expect the move to be rolled back, but it is // not, recall to mark the cell as dirty. inline void PhysicalDesign::placeCell(Rsyn::PhysicalCell physicalCell, const DBU x, const DBU y, Rsyn::PhysicalOrientation orient, const bool dontNotifyObservers) { const bool moved = (x != physicalCell.getPosition(X)) || (y != physicalCell.getPosition(Y)); // Notify observers. if (moved) { physicalCell->clsInstance->clsBounds.moveTo(x, y); if (orient != ORIENTATION_INVALID) { physicalCell->clsInstance->clsOrientation = orient; } // end if if (!dontNotifyObservers) { data->clsDesign.notifyInstancePlaced(physicalCell.getInstance()); } // end if } // end if } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::placeCell(Rsyn::Cell cell, const DBU x, const DBU y, Rsyn::PhysicalOrientation orient, const bool dontNotifyObservers) { placeCell(getPhysicalCell(cell), x, y, orient, dontNotifyObservers); } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::placeCell(Rsyn::PhysicalCell physicalCell, const DBUxy pos, Rsyn::PhysicalOrientation orient, const bool dontNotifyObservers) { placeCell(physicalCell, pos[X], pos[Y], orient, dontNotifyObservers); } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::placeCell(Rsyn::Cell cell, const DBUxy pos, Rsyn::PhysicalOrientation orient, const bool dontNotifyObservers) { placeCell(getPhysicalCell(cell), pos[X], pos[Y], orient, dontNotifyObservers); } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::setCellOrientation(Rsyn::PhysicalCell physicalCell, Rsyn::PhysicalOrientation orient, const bool dontNotifyObservers) { if (orient != ORIENTATION_INVALID) { physicalCell->clsInstance->clsOrientation = orient; } // end if if (!dontNotifyObservers) { data->clsDesign.notifyInstancePlaced(physicalCell.getInstance()); } // end if } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::setCellOrientation(Rsyn::Cell cell, Rsyn::PhysicalOrientation orient, const bool dontNotifyObservers) { setCellOrientation(getPhysicalCell(cell), orient, dontNotifyObservers); } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::flipCell(Rsyn::PhysicalCell physicalCell, const bool dontNotifyObservers) { Rsyn::PhysicalOrientation orient = physicalCell.getOrientation(); Rsyn::PhysicalOrientation flippedOrient = ORIENTATION_INVALID; switch (orient) { case ORIENTATION_N: flippedOrient = ORIENTATION_FN; break; case ORIENTATION_S: flippedOrient = ORIENTATION_FS; break; case ORIENTATION_W: flippedOrient = ORIENTATION_FW; break; case ORIENTATION_E: flippedOrient = ORIENTATION_FE; break; case ORIENTATION_FN: flippedOrient = ORIENTATION_N; break; case ORIENTATION_FS: flippedOrient = ORIENTATION_S; break; case ORIENTATION_FW: flippedOrient = ORIENTATION_W; break; case ORIENTATION_FE: flippedOrient = ORIENTATION_E; break; default: flippedOrient = ORIENTATION_INVALID; } // end switch if (flippedOrient != ORIENTATION_INVALID) { setCellOrientation(physicalCell, flippedOrient, dontNotifyObservers); } // end if } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::flipCell(Rsyn::Cell cell, const bool dontNotifyObservers) { flipCell(getPhysicalCell(cell), dontNotifyObservers); } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::notifyInstancePlaced(Rsyn::Instance instance, Rsyn::DesignObserver *ignoreObserver) { data->clsDesign.notifyInstancePlaced(instance, ignoreObserver); } // end method //////////////////////////////////////////////////////////////////////////////// // Routing //////////////////////////////////////////////////////////////////////////////// inline void PhysicalDesign::setNetRouting(Rsyn::Net net, const PhysicalRouting &routing) { Rsyn::PhysicalNet physicalNet = getPhysicalNet(net); physicalNet->clsRouting = routing; for (PhysicalDesignObserver * observer : data->clsPhysicalObservers[PHYSICAL_EVENT_POST_NET_ROUTING_CHANGE]) { observer->onPostNetRoutingChange(physicalNet); } // end for } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::clearNetRouting(Rsyn::Net net) { PhysicalRouting emptyRouting; setNetRouting(net, emptyRouting); } // end method // ----------------------------------------------------------------------------- inline const PhysicalRouting &PhysicalDesign::getNetRouting(Rsyn::Net net) const { Rsyn::PhysicalNet physicalNet = getPhysicalNet(net); return physicalNet->clsRouting; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalDesign::isNetRouted(Rsyn::Net net) const { Rsyn::PhysicalNet physicalNet = getPhysicalNet(net); return !physicalNet->clsRouting.isEmpty(); } // end method //////////////////////////////////////////////////////////////////////////////// // Notification //////////////////////////////////////////////////////////////////////////////// template inline void PhysicalDesign::registerObserver(T *observer) { static_assert(std::is_base_of::value, "Unable to register class as observer. " "The observer class must inherit from Rsyn::PhysicalObserver."); observer->PhysicalDesignObserver::clsPhDesign = PhysicalDesign(data); // Check if the observer implements (overwrites) the event callbacks if so // register it to receive notifications of the respective event. if (typeid (&PhysicalDesignObserver::onPhysicalDesignDestruction) != typeid (&T::onPhysicalDesignDestruction)) { data->clsPhysicalObservers[PHYSICAL_EVENT_DESTRUCTION].push_back(observer); } // end if if (typeid (&PhysicalDesignObserver::onPostNetRoutingChange) != typeid (&T::onPostNetRoutingChange)) { data->clsPhysicalObservers[PHYSICAL_EVENT_POST_NET_ROUTING_CHANGE] .push_back(observer); } // end if } // end method // ----------------------------------------------------------------------------- inline void PhysicalDesign::unregisterObserver(PhysicalDesignObserver *observer) { for (int i = 0; i < NUM_PHYSICAL_EVENTS; i++) { data->clsPhysicalObservers[i].remove(observer); } // end for observer->PhysicalDesignObserver::clsPhDesign = nullptr; } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalDie.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalDie.h * Author: jucemar * * Created on 4 de Fevereiro de 2017, 08:49 */ namespace Rsyn { inline DBUxy PhysicalDie::getCoordinate(const Boundary bound) const { return data->clsBounds[bound]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDie::getCoordinate(const Boundary bound, const Dimension dim) const { return data->clsBounds[bound][dim]; } // end method // ----------------------------------------------------------------------------- inline const Bounds & PhysicalDie::getBounds() const { return data->clsBounds; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDie::getLength(const Dimension dim) const { return data->clsBounds.computeLength(dim); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalDie::getPosition(const Boundary boundary) const { return data->clsBounds[boundary]; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalDie::getCenterPosition() const { return data->clsBounds.computeCenter(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalDie::getArea() const { return data->clsBounds.computeArea(); } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalGCell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalGCell.h * Author: jucemar * * Created on January 22, 2018, 9:23 PM */ namespace Rsyn { //! @brief Returns GCell direction inline Rsyn::PhysicalGCellDirection PhysicalGCell::getDirection() const { return data->clsDirection; } // end method // ----------------------------------------------------------------------------- //! @brief If direction is vertical, then numTracks means the number of columns //! If direction is Horizontal, then numTracks means the number of rows inline int PhysicalGCell::getNumTracks() const { return data->clsNumTracks; } // end method // ----------------------------------------------------------------------------- //! @brief If direction is Horizontal, then location is Y value. //! If direction is vertical, then location is X value. inline DBU PhysicalGCell::getLocation() const { return data->clsLocation; } // end method // ----------------------------------------------------------------------------- //! @brief Returns the spacing between GCell tracks. inline DBU PhysicalGCell::getStep() const { return data->clsStep; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalGroup.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalGroup.h * Author: jucemar * * Created on 09 de Abril de 2017, 16:45 */ namespace Rsyn { // ----------------------------------------------------------------------------- inline const std::string & PhysicalGroup::getName() const { return data->clsName; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalRegion PhysicalGroup::getPhysicalRegion() const { return data->clsRegion; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalGroup::allPatterns() const { return data->clsPatterns; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalInstance.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalInstance.h * Author: jucemar * * Created on 4 de Outubro de 2016, 19:37 */ namespace Rsyn { // ----------------------------------------------------------------------------- inline Rsyn::Instance PhysicalInstance::getInstance() const { return data->clsInstance; } // end method // ----------------------------------------------------------------------------- inline const std::string &PhysicalInstance::getName() const { return data? getInstance().getName() : NullName; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalInstance::getArea() const { return getInstance().getArea(); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalInstance::getCenter() const { return getInstance().getCenter(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalInstance::getCenter(const Dimension dim) const { return getInstance().getCenter(dim); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalInstance::getX() const { return getInstance().getX(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalInstance::getY() const { return getInstance().getY(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalInstance::getHeight() const { return getInstance().getHeight(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalInstance::getWidth() const { return getInstance().getWidth(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalInstance::getSize(const Dimension dimension) const { return getInstance().getSize(dimension); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalInstance::getSize() const { return getInstance().getSize(); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalInstance::getPosition() const { return getInstance().getPosition(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalInstance::getPosition(const Dimension dim) const { return getInstance().getPosition(dim); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalInstance::getCoordinate(const Boundary bound) const { return getInstance().getCoordinate(bound); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalInstance::getCoordinate(const Boundary bound, const Dimension dim) const { return getInstance().getCoordinate(bound, dim); } // end method // ----------------------------------------------------------------------------- inline const Bounds &PhysicalInstance::getBounds() const { return getInstance().getBounds(); } // end method // ----------------------------------------------------------------------------- inline PhysicalOrientation PhysicalInstance::getOrientation() const { return getInstance().getOrientation(); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalCell PhysicalInstance::asPhysicalCell() const { //#ifdef RSYN_SAFE_MODE if (data->clsInstance.getType() != Rsyn::CELL) throw SafeModeException("Invalid instance casting. Instance is not a cell."); //#endif return PhysicalCell(data); } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalLayer.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ namespace Rsyn { inline lefiLayer* PhysicalLayer::getLayer() const { return data->clsLayer; } // end method // ----------------------------------------------------------------------------- inline std::string PhysicalLayer::getName() const { return data->clsName; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayerType PhysicalLayer::getType() const { return data->clsType; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalLayer::getWidth() const { return data->clsWidth; } // end method // ----------------------------------------------------------------------------- inline int PhysicalLayer::getIndex() const { return data->id; } // end method // ----------------------------------------------------------------------------- inline int PhysicalLayer::getRelativeIndex() const { return data->clsRelativeIndex; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayer PhysicalLayer::getPhysicalLayerLower() const { return Rsyn::PhysicalLayer(data->clsLower); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayer PhysicalLayer::getPhysicalLayerUpper() const { return Rsyn::PhysicalLayer(data->clsUpper); } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalLibraryCell.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ namespace Rsyn { inline lefiMacro* PhysicalLibraryCell::getMacro() const { return data->clsMacro; } // end method //----------------------------------------------------------------------------- inline DBUxy PhysicalLibraryCell::getSize() const { return data->clsSize; } // end method //----------------------------------------------------------------------------- inline DBU PhysicalLibraryCell::getWidth() const { return data->clsSize[X]; } // end method //----------------------------------------------------------------------------- inline DBU PhysicalLibraryCell::getHeight() const { return data->clsSize[Y]; } // end method //----------------------------------------------------------------------------- inline DBU PhysicalLibraryCell::getLength(const Dimension dim) const { return data->clsSize[dim]; } // end method // ----------------------------------------------------------------------------- inline Bounds PhysicalLibraryCell::getBounds() const { return Bounds(0, 0, getWidth(), getHeight()); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalLibraryCell::hasLayerObstacles() const { return data->clsLayerBoundIndex > -1; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalLibraryCell::hasObstacles() const { return !data->clsObs.empty(); } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalLibraryCell::allLayerObstacles() const { return data->clsObs[data->clsLayerBoundIndex].allBounds(); } // end method //----------------------------------------------------------------------------- inline PhysicalSite PhysicalLibraryCell::getSite() const { return data->clsMacroSite; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalLibraryCell::hasTopLayerObstacle() const{ return data->clsTopLayerObs != nullptr; } // end method //----------------------------------------------------------------------------- inline Rsyn::PhysicalObstacle PhysicalLibraryCell::getTopLayerObstracle() const { return data->clsTopLayerObs; } // end method //----------------------------------------------------------------------------- inline const std::vector & PhysicalLibraryCell::allObstacles() const { return data->clsObs; } // end method //----------------------------------------------------------------------------- inline std::size_t PhysicalLibraryCell::getNumObstacles() const { return data->clsObs.size(); } // end method //----------------------------------------------------------------------------- inline std::size_t PhysicalLibraryCell::getNumPhysicalCellLayerBoundaries() const { if (data->clsLayerBoundIndex < 0) return 0; return data->clsObs[data->clsLayerBoundIndex].getNumObs(); } // end method //----------------------------------------------------------------------------- inline PhysicalObstacle PhysicalLibraryCell::getLayerObstacles() const { return data->clsObs[data->clsLayerBoundIndex]; } // end method // ----------------------------------------------------------------------------- inline PhysicalTransform PhysicalLibraryCell::getTransform(const Rsyn::PhysicalOrientation &orientation) const { return PhysicalTransform(getBounds(), orientation); } // end method //----------------------------------------------------------------------------- inline bool PhysicalLibraryCell::hasPolygonBoundaries() const { return data->clsPolygonBounds.getNumPoints() > 0; } // end method //----------------------------------------------------------------------------- inline const Polygon & PhysicalLibraryCell::getPolygonBoundaries() const { return data->clsPolygonBounds; } // end method //----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalLibraryPin.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ namespace Rsyn { // ----------------------------------------------------------------------------- inline PhysicalLibraryCell PhysicalLibraryPin::getPhysicalLibraryCell() const { return data->clsLibraryCell; } // end method // ----------------------------------------------------------------------------- inline Bounds PhysicalLibraryPin::getICCADBounds() { return data->clsLayerBound; } // end method // ----------------------------------------------------------------------------- inline const Bounds & PhysicalLibraryPin::getICCADBounds() const { return data->clsLayerBound; } // end method // ----------------------------------------------------------------------------- inline std::vector & PhysicalLibraryPin::allPinGeometries() { return data->clsPhysicalPinGeometries; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalLibraryPin::allPinGeometries() const { return data->clsPhysicalPinGeometries; } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalLibraryPin::getNumPinGeometries() const { return data->clsPhysicalPinGeometries.size(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalLibraryPin::hasPinGeometries() const { return !data->clsPhysicalPinGeometries.empty(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalLibraryPin::isEmptyPinGeometries() const { return data->clsPhysicalPinGeometries.empty(); } // end method // ----------------------------------------------------------------------------- inline PhysicalPinDirection PhysicalLibraryPin::getPinDirection() const { return data->clsDirection; } // end method // ----------------------------------------------------------------------------- inline PhysicalPinUse PhysicalLibraryPin::getUse () const { return data->clsUse; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalModule.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalModule.h * Author: jucemar * * Created on 4 de Outubro de 2016, 20:35 */ namespace Rsyn { } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalNet.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalNet.h * Author: jucemar * * Created on 18 de Setembro de 2016, 09:03 */ namespace Rsyn { // ----------------------------------------------------------------------------- inline Rsyn::Net PhysicalNet::getNet() const { return data? data->clsNet : nullptr; } // end method // ----------------------------------------------------------------------------- inline std::string PhysicalNet::getName() const { return getNet().getName(); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalNet::getHPWL() const { return data->clsBounds.computeLength(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalNet::getHPWL(const Dimension dim) { return data->clsBounds.computeLength(dim); } // end method // ----------------------------------------------------------------------------- inline const Bounds & PhysicalNet::getBounds() const { return data->clsBounds; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalNet::getCoordinate(const Boundary bound) const { return data->clsBounds[bound]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalNet::getCoordinate(const Boundary bound, const Dimension dim) const { return data->clsBounds[bound][dim]; } // end method // ----------------------------------------------------------------------------- inline Rsyn::Pin PhysicalNet::getPinBoundary(const Boundary bound, const Dimension dim) const { return data->clsBoundPins[bound][dim]; } // end method // ----------------------------------------------------------------------------- inline const PhysicalRouting &PhysicalNet::getRouting() const { return data->clsRouting; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalNet::isRouted() const { return !data->clsRouting.isEmpty(); } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalObstacle.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ namespace Rsyn { inline Rsyn::PhysicalLayer PhysicalObstacle::getLayer() const { return data->clsLayer; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalObstacle::allBounds() const { return data->clsBounds; } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalObstacle::getNumObs() const { return data->clsBounds.size(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalObstacle::hasLayer() const { return data->clsLayer != nullptr; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalPin.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPin.h * Author: jucemar * * Created on 18 de Setembro de 2016, 09:00 */ namespace Rsyn { inline DBUxy PhysicalPin::getDisplacement() const { return data->clsDisplacement; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalPin::getDisplacement(const Dimension dim) { return data->clsDisplacement[dim]; } // end method // ----------------------------------------------------------------------------- inline std::vector & PhysicalPin::allPinGeometries() { return data->clsPhysicalPinGeometries; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalPin::allPinGeometries() const { return data->clsPhysicalPinGeometries; } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalPin::getNumPinGeometries() const { return data->clsPhysicalPinGeometries.size(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalPin::hasPinGeometries() const { return !data->clsPhysicalPinGeometries.empty(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalPin::isEmptyPinGeometries() const { return data->clsPhysicalPinGeometries.empty(); } // end method // ----------------------------------------------------------------------------- inline PhysicalPinDirection PhysicalPin::getDirection() const { return data->clsDirection; } // end method // ----------------------------------------------------------------------------- inline const Bounds & PhysicalPin::getLayerBounds() const { return data->clsLayerBound; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalPinGeometry.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPinGeometry.h * Author: jucemar * * Created on 18 de Setembro de 2016, 08:50 */ namespace Rsyn { inline PhysicalPinGeometryClass PhysicalPinGeometry::getPinGeometryClass() const { return data->clsPinPortClass; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalPinGeometry::hasPinLayer() const { return !data->clsPinLayers.empty(); } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalPinGeometry::getNumPinLayers() const{ return data->clsPinLayers.size(); } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalPinGeometry::allPinLayers() const { return data->clsPinLayers; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalPinLayer PhysicalPinGeometry::getLowerPinLayer() const { if(data->clsPinLayers.empty()) return Rsyn::PhysicalPinLayer(nullptr); return data->clsPinLayers.front(); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalPinLayer PhysicalPinGeometry::getUpperPinLayer() const { if(data->clsPinLayers.empty()) return Rsyn::PhysicalPinLayer(nullptr); return data->clsPinLayers.back(); } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalPinLayer.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPinLayer.h * Author: jucemar * * Created on 18 de Setembro de 2016, 08:46 */ namespace Rsyn { inline const std::vector & PhysicalPinLayer::allBounds() const { return data->clsBounds; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalPinLayer::allPolygons() const { return data->clsPolygons; } // end method // ----------------------------------------------------------------------------- inline PhysicalLayer PhysicalPinLayer::getLayer() const { return data->clsLibLayer; } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalPinLayer::getNumBounds() const { return data->clsBounds.size(); } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalPinLayer::getNumPolygons() const { return data->clsPolygons.size(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalPinLayer::hasRectangleBounds() const { return !data->clsBounds.empty(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalPinLayer::hasPolygonBounds() const { return !data->clsPolygons.empty(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalPinLayer::isRectangleBoundsEmpty() const { return data->clsBounds.empty(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalPinLayer::isPolygonBoundsEmpty() const { return data->clsPolygons.empty(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalPinLayer::hasLayer() const { return data->clsLibLayer != nullptr; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalPort.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalPort.h * Author: jucemar * * Created on 4 de Outubro de 2016, 19:34 */ namespace Rsyn { // ----------------------------------------------------------------------------- inline PhysicalLayer PhysicalPort::getLayer() const { return data->clsPortLayer; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalPort::hasLayer() const { return data->clsPortLayer != nullptr; } // end method // ----------------------------------------------------------------------------- inline PhysicalOrientation PhysicalPort::getOrientation() const { return getInstance().getOrientation(); } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalRegion.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalRegion.h * Author: jucemar * * Created on 09 de Abril de 2017, 14:55 */ namespace Rsyn { // ----------------------------------------------------------------------------- inline const std::string & PhysicalRegion::getName() const { return data->clsName; } // end method // ----------------------------------------------------------------------------- inline RegionType PhysicalRegion::getType() const { return data->clsType; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalRegion::allBounds() const { return data->clsBounds; } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalRegion::getNumBounds() const { return data->clsBounds.size(); } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalRoutingGrid.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalRoutingGrid.h * Author: jucemar * * Created on February 2, 2018, 9:06 PM */ namespace Rsyn { inline Rsyn::PhysicalLayer PhysicalRoutingGrid::getLayer() const { return data->clsLayer; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalRoutingGrid::allTracks() const { return data->clsTracks; } // end method // ----------------------------------------------------------------------------- inline const Bounds & PhysicalRoutingGrid::getBounds() const { return data->clsBounds; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRoutingGrid::getPosition() const { return data->clsBounds[LOWER]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRoutingGrid::getPosition(const Dimension dim) const { return data->clsBounds[LOWER][dim]; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRoutingGrid::getSpacing() const { return data->clsSpacing; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRoutingGrid::getSpacing(const Dimension dim) const { return data->clsSpacing[dim]; } // end method // ----------------------------------------------------------------------------- inline int PhysicalRoutingGrid::getNumTracks(const Dimension dim) const { return data->clsNumTracks[dim]; } // end method // ----------------------------------------------------------------------------- inline int PhysicalRoutingGrid::getNumRows() const { return data->clsNumTracks[Y]; } // end method // ----------------------------------------------------------------------------- inline int PhysicalRoutingGrid::getNumCols() const { return data->clsNumTracks[X]; } // end method // ----------------------------------------------------------------------------- inline int PhysicalRoutingGrid::getNumTracks() const { return data->clsNumTracks[X] + data->clsNumTracks[Y]; } // end method // ----------------------------------------------------------------------------- inline int PhysicalRoutingGrid::getRow(const DBU posY, const RoundingStrategy roudingStrategy, const bool clamp) const { const DBU pos = posY - getPosition(Y); const int index = FloatingPoint::round(pos / float(getSpacing(Y)), roudingStrategy); return clamp? std::max(0, std::min(index, getNumRows() - 1)) : index; } // end method // ----------------------------------------------------------------------------- inline int PhysicalRoutingGrid::getCol(const DBU posX, const RoundingStrategy roudingStrategy, const bool clamp) const { const DBU pos = posX - getPosition(X); const int index = FloatingPoint::round(pos / float(getSpacing(X)), roudingStrategy); return clamp? std::max(0, std::min(index, getNumCols() - 1)) : index; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRoutingGrid::getPosition(const int col, const int row) const { const DBU x = getColPosition(col); const DBU y = getRowPosition(row); return DBUxy(x, y); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRoutingGrid::getSnappedPosition(const DBUxy pos, const RoundingStrategy roudingStrategy, const bool clamp) const { const int col = getCol(pos.x, roudingStrategy, clamp); const int row = getRow(pos.y, roudingStrategy, clamp); return getPosition(col, row); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRoutingGrid::getRowPosition(const int row) const { return getPosition(Y) + (getSpacing(Y) * row); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRoutingGrid::getRowMaxPosition() const { return getRowPosition(getNumRows()); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRoutingGrid::getColPosition(const int col) const { return getPosition(X) + (getSpacing(X) * col); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRoutingGrid::getColMaxPosition() const { return getColPosition(getNumCols()); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRoutingGrid::getTrackMaxPosition() const { DBUxy pos; pos[X] = getColMaxPosition(); pos[Y] = getRowMaxPosition(); return pos; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRoutingGrid::getTrackMaxPosition(const Dimension dim) const { DBU pos = std::numeric_limits::max(); if (dim == X) pos = getColMaxPosition(); if (dim == Y) pos = getRowMaxPosition(); return pos; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalRoutingGrid PhysicalRoutingGrid::getBottomRoutingGrid() const { return data->clsBottomRoutingGrid; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalRoutingGrid PhysicalRoutingGrid::getTopRoutingGrid() const { return data->clsTopRoutingGrid; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalRoutingGrid::hasBottomRoutingGrid() const { return data->clsBottomRoutingGrid != nullptr; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalRoutingGrid::hasTopRoutingGrid() const { return data->clsTopRoutingGrid != nullptr; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRoutingGrid::getGridMinPosition() const { return data->clsBounds[LOWER]; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRoutingGrid::getGridMaxPosition() const { return data->clsBounds[UPPER]; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRoutingGrid::getTrackMinPosition(const PhysicalLayerDirection dir, const int index) const { DBU x = 0; DBU y = 0; if (dir == Rsyn::VERTICAL) { x = getColPosition(index); y = getGridMinPosition().y; } else { x = getGridMinPosition().x; y = getRowPosition(index); } // end else return DBUxy(x, y); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRoutingGrid::getTrackMaxPosition(const PhysicalLayerDirection dir, const int index) const { DBU x = 0; DBU y = 0; if (dir == Rsyn::VERTICAL) { x = getColPosition(index); y = getGridMaxPosition().y; } else { x = getGridMaxPosition().x; y = getRowPosition(index); } // end else return DBUxy(x, y); } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalRoutingPoint.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalRoutingPoint.h * Author: jucemar * * Created on 23 de Maio de 2017, 20:52 */ namespace Rsyn { // ----------------------------------------------------------------------------- inline DBUxy PhysicalRoutingPoint::getPosition() const { return data->clsPos; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRoutingPoint::getPosition(const Dimension dim) const { return data->clsPos[dim]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRoutingPoint::getExtension() const { return data->clsExtension; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalVia PhysicalRoutingPoint::getVia() const { return data->clsVia; } // end method // ----------------------------------------------------------------------------- inline const Bounds & PhysicalRoutingPoint::getRectangle() const { return data->clsRectangle; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalRoutingPoint::hasExtension() const { return data->clsExtension > -1; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalRoutingPoint::hasRectangle() const { return data->clsHasRectangle; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalRoutingPoint::hasVia() const { return data->clsVia != nullptr; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalRow.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalRow.h * Author: jucemar * * Created on 18 de Setembro de 2016, 09:27 */ namespace Rsyn { inline std::string PhysicalRow::getName() const { return data->clsRowName; } // end method // ----------------------------------------------------------------------------- inline std::string PhysicalRow::getSiteName() const { return data->clsPhysicalSite.getName(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRow::getWidth() const { return data->clsNumSites[X] * data->clsStep[X]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRow::getHeight() const { return data->clsNumSites[Y] * data->clsStep[Y]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRow::getOrigin(const Dimension dim) const { return data->clsOrigin[dim]; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRow::getOrigin() const { return data->clsOrigin; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRow::getStep(const Dimension dim) const { return data->clsStep[dim]; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRow::getStep() const { return data->clsStep; } // end method // ----------------------------------------------------------------------------- inline int PhysicalRow::getNumSites(const Dimension dim) const { return data->clsNumSites[dim]; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalSite PhysicalRow::getPhysicalSite() const { return data->clsPhysicalSite; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRow::getSiteWidth() const { return data->clsPhysicalSite.getWidth(); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRow::getSiteHeight() const { return data->clsPhysicalSite.getHeight(); } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalRow::getCoordinate(const Boundary bound) const { return data->clsBounds[bound]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalRow::getCoordinate(const Boundary bound, const Dimension dim) const { return data->clsBounds[bound][dim]; } // end method // ----------------------------------------------------------------------------- inline const Bounds &PhysicalRow::getBounds() const { return data->clsBounds; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalOrientation PhysicalRow::getSiteOrientation() const { return data->clsSiteOrientation; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalSymmetry PhysicalRow::getSymmetry() const { return data->clsPhysicalSite ? data->clsPhysicalSite.getSymmetry() : Rsyn::PhysicalSymmetry::SYMMETRY_INVALID; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalSite.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSite.h * Author: jucemar * * Created on 18 de Setembro de 2016, 08:42 */ namespace Rsyn { inline std::string PhysicalSite::getName() const { return data->clsSiteName; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalSiteClass PhysicalSite::getClass() const { return data->clsSiteClass; } // end method // ----------------------------------------------------------------------------- inline DBUxy PhysicalSite::getSize() const { return data->clsSize; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalSite::getWidth() const { return data->clsSize[X]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalSite::getHeight() const { return data->clsSize[Y]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalSite::getLength(const Dimension dim) const { return data->clsSize[dim]; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalSymmetry PhysicalSite::getSymmetry() const { return data->clsSymmetry; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalSpacing.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ namespace Rsyn { inline PhysicalLayer PhysicalSpacing::getLayer1() const { return data->clsLayer1; } // end method // ----------------------------------------------------------------------------- inline PhysicalLayer PhysicalSpacing::getLayer2() const { return data->clsLayer2; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalSpacing::getDistance() const { return data->clsDistance; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalSpecialNet.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSpecialNet.h * Author: jucemar * * Created on 23 de Maio de 2017, 20:58 */ namespace Rsyn { inline const DefNetDscp & PhysicalSpecialNet::getNet() const { return data->clsNet; } // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalSpecialWire.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalSpecialWire.h * Author: jucemar * * Created on 23 de Maio de 2017, 21:12 */ namespace Rsyn { inline Rsyn::PhysicalLayer PhysicalSpecialWire::getPhysicalLayer() { return data->clsPhysicalLayer; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalSpecialWire::getWireWidth() const { return data->clsWireWidth; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalSpecialWire::allRoutingPoints() const { return data->clsRoutingPoints; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalTracks.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalTracks.h * Author: jucemar * * Created on 24 de Maio de 2017, 21:53 */ namespace Rsyn { inline PhysicalTrackDirection PhysicalTracks::getDirection() const { return data->clsDirection; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalTracks::getLocation() const { return data->clsLocation; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalTracks::getSpace() const { return data->clsSpace; } // end method // ----------------------------------------------------------------------------- inline int PhysicalTracks::getNumberOfTracks() const { return data->clsNumTracks; } // end method // ----------------------------------------------------------------------------- inline std::size_t PhysicalTracks::getNumberOfLayers() const { return data->clsLayers.size(); } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalTracks::allLayers() const { return data->clsLayers; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalVia.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalVia.h * Author: jucemar * * Created on 14 de Maio de 2017, 15:25 */ namespace Rsyn { inline const std::string & PhysicalVia::getName() const { return data->clsName; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayer PhysicalVia::getTopLayer() const { return PhysicalLayer(data->clsLayers[TOP_VIA_LAYER]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayer PhysicalVia::getCutLayer() const { return PhysicalLayer(data->clsLayers[CUT_VIA_LAYER]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayer PhysicalVia::getBottomLayer() const { return PhysicalLayer(data->clsLayers[BOTTOM_VIA_LAYER]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayer PhysicalVia::getLayer(const PhysicalViaLayerType type) const { return PhysicalLayer(data->clsLayers[type]); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalVia::isViaDesign() const { return data->clsIsViaDesign; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalVia::isViaRule() const { return data->clsType == VIA_RULE_TYPE; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalVia::isViaGeometry() const { return data->clsType == VIA_GEOMETRY_TYPE; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalVia::hasViaRule() const { return data->clsHasViaRule; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalVia::hasRowCol() const { return data->clsHasRowCol; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalVia::hasOrigin() const { return data->clsHasOrigin; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalVia::hasOffset() const { return data->clsHasOffset; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalVia::hasPattern() const { return data->clsHasPattern; } // end method // ----------------------------------------------------------------------------- inline ViaType PhysicalVia::getViaType() const { return data->clsType; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalViaRuleBase PhysicalVia::getViaRule() const { return PhysicalViaRuleBase(data->clsViaRuleData); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalVia::getCutSize(const Dimension dim) const { return data->clsCutSize[dim]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalVia::getSpacing(const Dimension dim) const { return data->clsSpacing[dim]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalVia::getEnclosure(const ViaLevel level, const Dimension dim) const { return data->clsEnclosure[level][dim]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalVia::getOrigin(const Dimension dim) const { return data->clsOrigin[dim]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalVia::getOffset(const ViaLevel level, const Dimension dim) const { return data->clsOffset[level][dim]; } // end method // ----------------------------------------------------------------------------- inline int PhysicalVia::getNumRows() const { return data->clsNumRows; } // end method // ----------------------------------------------------------------------------- inline int PhysicalVia::getNumCols() const { return data->clsNumCols; } // end method // ----------------------------------------------------------------------------- inline const std::string & PhysicalVia::getPattern() const { return data->clsPattern; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalVia::allBottomGeometries() const { return allGeometries(BOTTOM_VIA_LAYER); } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalVia::allCutGeometries() const { return allGeometries(CUT_VIA_LAYER); } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalVia::allTopGeometries() const { return allGeometries(TOP_VIA_LAYER); } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalVia::allGeometries(const PhysicalViaLayerType layer) const { return data->clsViaGeometries[layer]; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalViaGeometry.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalViaGeometry.h * Author: jucemar * * Created on November 12, 2018, 10:14 PM */ namespace Rsyn { inline const Bounds & PhysicalViaGeometry::getBounds() const { return data->clsBounds; } // end method // ----------------------------------------------------------------------------- inline int PhysicalViaGeometry::getMaskNumber() const { return data->clsMaskNumber; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalViaRule.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalViaRule.h * Author: jucemar * * Created on November 12, 2018, 9:24 PM */ namespace Rsyn { inline int PhysicalViaRule::getRelativeIndex() const { return data->clsRelativeIndex; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayer PhysicalViaRule::getLayer(const Rsyn::ViaLevel level) const { return Rsyn::PhysicalLayer(data->clsLayers[level]); } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayerDirection PhysicalViaRule::getLayerDirection(const Rsyn::ViaLevel level) const { return data->clsLayerDirection[level]; } // end method // ----------------------------------------------------------------------------- inline const std::vector & PhysicalViaRule::allVias() const { return data->clsVias; } // end method // ----------------------------------------------------------------------------- } ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalViaRuleBase.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalViaRuleBase.h * Author: jucemar * * Created on November 13, 2018, 3:42 PM */ namespace Rsyn { inline int PhysicalViaRuleBase::getIndex() const { return data->id; } // end method // ----------------------------------------------------------------------------- inline PhysicalViaRule PhysicalViaRuleBase::asViaRule() const { return isViaRule() ? PhysicalViaRule(data) : PhysicalViaRule(); } // end method // ----------------------------------------------------------------------------- inline PhysicalViaRuleGenerate PhysicalViaRuleBase::asViaRuleGenerate() const { return isViaRuleGenerate() ? PhysicalViaRuleGenerate(data) : PhysicalViaRuleGenerate(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalViaRuleBase::isViaRule() const { return !isViaRuleGenerate(); } // end method // ----------------------------------------------------------------------------- inline bool PhysicalViaRuleBase::isViaRuleGenerate() const { return data->clsIsGenerate; } // end method // ----------------------------------------------------------------------------- inline const std::string & PhysicalViaRuleBase::getName() const { return data->clsName; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalViaRuleBase::hasWidth(const Rsyn::ViaLevel level) const { return data->clsHasWidth[level]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalViaRuleBase::getWidth(const Rsyn::ViaLevel level, const Rsyn::ViaRange range) const { return data->clsWidth[level][range]; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/obj/impl/PhysicalViaRuleGenerate.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalViaGenerate.h * Author: jucemar * * Created on November 12, 2018, 9:56 PM */ namespace Rsyn { inline int PhysicalViaRuleGenerate::getRelativeIndex() const { return data->clsRelativeIndex; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalViaRuleGenerate::isDefault() const { return data->clsIsDefault; } // end method // ----------------------------------------------------------------------------- inline Rsyn::PhysicalLayer PhysicalViaRuleGenerate::getLayer(const Rsyn::PhysicalViaLayerType layer) const { return Rsyn::PhysicalLayer(data->clsLayers[layer]); } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalViaRuleGenerate::getEnclosure1(const Rsyn::ViaLevel level) const { return data->clsEnclosure1[level]; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalViaRuleGenerate::getEnclosure2(const Rsyn::ViaLevel level) const { return data->clsEnclosure2[level]; } // end method // ----------------------------------------------------------------------------- inline Bounds PhysicalViaRuleGenerate::getCutBounds() const { return data->clsCutBounds; } // end method // ----------------------------------------------------------------------------- inline DBU PhysicalViaRuleGenerate::getCutSpacing(const Dimension dim) const { return data->clsCutSpacing[dim]; } // end method // ----------------------------------------------------------------------------- inline bool PhysicalViaRuleGenerate::hasCutResistance() const { return data->clsHasCutResistance; } // end method // ----------------------------------------------------------------------------- inline float PhysicalViaRuleGenerate::getCutResistance() const { return data->clsCutResistance; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/util/DefDescriptors.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: DefDescriptors.h * Author: jucemar * * Created on 6 de Julho de 2016, 18:24 */ #ifndef DEFDESCRIPTORS_H #define DEFDESCRIPTORS_H #include #include #include #include "rsyn/util/Bounds.h" #include "rsyn/util/dbu.h" static const std::string INVALID_DEF_NAME = "**"; // ----------------------------------------------------------------------------- //! Descriptor for DEF components class DefComponentDscp { public: std::string clsName = INVALID_DEF_NAME; std::string clsMacroName = INVALID_DEF_NAME; std::string clsLocationType = INVALID_DEF_NAME; // {FIXED | COVER | PLACED | UNPLACED } DBUxy clsPos; std::string clsOrientation = INVALID_DEF_NAME; bool clsIsFixed = false; bool clsIsPlaced = false; DefComponentDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for Def Groups class DefGroupDscp { public: std::string clsName = INVALID_DEF_NAME; std::vector clsPatterns; // It may be a pattern, e.g. "name/*" std::string clsRegion = INVALID_DEF_NAME; DefGroupDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for DEF ports class DefPortDscp { public: std::string clsName = INVALID_DEF_NAME; std::string clsNetName = INVALID_DEF_NAME; std::string clsDirection = INVALID_DEF_NAME; // {INPUT | OUTPUT | INOUT | FEEDTHRU} std::string clsLocationType = INVALID_DEF_NAME; // {FIXED | COVER | PLACED } std::string clsOrientation = INVALID_DEF_NAME; std::string clsLayerName = INVALID_DEF_NAME; std::string clsUse = INVALID_DEF_NAME; // { SIGNAL | POWER | GROUND | CLOCK | TIEOFF | ANALOG} DBUxy clsPos; DBUxy clsICCADPos; Bounds clsLayerBounds; bool clsSpecial = false; DefPortDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for DEF Net connections class DefNetConnection { public: std::string clsPinName = INVALID_DEF_NAME; std::string clsComponentName = INVALID_DEF_NAME; DefNetConnection() = default; }; // end class // ----------------------------------------------------------------------------- class DefRoutingPointDscp { public: std::string clsViaName = INVALID_DEF_NAME; std::string clsOrientation = "N"; // Default orientation DBU clsExtension = 0; DBUxy clsPos; bool clsHasMask : 1; bool clsHasRectangle : 1; bool clsHasVirtual : 1; bool clsHasVia : 1; bool clsHasExtension : 1; /* * "RECT ( deltax1 deltay1 deltax2 deltay2 ) * Indicates that a rectangle is created from the previous ( x y ) * routing point using the delta values. The RECT values leave the * current point and layer unchanged." Source: LEf/DEf Reference Manual 5.8 */ Bounds clsRect; DefRoutingPointDscp() { clsHasMask = false; clsHasRectangle = false; clsHasVirtual = false; clsHasVia = false; clsHasExtension = false; } // end constructor }; // end class // ----------------------------------------------------------------------------- //! Descriptor for wire path associated to wires class DefWireSegmentDscp { public: std::string clsLayerName = INVALID_DEF_NAME; std::vector clsRoutingPoints; // only valid to special nets. DBU clsRoutedWidth = 0; bool clsHasShape = false; std::string clsShape = ""; DefWireSegmentDscp() = default; }; // end class //! Descriptor for routed wires class DefWireDscp { public: std::vector clsWireSegments; std::string clsWireType = INVALID_DEF_NAME; DefWireDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for DEF Nets class DefNetDscp { public: std::string clsName = INVALID_DEF_NAME; bool clsHasUse = false; std::string clsUse = INVALID_DEF_NAME; std::vector clsConnections; std::vector clsWires; DefNetDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for DEF Regions class DefRegionDscp { public: std::string clsName = INVALID_DEF_NAME; std::string clsType = INVALID_DEF_NAME; // FENCE or GUIDE std::vector clsBounds; DefRegionDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for DEF rows. class DefRowDscp { public: std::string clsName = INVALID_DEF_NAME; std::string clsSite = INVALID_DEF_NAME; DBUxy clsOrigin; std::string clsOrientation = INVALID_DEF_NAME; int clsNumX = 0; int clsNumY = 0; int clsStepX = 0; int clsStepY = 0; DefRowDscp() = default; }; // end class // ----------------------------------------------------------------------------- class DefTrackDscp { public: bool clsHasRect : 1; bool clsHasPolygon : 1; std::string clsDirection = INVALID_DEF_NAME; DBU clsLocation = 0; int clsNumTracks = 0; std::vector clsLayers; DBU clsSpace = 0; DefTrackDscp() { clsHasRect = false; clsHasPolygon = false; } // end constructor }; // end class // ----------------------------------------------------------------------------- class DefGcellGridDscp { public: std::string clsMacro = ""; int clsX = 0; int clsXNum = 0; double clsXStep = 0.0; DefGcellGridDscp () = default; }; // end class // ----------------------------------------------------------------------------- class DefViaGeometryDscp { public: bool clsIsPolygon : 1; bool clsIsRect : 1; int clsMask = 0; bool clsHasMask = false; Bounds clsBounds; // TODO Polygon DefViaGeometryDscp (){ clsIsPolygon = false; clsIsRect = false; } // end constructor }; // end class // ----------------------------------------------------------------------------- class DefViaDscp { public: bool clsHasViaRule : 1; bool clsHasRowCol : 1; bool clsHasOrigin : 1; bool clsHasOffset : 1; bool clsHasPattern : 1; DBU clsXOffsetOrigin = 0; DBU clsYOffsetOrigin = 0; DBU clsXCutSize = 0; DBU clsYCutSize = 0; DBU clsXCutSpacing = 0; DBU clsYCutSpacing = 0; DBU clsXBottomEnclosure = 0; DBU clsYBottomEnclosure = 0; DBU clsXTopEnclosure = 0; DBU clsYTopEnclosure = 0; DBU clsXBottomOffset = 0; DBU clsYBottomOffset = 0; DBU clsXTopOffset = 0; DBU clsYTopOffset = 0; int clsNumCutRows = 0; int clsNumCutCols = 0; std::string clsName = INVALID_DEF_NAME; std::string clsViaRuleName = INVALID_DEF_NAME; std::string clsBottomLayer; std::string clsCutLayer; std::string clsTopLayer; std::string clsPattern; // map->first = layerName; map->second = list of geometry rects or polygons. std::map> clsGeometries; DefViaDscp() { clsHasViaRule = false; clsHasRowCol = false; clsHasOrigin = false; clsHasOffset = false; clsHasPattern = false; } // end constructor }; // end class // ----------------------------------------------------------------------------- //! Descriptor for DEF Design class DefDscp { public: bool clsHasVersion : 1; bool clsHasDevideChar : 1; bool clsHasBusBitChar : 1; bool clsHasDieBounds : 1; bool clsHasDatabaseUnits : 1; double clsVersion = 0.0; std::string clsDeviderChar = INVALID_DEF_NAME; std::string clsBusBitChars = INVALID_DEF_NAME; std::string clsDesignName = INVALID_DEF_NAME; Bounds clsDieBounds; int clsDatabaseUnits = 0; std::vector clsRows; std::vector clsComps; std::vector clsPorts; std::vector clsNets; std::vector clsRegions; std::vector clsGroups; std::vector clsSpecialNets; std::vector clsVias; std::vector clsTracks; std::vector clsGcellGrids; DefDscp() { clsHasVersion = false; clsHasDevideChar = false; clsHasBusBitChar = false; clsHasDieBounds = false; clsHasDatabaseUnits = false; } // end constructor }; // end class // ----------------------------------------------------------------------------- #endif /* DEFDESCRIPTORS_H */ ================================================ FILE: rsyn/src/rsyn/phy/util/LefDescriptors.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: PhysicalDescriptors.h * Author: jucemar * * Created on 6 de Julho de 2016, 15:29 */ #ifndef LEFDESCRIPTORS_H #define LEFDESCRIPTORS_H #include #include #include "rsyn/util/DoubleRectangle.h" #include "rsyn/util/double2.h" #include "lef5.8/lefrReader.hpp" // NOTE: Guilherme Flach - 2016/11/04 // I did not change here from double to dbu because the data is load from // lef as is and therefore it's in micron. The conversion to dbu is currently // done in the physical layer initialization. static const std::string INVALID_LEF_NAME = "**"; static const std::string DEFAULT_PIN_DIRECTION = "INPUT"; // ----------------------------------------------------------------------------- //! Descriptor for LEF Polygon class LefPolygonDscp { public: std::vector clsPolygonPoints; LefPolygonDscp() = default; }; // end class // ----------------------------------------------------------------------------- class LefPortGeometryDscp { public: std::string clsMetalName = INVALID_LEF_NAME; std::vector clsBounds; std::vector clsLefPolygonDscp; }; // end class //! Descriptor for LEF Port class LefPortDscp { public: std::vector clsLefPortGeoDscp; LefPortDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for LEF Pin class LefPinDscp { public: bool clsHasPort = false; std::string clsPinName = INVALID_LEF_NAME; std::string clsPinDirection = DEFAULT_PIN_DIRECTION; std::string clsPinUse = INVALID_LEF_NAME; DoubleRectangle clsBounds; std::vector clsPorts; LefPinDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for LEF Obstruction class LefObsDscp { public: std::string clsMetalLayer = INVALID_LEF_NAME; std::vector clsBounds; LefObsDscp() = default; }; // ----------------------------------------------------------------------------- //! Descriptor for LEF Macro class LefMacroDscp { public: lefiMacro* clsMacro = nullptr; std::vector clsPins; std::vector clsObs; LefMacroDscp() { clsMacro = new lefiMacro(); } }; // end class // ----------------------------------------------------------------------------- //! Descriptor for LEF Site class LefSiteDscp { public: std::string clsName = INVALID_LEF_NAME; double2 clsSize; bool clsHasClass = false; std::string clsSiteClass = INVALID_LEF_NAME; std::string clsSymmetry = INVALID_LEF_NAME; LefSiteDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for LEF Spacing class LefSpacingDscp { public: std::string clsLayer1 = INVALID_LEF_NAME; std::string clsLayer2 = INVALID_LEF_NAME; double clsDistance = 0.0; LefSpacingDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for LEF Via Layer. A via layer is composed by a layer and a set of rectangles. class LefViaGeometryDscp { public: DoubleRectangle clsBounds; int clsMask = 0; LefViaGeometryDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for LEF Via class LefViaDscp { public: bool clsIsDefault : 1; bool clsHasViaRule : 1; bool clsHasRowCol : 1; bool clsHasOrigin : 1; bool clsHasOffset : 1; bool clsHasResistance : 1; double clsXCutSize = 0; double clsYCutSize = 0; double clsXCutSpacing = 0; double clsYCutSpacing = 0; double clsXBottomEnclosure = 0; double clsYBottomEnclosure = 0; double clsXTopEnclosure = 0; double clsYTopEnclosure = 0; double clsXOrigin = 0; double clsYOrigin = 0; double clsXBottomOffset = 0; double clsYBottomOffset = 0; double clsXTopOffset = 0; double clsYTopOffset = 0; double clsCutResistance = 0.0; int clsNumCutRows = 0; int clsNumCutCols = 0; // map->first = layerName; map->second = list of geometry rects or polygons. std::map> clsGeometries; std::string clsName = INVALID_LEF_NAME; std::string clsViaRuleName = INVALID_LEF_NAME; std::string clsBottomLayer = INVALID_LEF_NAME; std::string clsCutLayer = INVALID_LEF_NAME; std::string clsTopLayer = INVALID_LEF_NAME; LefViaDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for LEF Layer of Via Rule and Via Rule Generate class LefViaRuleLayerDscp { public: bool clsHasDirection : 1; bool clsHasEnclosure : 1; bool clsHasWidth : 1; bool clsHasResistance : 1; bool clsHasOverhang : 1; bool clsHasMetalOverhang : 1; bool clsHasSpacing : 1; bool clsHasRect : 1; bool clsIsHorizontal : 1; bool clsIsVertical : 1; std::string clsName = INVALID_LEF_NAME; double clsEnclosure1 = 0.0; double clsEnclosure2 = 0.0; double clsCutResistance = 0.0; double clsMinWidth = 0.0; double clsMaxWidth = 0.0; double clsXSpacing = 0.0; double clsYSpacing = 0.0; DoubleRectangle clsRect; LefViaRuleLayerDscp() { clsHasDirection = false; clsHasEnclosure = false; clsHasWidth = false; clsHasResistance = false; clsHasOverhang = false; clsHasMetalOverhang = false; clsHasSpacing = false; clsHasRect = false; clsIsHorizontal = false; clsIsVertical = false; } // end constructor }; // end class //! Descriptor for LEF Via Rule and Via Rule Generate class LefViaRuleDscp { public: std::string clsName = INVALID_LEF_NAME; bool clsIsGenerate = false; bool clsIsDefault = false; std::vector clsLayers; std::vector clsVias; LefViaRuleDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for LEF Units class LefUnitsDscp { public: bool clsHasTime = false; bool clsHasCapacitance = false; bool clsHasResitance = false; bool clsHasPower = false; bool clsHasCurrent = false; bool clsHasVoltage = false; bool clsHasDatabase = false; bool clsHasFrequency = false; int clsTime = 0; int clsCapacitance = 0; int clsResitance = 0; int clsPower = 0; int clsCurrent = 0; int clsVoltage = 0; int clsDatabase = 100; // default value at LEF/DEF reference int clsFrequency = 0; LefUnitsDscp() = default; }; // end class // ----------------------------------------------------------------------------- //! Descriptor for LEF. The LEF elements are kept in the units defined at LefUnitsDscp. class LefDscp { public: int clsMajorVersion = 0; int clsMinorVersion = 0; std::string clsCaseSensitive = INVALID_LEF_NAME; std::string clsBusBitChars = INVALID_LEF_NAME; std::string clsDivideChar = INVALID_LEF_NAME; double clsManufactGrid = 0.0; LefUnitsDscp clsLefUnitsDscp; std::vector clsLefSiteDscps; std::vector clsLefLayer; std::vector clsLefMacroDscps; std::vector clsLefSpacingDscps; std::vector clsLefViaDscps; std::deque clsLefViaRuleDscps; LefDscp() = default; }; // end class // ----------------------------------------------------------------------------- #endif /* PHYSICALDESCRIPTORS_H */ ================================================ FILE: rsyn/src/rsyn/phy/util/PhysicalLayerUtil.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ #include "PhysicalUtil.h" namespace Rsyn { static const std::string NULL_PHY_NAME = "**"; static const std::string GEN_NAME = "**_"; static const std::string INVALID_NAME = "**"; Rsyn::PhysicalLayerType getPhysicalLayerType(const std::string & type) { if (type.compare("ROUTING") == 0) return ROUTING; if (type.compare("CUT") == 0) return CUT; if (type.compare("OVERLAP") == 0) return OVERLAP; if (type.compare("MASTERSLICE") == 0) return MASTERSLICE; if (type.compare("IMPLANT") == 0) return IMPLANT; return INVALID_PHY_LAYER_TYPE; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalLayerType(const Rsyn::PhysicalLayerType type) { switch (type) { case ROUTING: return "ROUTING"; case CUT: return "CUT"; case OVERLAP: return "OVERLAP"; case MASTERSLICE: return "MASTERSLICE"; case IMPLANT: return "IMPLANT"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalLayerDirection getPhysicalLayerDirection(const std::string & direction) { if (direction.compare("HORIZONTAL") == 0) return HORIZONTAL; if (direction.compare("VERTICAL") == 0) return VERTICAL; return UNKNOWN_PREFERRED_DIRECTION; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalLayerDirection(const PhysicalLayerDirection direction) { switch (direction) { case HORIZONTAL: return "HORIZONTAL"; case VERTICAL: return "VERTICAL"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalOrientation getPhysicalOrientation(const std::string &orientation) { if (orientation.compare("N") == 0) return ORIENTATION_N; if (orientation.compare("S") == 0) return ORIENTATION_S; if (orientation.compare("E") == 0) return ORIENTATION_E; if (orientation.compare("W") == 0) return ORIENTATION_W; if (orientation.compare("FN") == 0) return ORIENTATION_FN; if (orientation.compare("FS") == 0) return ORIENTATION_FS; if (orientation.compare("FE") == 0) return ORIENTATION_FE; if (orientation.compare("FW") == 0) return ORIENTATION_FW; return ORIENTATION_INVALID; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalOrientation(const Rsyn::PhysicalOrientation orientation) { switch (orientation) { case ORIENTATION_N: return "N"; case ORIENTATION_S: return "S"; case ORIENTATION_E: return "E"; case ORIENTATION_W: return "W"; case ORIENTATION_FN: return "FN"; case ORIENTATION_FS: return "FS"; case ORIENTATION_FE: return "FE"; case ORIENTATION_FW: return "FW"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalMacroClass getPhysicalMacroClass(const std::string & macroClass) { if (macroClass.compare("COVER") == 0) return MACRO_COVER; if (macroClass.compare("RING") == 0) return MACRO_RING; if (macroClass.compare("BLOCK") == 0) return MACRO_BLOCK; if (macroClass.compare("PAD") == 0) return MACRO_PAD; if (macroClass.compare("CORE") == 0) return MACRO_CORE; if (macroClass.compare("ENDCAP") == 0) return MACRO_ENDCAP; return MACRO_INVALID_CLASS; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalMacroClass(const Rsyn::PhysicalMacroClass macroClass) { switch (macroClass) { case MACRO_COVER: return "COVER"; case MACRO_RING: return "RING"; case MACRO_BLOCK: return "BLOCK"; case MACRO_PAD: return "PAD"; case MACRO_CORE: return "CORE"; case MACRO_ENDCAP: return "ENDCAP"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalSymmetry getPhysicalSymmetry(const std::string &rowSymmetry) { bool hasX = std::string::npos != rowSymmetry.find("X"); bool hasY = std::string::npos != rowSymmetry.find("Y"); bool hasR90 = std::string::npos != rowSymmetry.find("R90"); if (hasX && hasY && hasR90) return SYMMETRY_XYR90; if (hasY && hasR90) return SYMMETRY_YR90; if (hasX && hasR90) return SYMMETRY_XR90; if (hasX && hasY) return SYMMETRY_XY; if (hasR90) return SYMMETRY_R90; if (hasY) return SYMMETRY_Y; if (hasX) return SYMMETRY_X; return SYMMETRY_INVALID; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalSymmetry(const Rsyn::PhysicalSymmetry rowSymmetry) { switch (rowSymmetry) { case SYMMETRY_X: return "X"; break; case SYMMETRY_Y: return "Y"; break; case SYMMETRY_R90: return "R90"; break; case SYMMETRY_XY: return "X Y"; break; case SYMMETRY_XR90: return "X R90"; break; case SYMMETRY_YR90: return "Y R90"; break; case SYMMETRY_XYR90: return "X Y R90"; break; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- bool isPhysicalSymmetryX(const Rsyn::PhysicalSymmetry symmetry) { return symmetry == SYMMETRY_X || symmetry == SYMMETRY_XY || symmetry == SYMMETRY_XR90 || SYMMETRY_XYR90; } // end method // ----------------------------------------------------------------------------- bool isPhysicalSymmetryY(const Rsyn::PhysicalSymmetry symmetry) { return symmetry == SYMMETRY_Y || symmetry == SYMMETRY_XY || symmetry == SYMMETRY_YR90 || SYMMETRY_XYR90; } // end method // ----------------------------------------------------------------------------- bool isPhysicalSymmetryR90(const Rsyn::PhysicalSymmetry symmetry) { return symmetry == SYMMETRY_R90 || symmetry == SYMMETRY_XR90 || symmetry == SYMMETRY_YR90 || SYMMETRY_XYR90; } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalSiteClass getPhysicalSiteClass(const std::string & siteClass) { if (siteClass.compare("CORE") == 0) return PhysicalSiteClass::CORE; if (siteClass.compare("PAD") == 0) return PhysicalSiteClass::PAD; return PhysicalSiteClass::INVALID_SITECLASS; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalSiteClass(const Rsyn::PhysicalSiteClass siteClass) { switch (siteClass) { case CORE: return "CORE"; break; case PAD: return "PAD"; break; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method Rsyn::PhysicalPinDirection getPhysicalPinDirection(const std::string &direction) { if (direction.compare("INPUT") == 0) return PIN_INPUT; if (direction.compare("OUTPUT") == 0) return PIN_OUTPUT; return PIN_INVALID_DIRECTION; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalPinDirection(const Rsyn::PhysicalPinDirection pinDirection) { switch (pinDirection) { case PIN_INPUT: return "INPUT"; case PIN_OUTPUT: return "OUTPUT"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method Rsyn::PhysicalPinGeometryClass getPhysicalPinGeometryClass(const std::string & geometryClass) { if (geometryClass.compare("NONE") == 0) return PINGEOMETRYCLASS_NONE; if (geometryClass.compare("CORE") == 0) return PINGEOMETRYCLASS_CORE; if (geometryClass.compare("BUMP") == 0) return PINGEOMETRYCLASS_BUMP; return PINGEOMETRYCLASS_INVALID; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalPinGeometryClass(const Rsyn::PhysicalPinGeometryClass geometryClass) { switch (geometryClass) { case PINGEOMETRYCLASS_NONE: return "NONE"; case PINGEOMETRYCLASS_CORE: return "CORE"; case PINGEOMETRYCLASS_BUMP: return "BUMP"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- Rsyn::RegionType getPhysicalRegionType(const std::string & type) { if (type.compare("FENCE") == 0) return RegionType::FENCE; if (type.compare("GUIDE") == 0) return RegionType::GUIDE; return RegionType::INVALID; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalRegionType(const Rsyn::RegionType type) { switch (type) { case RegionType::FENCE: return "FENCE"; case RegionType::GUIDE: return "GUIDE"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalDesignMode getPhysicalDesignModeType(const std::string & type) { if (type.compare("ALL") == 0) return PhysicalDesignMode::ALL; if (type.compare("CTS") == 0) return PhysicalDesignMode::CTS; if (type.compare("FLOORPLANNING") == 0) return PhysicalDesignMode::FLOORPLANNING; if (type.compare("PLACEMENT") == 0) return PhysicalDesignMode::PLACEMENT; if (type.compare("ROUTING") == 0) return PhysicalDesignMode::ROUTING; return PhysicalDesignMode::INVALID; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalDesignModeType(const Rsyn::PhysicalDesignMode type) { switch (type) { case PhysicalDesignMode::ALL: return "ALL"; case PhysicalDesignMode::CTS: return "CTS"; case PhysicalDesignMode::FLOORPLANNING: return "FLOORPLANNING"; case PhysicalDesignMode::PLACEMENT: return "PLACEMENT"; case PhysicalDesignMode::ROUTING: return "ROUTING"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- //! Converts Physical Pin Use type from string to enum, respectively. Rsyn::PhysicalPinUse getPhysicalPinUseType(const std::string & type) { if (type.compare("SIGNAL") == 0) return PhysicalPinUse::PIN_USE_SIGNAL; if (type.compare("ANALOG") == 0) return PhysicalPinUse::PIN_USE_ANALOG; if (type.compare("POWER") == 0) return PhysicalPinUse::PIN_USE_POWER; if (type.compare("GROUND") == 0) return PhysicalPinUse::PIN_USE_GROUND; if (type.compare("CLOCK") == 0) return PhysicalPinUse::PIN_USE_CLOCK; return PhysicalPinUse::PIN_INVALID_USE; } // end method // ----------------------------------------------------------------------------- //! Converts Physical Pin Use type from enum to string, respectively. std::string getPhysicalPinUseType(const Rsyn::PhysicalPinUse type) { switch (type) { case PhysicalPinUse::PIN_USE_SIGNAL: return "SIGNAL"; case PhysicalPinUse::PIN_USE_ANALOG: return "ANALOG"; case PhysicalPinUse::PIN_USE_POWER: return "POWER"; case PhysicalPinUse::PIN_USE_GROUND: return "GROUND"; case PhysicalPinUse::PIN_USE_CLOCK: return "CLOCK"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalTrackDirection getPhysicalTrackDirectionDEF(const std::string & type) { if (type.compare("X") == 0) return Rsyn::PhysicalTrackDirection::TRACK_VERTICAL; if (type.compare("Y") == 0) return Rsyn::PhysicalTrackDirection::TRACK_HORIZONTAL; return Rsyn::PhysicalTrackDirection::INVALID_PHY_TRACK_DIRECTION; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalTrackDirectionDEF(const Rsyn::PhysicalTrackDirection type) { switch (type) { case PhysicalTrackDirection::TRACK_VERTICAL: return "X"; case PhysicalTrackDirection::TRACK_HORIZONTAL: return "Y"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- std::string getPhysicalTrackDirection(const Rsyn::PhysicalTrackDirection type) { switch (type) { case PhysicalTrackDirection::TRACK_VERTICAL: return "HORIZONTAL"; case PhysicalTrackDirection::TRACK_HORIZONTAL: return "VERTICAL"; default: return Rsyn::getPhysicalInvalidName(); } // end switch } // end method // ----------------------------------------------------------------------------- std::string getPhysicalGeneratedNamePrefix() { return GEN_NAME; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalInvalidPrefix() { return INVALID_NAME; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalInvalidName() { return INVALID_NAME; } // end method // ----------------------------------------------------------------------------- std::string getPhysicalNullName() { return NULL_PHY_NAME; } // end method // ----------------------------------------------------------------------------- } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/util/PhysicalTransform.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "PhysicalTransform.h" namespace Rsyn { const DBU PhysicalTransform::TRANSFORMATION_MATRIXES[NUM_PHY_ORIENTATION][2][2] = { // NORTH (R0) {{ 1, 0}, // | cos(0) sin(0)| { 0, 1}}, // |-sin(0) cos(0)| // SOUTH (R180) {{-1, 0}, // | cos(-180) sin(-180)| { 0, -1}}, // |-sin(-180) cos(-180)| // WEST (R90) {{ 0, -1}, // | cos(-90) sin(-90)| { 1, 0}}, // |-sin(-90) cos(-90)| // EAST (R270) {{ 0, 1}, // | cos(-270) sin(-270)| {-1, 0}}, // |-sin(-270) cos(-270)| // FLIPPED NORTH (MY) {{-1, 0}, // |-1 0| { 0, 1}}, // | 0 1| // FLIPPED SOUTH (MX) {{ 1, 0}, // |1 0| { 0, -1}}, // |0 -1| // FLIPPED WEST (MX90) {{ 0, 1}, // |1 0| | cos(90) sin(90)| { 1, 0}}, // |0 -1| |-sin(90) cos(90)| // FLIPPED EAST (MY90) {{ 0, -1}, // |-1 0| | cos(90) sin(90)| {-1, 0}} // | 0 1| |-sin(90) cos(90)| }; // end array const DBU PhysicalTransform::TRANSLATION_MATRIXES[NUM_PHY_ORIENTATION][2][2] = { // NORTH (R0) {{ 0, 0}, // 0 { 0, 0}}, // 0 // SOUTH (R180) {{ 1, 0}, // w { 0, 1}}, // h // WEST (R90) {{ 0, 1}, // h { 0, 0}}, // 0 // EAST (R270) {{ 0, 0}, // 0 { 1, 0}}, // w // FLIPPED NORTH (MY) {{ 1, 0}, // w { 0, 0}}, // 0 // FLIPPED SOUTH (MX) {{ 0, 0}, // 0 { 0, 1}}, // h // FLIPPED WEST (MX90) {{ 0, 0}, // 0 { 0, 0}}, // 0 // FLIPPED EAST (MY90) {{ 0, 1}, // h { 1, 0}} // w }; // end array } // end namespace ================================================ FILE: rsyn/src/rsyn/phy/util/PhysicalTransform.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_PHYSICAL_TRANSFORMATION_H #define RSYN_PHYSICAL_TRANSFORMATION_H #include "rsyn/core/RsynTypes.h" #include "rsyn/util/dbu.h" #include "rsyn/util/Bounds.h" #include namespace Rsyn { class PhysicalTransform { public: PhysicalTransform() : clsOrientation(ORIENTATION_INVALID) {} //! @brief Creates a transform with origin at (0, 0). //! Example of Use: Transform port geometries. PhysicalTransform(const PhysicalOrientation orientation) : clsBounds(0, 0, 0, 0), clsOrientation(orientation) {} //! @brief Creates a transform with origin at (origin.x, origin.y). PhysicalTransform(const DBUxy origin, const PhysicalOrientation orientation) : clsBounds(origin.x, origin.y, 0, 0), clsOrientation(orientation) {} //! @briief Creates a transform with origin at the lower-left point of the //! bounds with the necessary translation, obtained from the bounds size, to //! keep the lower-left position of the transformed bounds at the same //! position of the lower-left of the original bounds. //! Example of Use: Handle cell transformation where one expects that the //! cell position (lower-left) to be kept at the same position after the //! transformation. For instance, if one is flipping the boundary of a cell //! at (0, 0), the flipped cell boundary should still be at (0, 0) after the //! transformation. PhysicalTransform(const Bounds bounds, const PhysicalOrientation orientation) : clsBounds(bounds), clsOrientation(orientation) {} DBUxy apply(const DBUxy &point) const { const DBU &x = point.x - clsBounds.getX(); const DBU &y = point.y - clsBounds.getY(); const DBU &w = clsBounds.getWidth(); const DBU &h = clsBounds.getHeight(); const PhysicalOrientation &o = clsOrientation == ORIENTATION_INVALID? ORIENTATION_N : clsOrientation; // Compute transformation. const DBU (&M)[2][2] = TRANSFORMATION_MATRIXES[o]; const DBU mx = (x*M[0][0]) + (y*M[0][1]); const DBU my = (x*M[1][0]) + (y*M[1][1]); // Compute translation. const DBU (&T)[2][2] = TRANSLATION_MATRIXES[o]; const DBU tx = (w*T[0][0]) + (h*T[0][1]); const DBU ty = (w*T[1][0]) + (h*T[1][1]); // Compute transformed point. return DBUxy(mx, my) + DBUxy(tx, ty) + clsBounds.getLower(); } // end method DBUxy apply(const DBU &x, const DBU &y) const { return apply(DBUxy(x, y)); } // end method Bounds apply(const Bounds &bounds) const { const DBUxy p0 = apply(bounds.getLower()); const DBUxy p1 = apply(bounds.getUpper()); return Bounds(min(p0, p1), max(p0, p1)); } // end method Polygon apply(const Polygon &polygon) const { Polygon transformedPolygon; for (const Rsyn::Point &point : polygon.allPoints()) { transformedPolygon.addPoint(apply(point)); } // end for return transformedPolygon; } // end method Bounds getBounds() const {return clsBounds;} PhysicalOrientation getOrientation() const {return clsOrientation;} void setBounds(const Bounds &bounds) {clsBounds = bounds;} void setOrientation(const PhysicalOrientation &orientation) {clsOrientation = orientation;} private: Bounds clsBounds; PhysicalOrientation clsOrientation; static const DBU TRANSFORMATION_MATRIXES[NUM_PHY_ORIENTATION][2][2]; static const DBU TRANSLATION_MATRIXES[NUM_PHY_ORIENTATION][2][2]; }; // end class } // end namespace #endif /* TRANSFORMATION_H */ ================================================ FILE: rsyn/src/rsyn/phy/util/PhysicalTypes.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: PhysicalTypes.h * Author: jucemar * * Created on 29 de Outubro de 2015, 13:29 */ #ifndef PHYSICALDESIGN_PHYSICALTYPES_H #define PHYSICALDESIGN_PHYSICALTYPES_H #include //! @file PhysicalTypes.h //! @brief This file aggregates all Enum definitions for Rsyn::PhysicalDesign. namespace Rsyn { //! @brief Enum type associated to the Database Units of the LEF and DEF resolutions. enum DBUType : std::int8_t { /*! \brief Only used for Rsyn internal control. */ INVALID_DBU = -1, /*! \brief Database Units (DBU) defined on LEF technology Library. */ LIBRARY_DBU = 0, /*! \brief Database Units (DBU) defined on DEF. */ DESIGN_DBU = 1, /*! \brief LEF_DBU = DEF_DBU * DEF_MULT, e.g. 2000 = 1000 x 2. * LEF/DEF rules allow only integer multiple between LEF and DEF DBU resolutions.*/ MULT_FACTOR_DBU = 2, /*! \brief Only used for Rsyn internal control.*/ NUM_DBU = 3 }; // end enum // ----------------------------------------------------------------------------- //! @brief Enum type associated to the Rsyn::PhysicalInstance. enum PhysicalType : std::int8_t { //! @brief Only used for Rsyn internal control. INVALID_PHYSICAL_TYPE = -1, //! @brief A Rsyn::PhysicalInstance is defined as fixed. PHYSICAL_FIXED = 0, //! @brief A Rsyn::PhysicalInstance is defined as movable. PHYSICAL_MOVABLE = 1, //! @brief A Rsyn::PhysicalInstance is defined as block. PHYSICAL_BLOCK = 2, //! @brief A Rsyn::PhysicalInstance is defined as port. PHYSICAL_PORT = 3, //! @brief A Rsyn::PhysicalInstance is defined as fixed bounds. PHYSICAL_FIXEDBOUNDS = 4, //! @brief A Rsyn::PhysicalInstance is defined as placeable. PHYSICAL_PLACEABLE = 5, /*! \brief Only used for Rsyn internal control.*/ NUM_PHYSICAL_TYPES = 6 }; // end enum // ----------------------------------------------------------------------------- //! @brief Layer type. enum PhysicalLayerType : std::int8_t { /*! \brief Only used for Rsyn internal control.*/ INVALID_PHY_LAYER_TYPE = -1, //! @brief Layer is defined as Routing type. ROUTING = 0, //! @brief Layer is defined as cut type. CUT = 1, //! @brief Layer is defined as overlap type. OVERLAP = 2, //! @brief Layer is defined as master slice type . They are typically polysilicon. MASTERSLICE = 3, //! @brief Layer is defined as implant type. IMPLANT = 4, /*! \brief Only used for Rsyn internal control.*/ NUM_PHY_LAYER = 5 }; enum PhysicalViaLayerType : std::int8_t { INVALID_VIA_LAYER_TYPE = -1, BOTTOM_VIA_LAYER = 0, CUT_VIA_LAYER = 1, TOP_VIA_LAYER = 2, NUM_VIA_LAYERS = 3 }; // end enum enum ViaType : std::int8_t { INVALID_VIA_TYPE = -1, VIA_RULE_TYPE = 0, VIA_GEOMETRY_TYPE = 1, NUM_VIA_TYPES = 2 }; // end enum enum ViaLevel : std::int8_t { INVALID_VIA_LEVEL = -1, BOTTOM_VIA_LEVEL = 0, TOP_VIA_LEVEL = 1, NUM_VIA_LEVELS = 2 }; // end enum enum ViaRange : std::int8_t { INVALID_VIA_RANGE = -1, VIA_RANGE_MIN = 0, VIA_RANGE_MAX = 1, NUM_VIA_RANGES = 2 }; // end enum //! @brief Layer direction. enum PhysicalLayerDirection : std::int8_t { UNKNOWN_PREFERRED_DIRECTION = -1, //! @brief Layer preferred direction is defined as horizontal. HORIZONTAL = 0, //! @brief Layer preference direction is defined as vertical. VERTICAL = 1, /*! \brief Only used for Rsyn internal control.*/ NUM_PREFERRED_DIRECTIONS = 2 }; // ----------------------------------------------------------------------------- enum PhysicalTrackDirection : std::int8_t { /*! \brief Only used for Rsyn internal control.*/ INVALID_PHY_TRACK_DIRECTION = -1, //! @brief track direction is defined as vertical. //! TRACK_VERTICAL is equal to X direction defined in DEF file. TRACK_VERTICAL = 0, //! @brief track direction is defined as horizontal. //! TRACK_HORIZONTAL is equal to Y direction defined in DEF file. TRACK_HORIZONTAL = 1, /*! \brief Only used for Rsyn internal control.*/ NUM_PHY_TRACK_DIRECTION = 2 }; // ----------------------------------------------------------------------------- //! @brief Class types of the sites. enum PhysicalSiteClass : std::int8_t { /*! \brief Only used for Rsyn internal control.*/ INVALID_SITECLASS = -1, //! @brief The site is defined as PAD type. Sites are typically used in rows. PAD = 0, //! @brief The site is defined as Core type. Sites are typically used in rows. CORE = 1, /*! \brief Only used for Rsyn internal control.*/ NUM_PHY_SITECLASS = 2 }; // ----------------------------------------------------------------------------- //! @brief Pin direction enum PhysicalPinDirection : std::int8_t { //! @brief Only used for Rsyn internal control. PIN_INVALID_DIRECTION = -1, //! @brief Pin direction is input. PIN_INPUT = 0, //! @brief Pin direction is output. PIN_OUTPUT = 1, //! @brief Only used for Rsyn internal control. NUM_PHY_PIN_DIRECTION = 2 }; // end enum // ----------------------------------------------------------------------------- //! @brief Pin use type enum PhysicalPinUse : std::int8_t { //! @brief Only used for Rsyn internal control. PIN_INVALID_USE = -1, //! @brief Pin use is signal type. PIN_USE_SIGNAL = 0, //! @brief Pin use is analog type. PIN_USE_ANALOG = 1, //! @brief Pin use is power type. PIN_USE_POWER = 2, //! @brief Pin use is ground type. PIN_USE_GROUND = 3, //! @brief Pin use is clock type. PIN_USE_CLOCK = 4, //! @brief Only used for Rsyn internal control. NUM_PHY_PIN_USE = 5 }; // end enum // ----------------------------------------------------------------------------- //! @brief The class type of macros. enum PhysicalMacroClass : std::int8_t { /*! \brief Only used for Rsyn internal control.*/ MACRO_INVALID_CLASS = -1, //! @brief Macro is Cover class. MACRO_COVER = 0, //! @brief Macro is Ring class. MACRO_RING = 1, //! @brief Macro is Block class. It may have a subtype of PhysicalMacroBlockClass MACRO_BLOCK = 2, //! @brief Macro is Pad class. MACRO_PAD = 3, //! @brief Macro is Core class. MACRO_CORE = 4, //! @brief Macro is Endcap class. MACRO_ENDCAP = 5, /*! \brief Only used for Rsyn internal control.*/ NUM_PHY_MACRO_CLASS = 6 }; // ----------------------------------------------------------------------------- //! @brief The subtype of MACRO_BLOCK type from PhysicalMacroClass. enum PhysicalMacroBlockClass : std::int8_t { /*! \brief Only used for Rsyn internal control.*/ MACRO_INVALID_BLOCK_CLASS = -1, //! @brief The Block is defined as black block. MACRO_BLOCK_BLACKBOX = 0, //! @brief The Block is defined as soft block. MACRO_BLOCK_SOFT = 1, /*! \brief Only used for Rsyn internal control.*/ NUM_MACRO_BLOCK_CLASS = 2 }; // ----------------------------------------------------------------------------- //! @brief Symmetry based on Cartesian coordinate system //! @details X and Y - allows flips around axis, ROT90 - allows any of //! rotations by 0, 90, 180 or 270 degrees. //! Source: http://vlsicad.ucsd.edu/GSRC/bookshelf/Slots/Fundamental/HGraph/ //! @todo ROT90 enum PhysicalSymmetry : std::int8_t { //! @brief Only used for Rsyn internal control. SYMMETRY_INVALID = -1, //! @brief Defines the symmetry in the abscissa (X). SYMMETRY_X = 0, //! @brief Defines the symmetry in the ordinate (Y). SYMMETRY_Y = 1, //! @brief Defines the symmetry 90 degrees rotation. SYMMETRY_R90 = 2, //! @brief Defines the symmetry in the abscissa (X) and ordinate (Y). SYMMETRY_XY = 3, //! @brief Defines the symmetry in the abscissa (X) and 90 degrees rotation. SYMMETRY_XR90 = 4, //! @brief Defines the symmetry in the ordinate (Y) and 90 degrees rotation. SYMMETRY_YR90 = 5, //! @brief Defines the symmetry in the abscissa (X), ordinate (Y) and 90 degrees rotation. SYMMETRY_XYR90 = 6, //! @brief Only used for Rsyn internal control. NUM_PHY_SYMMETRY = 7 }; // end enum // ----------------------------------------------------------------------------- //! @brief Class type for the Pin geometry object. enum PhysicalPinGeometryClass : std::int8_t { //! @brief Only used for Rsyn internal control. PINGEOMETRYCLASS_INVALID = -1, //! @brief A pin geometry has none class defined. It is the default geometry class type. PINGEOMETRYCLASS_NONE = 0, //! @brief A pin geometry has Core class defined. PINGEOMETRYCLASS_CORE = 1, //! @brief A pin geometry has Bump class defined. PINGEOMETRYCLASS_BUMP = 2, //! @brief Only used for Rsyn internal control. NUM_PINGEOMETRYCLASS = 3 }; // end enum // ----------------------------------------------------------------------------- //! @brief Region type for the Region object. enum class RegionType : std::int8_t { INVALID = -1, FENCE = 0, GUIDE = 1 }; // end enum class // ----------------------------------------------------------------------------- //! @brief Layout may be upload in physical design only for Floorplanning, //! Placement, CTS or Routing. It avoids loading unnecessary data. enum class PhysicalDesignMode : std::int8_t { INVALID = -1, ALL = 0, FLOORPLANNING = 1, PLACEMENT = 2, CTS = 3, ROUTING = 4, }; // end enum class // ----------------------------------------------------------------------------- //! @brief Layout may be upload in physical design only for Floorplanning, //! Placement, CTS or Routing. It avoids loading unnecessary data. enum class PhysicalGCellDirection : std::int8_t { INVALID = -1, VERTICAL = 0, HORIZONTAL = 1 }; // end enum class // ----------------------------------------------------------------------------- enum PhysicalEventType { PHYSICAL_EVENT_DESTRUCTION, PHYSICAL_EVENT_POST_NET_ROUTING_CHANGE, NUM_PHYSICAL_EVENTS }; // end enum } // end namespace #endif /* PHYSICALDESIGN_PHYSICALTYPES_H */ ================================================ FILE: rsyn/src/rsyn/phy/util/PhysicalUtil.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef PHYSICALDESIGN_PHYSICALUTIL_H #define PHYSICALDESIGN_PHYSICALUTIL_H #include #include "rsyn/core/RsynTypes.h" #include "rsyn/phy/util/PhysicalTypes.h" namespace Rsyn { //! @file PhysicalUtil.h //! @brief This file aggregates conversion methods from/to Enum to/from string for Rsyn::PhysicalDesign. //! Converts Layer type from string to enum, respectively. Rsyn::PhysicalLayerType getPhysicalLayerType(const std::string &type); //! Converts Layer type from enum to string, respectively. std::string getPhysicalLayerType(const Rsyn::PhysicalLayerType type); //! Converts Layer direction from string to enum, respectively. Rsyn::PhysicalLayerDirection getPhysicalLayerDirection(const std::string &direction); //! Converts Layer direction from enum to string, respectively. std::string getPhysicalLayerDirection(const Rsyn::PhysicalLayerDirection direction); //! Converts Orientation from string to enum, respectively. Rsyn::PhysicalOrientation getPhysicalOrientation(const std::string &orientation); //! Converts Orientation from enum to string, respectively. std::string getPhysicalOrientation(const Rsyn::PhysicalOrientation orientation); //! Converts Macro Class from string to enum, respectively. Rsyn::PhysicalMacroClass getPhysicalMacroClass(const std::string & macroClass); //! Converts Macro Class from enum to string, respectively. std::string getPhysicalMacroClass(const Rsyn::PhysicalMacroClass macroClass); //! Converts Symmetry from string to enum, respectively. Rsyn::PhysicalSymmetry getPhysicalSymmetry(const std::string &rowSymmetry); //! Converts Symmetry from enum to string, respectively. std::string getPhysicalSymmetry(const Rsyn::PhysicalSymmetry rowSymmetry); // ! @brief check if PhysicalSymmetry has symmetry to X. bool isPhysicalSymmetryX(const Rsyn::PhysicalSymmetry symmetry); // ! @brief check if PhysicalSymmetry has symmetry to Y. bool isPhysicalSymmetryY(const Rsyn::PhysicalSymmetry symmetry); // ! @brief check if PhysicalSymmetry has symmetry to XR90. bool isPhysicalSymmetryR90(const Rsyn::PhysicalSymmetry symmetry); //! Converts Site Class from string to enum, respectively. Rsyn::PhysicalSiteClass getPhysicalSiteClass(const std::string & siteClass); //! Converts Site Class from enum to string, respectively. std::string getPhysicalSiteClass(const Rsyn::PhysicalSiteClass siteClass); //! Converts Pin Direction from string to enum, respectively. Rsyn::PhysicalPinDirection getPhysicalPinDirection(const std::string &direction); //! Converts Pin Direction from enum to string, respectively. std::string getPhysicalPinDirection(const Rsyn::PhysicalPinDirection pinDirection); //! Converts Pin Geometry Class from string to enum, respectively. Rsyn::PhysicalPinGeometryClass getPhysicalPinGeometryClass(const std::string & geometryClass); //! Converts Pin Port Class from enum to string, respectively. std::string getPhysicalPinGeometryClass(const Rsyn::PhysicalPinGeometryClass geometryClass); //! Converts Region type from string to enum, respectively. Rsyn::RegionType getPhysicalRegionType(const std::string & type); //! Converts Region type from enum to string, respectively. std::string getPhysicalRegionType(const Rsyn::RegionType type); //! Converts Physical Design Mode type from string to enum, respectively. Rsyn::PhysicalDesignMode getPhysicalDesignModeType(const std::string & type); //! Converts Physical Design Mode type from enum to string, respectively. std::string getPhysicalDesignModeType(const Rsyn::PhysicalDesignMode type); //! Converts Physical Pin Use type from string to enum, respectively. Rsyn::PhysicalPinUse getPhysicalPinUseType(const std::string & type); //! Converts Physical Pin Use type from enum to string, respectively. std::string getPhysicalPinUseType(const Rsyn::PhysicalPinUse type); Rsyn::PhysicalTrackDirection getPhysicalTrackDirectionDEF(const std::string & type); std::string getPhysicalTrackDirectionDEF(const Rsyn::PhysicalTrackDirection type); std::string getPhysicalTrackDirection(const Rsyn::PhysicalTrackDirection type); //! Returns a prefix key word to generated names. std::string getPhysicalGeneratedNamePrefix(); //! Returns a prefix key word to invalid prefix. std::string getPhysicalInvalidPrefix(); //! Returns a prefix key word to invalid name. std::string getPhysicalInvalidName(); //! Returns a prefix key word to null name. std::string getPhysicalNullName(); // ***************************************************************************** // * // * Overloading operator<< // * // * // ***************************************************************************** // ----------------------------------------------------------------------------- //! Overloads operator << to Symmetry. inline std::ostream& operator<<(std::ostream& out, const Rsyn::PhysicalSymmetry symmetry) { return out << getPhysicalSymmetry(symmetry); } // end operator overloading // ----------------------------------------------------------------------------- //! Overloads operator << to Layer type. inline std::ostream& operator<<(std::ostream& out, const Rsyn::PhysicalLayerType layerType) { return out << getPhysicalLayerType(layerType); } // end operator overloading // ----------------------------------------------------------------------------- //! Overloads operator << to Layer Direction. inline std::ostream& operator<<(std::ostream& out, const Rsyn::PhysicalLayerDirection direction) { return out << getPhysicalLayerDirection(direction); } // end operator overloading // ----------------------------------------------------------------------------- //! Overloads operator << to Orientation. inline std::ostream& operator<<(std::ostream& out, const Rsyn::PhysicalOrientation orientation) { return out << getPhysicalOrientation(orientation); } // end operator overloading // ----------------------------------------------------------------------------- //! Overloads operator << to Macro Class. inline std::ostream& operator<<(std::ostream& out, const Rsyn::PhysicalMacroClass macroClass) { return out << getPhysicalMacroClass(macroClass); } // end operator overloading // ----------------------------------------------------------------------------- //! Overloads operator << to Site Class. inline std::ostream& operator<<(std::ostream& out, const Rsyn::PhysicalSiteClass siteClass) { return out << getPhysicalSiteClass(siteClass); } // end operator overloading // ----------------------------------------------------------------------------- //! Overloads operator << to Pin Direction. inline std::ostream& operator<<(std::ostream& out, const Rsyn::PhysicalPinDirection pinDirection) { return out << getPhysicalPinDirection(pinDirection); } // end operator overloading // ----------------------------------------------------------------------------- //! Overloads operator << to Pin Port Class. inline std::ostream& operator<<(std::ostream& out, const Rsyn::PhysicalPinGeometryClass pinPortClass) { return out << getPhysicalPinGeometryClass(pinPortClass); } // end operator overloading // ----------------------------------------------------------------------------- //! Overloads operator << to Region type. inline std::ostream& operator<<(std::ostream& out, const Rsyn::RegionType type) { return out << getPhysicalRegionType(type); } // end operator overloading // ----------------------------------------------------------------------------- //! Overloads operator << to Physical Pin Use type. inline std::ostream& operator<<(std::ostream& out, const Rsyn::PhysicalPinUse type) { return out << getPhysicalPinUseType(type); } // end operator overloading // ----------------------------------------------------------------------------- //! Overloads operator << to Physical Track direction. inline std::ostream& operator<<(std::ostream& out, const Rsyn::PhysicalTrackDirection type) { return out << getPhysicalTrackDirection(type); } // end operator overloading // ----------------------------------------------------------------------------- } // end namespace #endif /* PHYSICALDESIGN_PHYSICALUTIL_H */ ================================================ FILE: rsyn/src/rsyn/session/Reader.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: Reader.h * Author: jucemar * * Created on 18 de Fevereiro de 2017, 08:20 */ #ifndef RSYN_READER_H #define RSYN_READER_H #include "rsyn/util/Json.h" #include "rsyn/io/reader/PopulateRsyn.h" namespace Rsyn { class Session; class Reader : public PopulateRsyn { public: virtual bool load(const Rsyn::Json ¶ms) = 0; }; // end class } // end namespace #endif /* RSYN_READER_H */ ================================================ FILE: rsyn/src/rsyn/session/Service.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_SERVICE_H #define RSYN_SERVICE_H #include "rsyn/util/Json.h" namespace Rsyn { class Session; enum ServiceRequestType { SERVICE_OPTIONAL, SERVICE_MANDATORY }; // end enum class Service { public: virtual void start(const Rsyn::Json ¶ms) = 0; virtual void stop() = 0; }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/session/Session.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "Session.h" #include "rsyn/util/Json.h" #include "rsyn/phy/PhysicalService.h" #include "rsyn/util/Environment.h" namespace Rsyn { static Startup initEngine([]{ // This will ensure the engine singleton gets initialized when the program // starts. }); // ----------------------------------------------------------------------------- SessionData * Session::sessionData = nullptr; // ----------------------------------------------------------------------------- void Session::init() { if (checkInitialized()) return; std::setlocale(LC_ALL, "en_US.UTF-8"); sessionData = new SessionData(); // TODO: hard coded sessionData->clsInstallationPath = "../../rsyn/install"; // Register services registerServices(); // Register readers. registerReaders(); // Create design. sessionData->clsDesign.create("__Root_Design__"); // Create library sessionData->clsLibrary = Library(new LibraryData); sessionData->clsLibrary->designData = sessionData->clsDesign.data; checkInitialized(true); } // end constructor // ----------------------------------------------------------------------------- Rsyn::Design Session::getDesign() { return sessionData->clsDesign; } // end method // ----------------------------------------------------------------------------- Rsyn::Library Session::getLibrary() { return sessionData->clsLibrary; } // end method // ----------------------------------------------------------------------------- Rsyn::Module Session::getTopModule() { return getDesign().getTopModule(); } // end method // ----------------------------------------------------------------------------- Rsyn::PhysicalDesign Session::getPhysicalDesign() { if (isServiceRunning("rsyn.physical")) { PhysicalService *service = getService("rsyn.physical"); return service->getPhysicalDesign(); } else { return nullptr; } // end else } // end method // ----------------------------------------------------------------------------- std::string Session::mergePathAndFileName(const std::string &path, const std::string &fileName) { const char separator = boost::filesystem::path::preferred_separator; if (!path.empty() && (path.back() != separator && path.back() != '/')) { return path + separator + fileName; } else { return path + fileName; } // end else } // end method // ----------------------------------------------------------------------------- std::string Session::findFile(const std::string fileName, const std::string extraPath) { // Check if the file exists without any path. if (boost::filesystem::exists(fileName)) { return fileName; } // end if // Check if the file exists in the extra path. if (!extraPath.empty()) { const std::string fullFileName = mergePathAndFileName(extraPath, fileName); if (boost::filesystem::exists(fullFileName)) { return fullFileName; } // end if } // end if // Check if the file exists in the paths. for (const std::string &path : sessionData->clsPaths) { const std::string fullFileName = mergePathAndFileName(path, fileName); if (boost::filesystem::exists(fullFileName)) { return fullFileName; } // end if } // end for // File not found. return ""; } // end method // ----------------------------------------------------------------------------- void Session::runReader(const std::string &name, const Rsyn::Json ¶ms) { auto it = sessionData->clsReaders.find(name); if (it == sessionData->clsReaders.end()) { std::cout << "ERROR: Reader '" << name << "' was not " "registered.\n"; } else { std::unique_ptr reader(it->second()); reader->load(params); } // end else } // end method // ----------------------------------------------------------------------------- bool Session::startService(const std::string &name, const Rsyn::Json ¶ms, const bool dontErrorOut) { auto it = sessionData->clsServiceInstanciationFunctions.find(name); if (it == sessionData->clsServiceInstanciationFunctions.end()) { if (!dontErrorOut) { std::cout << "ERROR: Service '" << name << "' was not " "registered.\n"; std::exit(1); } // end if return false; } else { Service * service = getServiceInternal(name); if (!service) { service = it->second(); service->start(params); sessionData->clsRunningServices[name] = service; return true; } else { if (!dontErrorOut) { std::cout << "WARNING: Service '" << name << "' is already running.\n"; } // end if return false; } // end else } // end else } // end method } /* namespace Rsyn */ ================================================ FILE: rsyn/src/rsyn/session/Session.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_SESSION_H #define RSYN_SESSION_H #include #include "rsyn/session/Service.h" #include "rsyn/session/Reader.h" #include "rsyn/util/Json.h" #include "rsyn/core/Rsyn.h" #include "rsyn/util/Units.h" namespace Rsyn { class PhysicalDesign; typedef std::function ServiceInstantiatonFunction; typedef std::function ReaderInstantiatonFunction; //////////////////////////////////////////////////////////////////////////////// // Session Data //////////////////////////////////////////////////////////////////////////////// struct SessionData { //////////////////////////////////////////////////////////////////////////// // Session Variables //////////////////////////////////////////////////////////////////////////// std::map clsSessionVariables; //////////////////////////////////////////////////////////////////////////// // Services //////////////////////////////////////////////////////////////////////////// // Generic functions used to instantiate optimizers by name. std::unordered_map clsServiceInstanciationFunctions; std::unordered_map clsRunningServices; //////////////////////////////////////////////////////////////////////////// // Loader //////////////////////////////////////////////////////////////////////////// // Generic functions used to instantiate optimizers by name. std::unordered_map clsReaders; //////////////////////////////////////////////////////////////////////////// // Design/Library //////////////////////////////////////////////////////////////////////////// Rsyn::Design clsDesign; Rsyn::Library clsLibrary; //////////////////////////////////////////////////////////////////////////// // Configuration //////////////////////////////////////////////////////////////////////////// std::string clsInstallationPath; //////////////////////////////////////////////////////////////////////////// // Misc //////////////////////////////////////////////////////////////////////////// std::list clsPaths; }; // end struct //////////////////////////////////////////////////////////////////////////////// // Session Proxy //////////////////////////////////////////////////////////////////////////////// class Session : public Rsyn::Proxy { public: Session() { data = sessionData; }; Session(std::nullptr_t) { data = nullptr; } Session &operator=(const Session &other) { data = other.data; return *this; } static void init(); //! @note To prevent "static variable order initialization fiasco", the // static variable signaling that the engine was initialized is // stored inside this function. In this way, we can guarantee it will // be initialized to false before being used. static bool checkInitialized(const bool markAsInitialized = false) { static bool sessionInitialized = false; if (markAsInitialized) sessionInitialized = true; return sessionInitialized; } // end method private: static SessionData * sessionData; //////////////////////////////////////////////////////////////////////////// // Session Variables //////////////////////////////////////////////////////////////////////////// public: static void setSessionVariable(const std::string &name, const Rsyn::Json &value) { sessionData->clsSessionVariables[name] = value; } // end method static void unsetSessionVariable(const std::string &name) { sessionData->clsSessionVariables.erase(name); } // end method static const bool getSessionVariableAsBool(const std::string &name, const bool defaultValue = false) { auto it = sessionData->clsSessionVariables.find(name); return (it != sessionData->clsSessionVariables.end())? it->second.get() : defaultValue; } // end method static const int getSessionVariableAsInteger(const std::string &name, const int defaultValue = 0) { auto it = sessionData->clsSessionVariables.find(name); return (it != sessionData->clsSessionVariables.end())? it->second.get() : defaultValue; } // end method static const float getSessionVariableAsFloat(const std::string &name, const float defaultValue = 0.0f) { auto it = sessionData->clsSessionVariables.find(name); return (it != sessionData->clsSessionVariables.end())? it->second.get() : defaultValue; } // end method static const std::string getSessionVariableAsString(const std::string &name, const std::string &defaultValue = "") { auto it = sessionData->clsSessionVariables.find(name); return (it != sessionData->clsSessionVariables.end())? it->second.get() : defaultValue; } // end method static const Rsyn::Json getSessionVariableAsJson(const std::string &name, const Rsyn::Json &defaultValue = {}) { auto it = sessionData->clsSessionVariables.find(name); return (it != sessionData->clsSessionVariables.end())? it->second : defaultValue; } // end method //////////////////////////////////////////////////////////////////////////// // Services //////////////////////////////////////////////////////////////////////////// // Register services. static void registerServices(); public: // Helper class to allow seamless casting from a Service pointer to any type // which implements operator=(Service *) is is directly compatible. class ServiceHandler { private: Service *clsService; public: ServiceHandler(Service *service) : clsService(service) {} template operator T *() { T * pointer = dynamic_cast(clsService); if (pointer != clsService) { std::cout << "ERROR: Trying to cast a service to the wrong type.\n"; throw Exception("Trying to cast a service to the wrong type."); } // end if return pointer; } // end operator }; // end class // Register a service. template static void registerService(const std::string &name) { auto it = sessionData->clsServiceInstanciationFunctions.find(name); if (it != sessionData->clsServiceInstanciationFunctions.end()) { std::cout << "ERROR: Service '" << name << "' was already " "registered.\n"; std::exit(1); } else { sessionData->clsServiceInstanciationFunctions[name] = []() -> Service *{ return new T(); }; } // end else } // end method // Start a service. static bool startService(const std::string &name, const Rsyn::Json ¶ms = {}, const bool dontErrorOut = false); // Gets a running service. static ServiceHandler getService(const std::string &name, const ServiceRequestType requestType = SERVICE_MANDATORY) { Service *service = getServiceInternal(name); if (!service && (requestType == SERVICE_MANDATORY)) { std::cout << "ERROR: Service '" << name << "' was not started.\n"; throw Exception("ERROR: Service '" + name + "' was not started"); } // end if return ServiceHandler(service); } // end method // Checks if a service is registered. static bool isServiceRegistered(const std::string &name) { auto it = sessionData->clsServiceInstanciationFunctions.find(name); return (it != sessionData->clsServiceInstanciationFunctions.end()); } // end method // Checks if a service is running. static bool isServiceRunning(const std::string &name) { return getServiceInternal(name) != nullptr; } // end method private: static Service * getServiceInternal(const std::string &name) { auto it = sessionData->clsRunningServices.find(name); return it == sessionData->clsRunningServices.end()? nullptr : it->second; } // end method static void listService(std::ostream & out = std::cout) { out<<"List of services "; out<<"([R] -> Running, [S] -> Stopped):\n"; // print only running services for (std::pair srv : sessionData->clsServiceInstanciationFunctions) { if (!isServiceRunning(srv.first)) continue; out << "\t[R] " << srv.first << "\n"; } // end for // print only stopped services for (std::pair srv : sessionData->clsServiceInstanciationFunctions) { if (isServiceRunning(srv.first)) continue; out << "\t[S] "< reader : sessionData->clsReaders) { out<<"\t"< static void registerReader(const std::string &name) { auto it = sessionData->clsReaders.find(name); if (it != sessionData->clsReaders.end()) { std::cout << "ERROR: Reader '" << name << "' was already " "registered.\n"; std::exit(1); } else { sessionData->clsReaders[name] = []() -> Reader *{ return new T(); }; } // end else } // end method // Run an loader. static void runReader(const std::string &name, const Rsyn::Json ¶ms = {}); //////////////////////////////////////////////////////////////////////////// // Misc //////////////////////////////////////////////////////////////////////////// static Rsyn::Design getDesign(); static Rsyn::Library getLibrary(); static Rsyn::Module getTopModule(); static Rsyn::PhysicalDesign getPhysicalDesign(); static const std::string &getInstallationPath() { return sessionData->clsInstallationPath; } //////////////////////////////////////////////////////////////////////////// // Utilities //////////////////////////////////////////////////////////////////////////// private: static std::string mergePathAndFileName(const std::string &path, const std::string &fileName); public: //! @brief Find a file in the current path. If found, returns its absolute //! path, an empty string otherwise. //! @param extraPath can be used to specify an extra path location besides //! the one stored internally in the current path list. std::string findFile(const std::string fileName, const std::string extraPath = ""); }; // end class //////////////////////////////////////////////////////////////////////////////// // Startup //////////////////////////////////////////////////////////////////////////////// // Helper class used to perform component initialization during the application // startup. Declare a startup object in a cpp file: // // Rsyn::Startup startup([]{ // Rsyn::Session::registerService(...); // Rsyn::Session::registerMessage(...); // }); // end startup // // This will construct a global object that will be called during the // application initialization. class Startup { public: Startup(std::function f) { if (!Session::checkInitialized()) Session::init(); f(); } // end constructor }; // end class } // end namespace #endif /* INFRA_ICCAD15_SESSION_H_ */ ================================================ FILE: rsyn/src/rsyn/setup/reader.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ #include // Readers #include "rsyn/io/reader/ISPD2018Reader.h" // Registration namespace Rsyn { void Session::registerReaders() { registerReader("ispd18"); registerReader("ispd19"); // ispd19 files are the same from ispd18 contest } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/setup/service.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // HOW-TO // To register a step, just include its .h below and add a call to // "registerService(name)" where T is the service class name and name how // the service will be referred to. #include // Services #include "rsyn/phy/PhysicalService.h" #include "rsyn/ispd18/RoutingGuide.h" // Registration namespace Rsyn { void Session::registerServices() { registerService("rsyn.physical"); registerService("rsyn.routingGuide"); } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/util/Array.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_MULTIDIMENSIONAL_ARRAY_H #define RSYN_MULTIDIMENSIONAL_ARRAY_H #include #include #include #include #include // @todo make it generic to work with any number of dimensions // ============================================================================= // Array2D // ============================================================================= template< class T > class Array2D { private: std::vector clsElements; int clsNumCols; int clsNumRows; public: Array2D() { clsNumCols = 0; clsNumRows = 0; } // end constructor void initialize( const int numCols, const int numRows ) { clsNumCols = numCols; clsNumRows = numRows; clsElements.clear(); clsElements.resize(clsNumCols * clsNumRows); } // end method void initialize( const int numCols, const int numRows, const T value ) { clsNumCols = numCols; clsNumRows = numRows; clsElements.clear(); clsElements.resize(clsNumCols * clsNumRows, value); } // end method void initialize( const int dimension ) { initialize( dimension, dimension ); } // end method void assign(const T value) { clsElements.assign(clsElements.size(), value); } // end method T & operator()( const int col, const int row ) { return clsElements[ computeLinearIndex(col,row) ]; } const T & operator()( const int col, const int row ) const { return clsElements[ computeLinearIndex(col,row) ]; } T & operator()( const int linearIndex ) { return clsElements[ linearIndex ]; } const T & operator()( const int linearIndex ) const { return clsElements[ linearIndex ]; } int getNumElements() const { return clsElements.size(); } int getNumCols() const { return clsNumCols; } int getNumRows() const { return clsNumRows; } int getCol( const int linearIndex ) const { return linearIndex % clsNumCols; } int getRow( const int linearIndex ) const { return linearIndex / clsNumCols; } int clampCol(const int col) const { return std::max(0, std::min(col, clsNumCols - 1)); } int clampRow(const int row) const { return std::max(0, std::min(row, clsNumRows - 1)); } bool isValidIndex(const int col, const int row) const { return (col>=0 && col=0 && row class Array3D { public: void initialize(const int length0, const int length1, const int length2) { initialize(length0, length1, length2, false, T()); } // end method void initialize(const int length0, const int length1, const int length2, const T &defaultValue) { initialize(length0, length1, length2, true, defaultValue); } // end method T &operator()(const int i, const int j, const int k) { return _data[getLinearIndex(i, j, k)]; } // end method const T &operator()(const int i, const int j, const int k) const { return _data[getLinearIndex(i, j, k)]; } // end method int getNumElements() const { return _data.size(); } // end method int getLength(const int dimension) const { return _length[dimension]; } // end method //! @brief Assigns all elements to a certain value. void assign(const T &value) { _data.assign(getNumElements(), value); } // end method bool isValidIndex(const int i, const int j, const int k) const { return i >= 0 && i < _length[0] && j >= 0 && j < _length[1] && k >= 0 && k < _length[2]; } // end method bool isEmpty() const {return _data.empty();} private: void initialize(const int length0, const int length1, const int length2, const bool setDefaultValue, const T &defaultValue) { _length[0] = length0; _length[1] = length1; _length[2] = length2; _data.clear(); if (setDefaultValue) { _data.assign(getNumElements(), defaultValue); } else { _data.resize(getNumElements()); } // end else } // end method //! @brief Computes a linear index given a multi-dimensional index. int getLinearIndex(const int i, const int j, const int k) const { return i + j*_length[0] + k*(_length[0]*_length[1]); } // end method std::array _length; std::vector _data; }; // end class #endif ================================================ FILE: rsyn/src/rsyn/util/AsciiProgressBar.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: AsciiProgressBar.h * Author: gaflach * * Created on September 6, 2015, 1:11 AM */ #ifndef ASCII_PROGRESS_BAR_H #define ASCII_PROGRESS_BAR_H #include #include #include static const int DEFAULT_N = 40; class AsciiProgressBar { private: const int N; int clsMaxValue; int clsCurrentValue; int clsDrawingThreshold; int clsNextDraw; void updateDrawingThreshold() { const double precision = 1.0 / N; clsDrawingThreshold = (int) (precision * clsMaxValue); } // end method void draw() { const int percentage = clsMaxValue > 0? (100*clsCurrentValue)/clsMaxValue : 100; const int middle = (N*percentage) / 100; std::cout << "\r"; std::cout << std::setw(3) << percentage << "% "; std::cout << "["; for (int i = 0; i < middle; i++) { std::cout << "="; } // end for for (int i = middle; i < N; i++) { std::cout << " "; } // end for std::cout << "]"; std::cout << std::flush; } // end method void reset(const int maxValue = 0) { clsMaxValue = maxValue; clsCurrentValue = 0; updateDrawingThreshold(); clsNextDraw = clsDrawingThreshold; } // end method public: AsciiProgressBar() : N(DEFAULT_N) { reset(); } // end constructor AsciiProgressBar(const int maxValue, const int numColumns = DEFAULT_N) : N(numColumns) { reset(maxValue); } // end constructor void setMaxValue(const int maxValue) { clsMaxValue = maxValue; updateDrawingThreshold(); } // end method void setCurrentValue(const int value) { clsCurrentValue = std::min(value, clsMaxValue); } // end method void progress(const int increment = 1) { clsCurrentValue = std::min(clsCurrentValue + increment, clsMaxValue); if (clsNextDraw >= clsDrawingThreshold) { draw(); clsNextDraw = 0; } else { clsNextDraw += increment; } // end else } // end method void finish() { clsCurrentValue = clsMaxValue; clsNextDraw = 0; draw(); std::cout << "\n"; } // end method }; // end class #endif /* ASCIIPROGRESSBAR_H */ ================================================ FILE: rsyn/src/rsyn/util/Bounds.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_BOUNDS_H #define RSYN_BOUNDS_H #include #include #include "dim.h" #include "dbu.h" // ----------------------------------------------------------------------------- class Bounds { friend ostream &operator<<( std::ostream &out, const Bounds &r ) { return out << "[" << r[LOWER] << ", " << r[UPPER] << "]"; } // end function private: DBUxy clsPoints[2]; public: Bounds() { clsPoints[0] = DBUxy(); clsPoints[1] = DBUxy(); } Bounds(const DBU xmin, const DBU ymin, const DBU xmax, const DBU ymax ) { (*this)[LOWER].set(xmin,ymin); (*this)[UPPER].set(xmax,ymax); } // end constructor Bounds(const DBUxy pmin, const DBUxy pmax ) { (*this)[LOWER] = pmin; (*this)[UPPER] = pmax; } // end constructor void updatePoints(const DBUxy pmin, const DBUxy pmax){ (*this)[LOWER] = pmin; (*this)[UPPER] = pmax; } void updatePoints(const DBU xMin, const DBU yMin, const DBU xMax, const DBU yMax){ (*this)[LOWER][X] = xMin; (*this)[LOWER][Y] = yMin; (*this)[UPPER][X] = xMax; (*this)[UPPER][Y] = yMax; } DBUxy &operator[](const int boundary) { return clsPoints[boundary]; } const DBUxy &operator[](const int boundary) const { return clsPoints[boundary]; } DBU computeLength(const int dimension) const { return (*this)[UPPER][dimension] - (*this)[LOWER][dimension]; } DBUxy computeLength() const { return (*this)[UPPER] - (*this)[LOWER]; } FloatingPointDBU computeDiagonal() const { return std::sqrt( std::pow(computeLength(X), 2) + std::pow(computeLength(Y), 2) ); } DBU computeCenter(const int dimension) const { return ( (*this)[UPPER][dimension] + (*this)[LOWER][dimension] ) / 2; } DBUxy computeCenter() const { return ( (*this)[UPPER] + (*this)[LOWER] ) / 2; } DBU computeArea() const { return computeLength(0)*computeLength(1); } DBU computeSemiperimeter() const { return computeLength(0)+computeLength(1); } DBU randomInnerPoint(const int dimension) const { const FloatingPointDBU random = rand()/double(RAND_MAX); return (DBU) ((*this)[LOWER][dimension] + random*computeLength(dimension)); } // end method DBU overlapArea( const Bounds &rect ) const { const DBU dx = std::max( (*this)[LOWER][X], rect[LOWER][X] ) - std::min( (*this)[UPPER][X], rect[UPPER][X] ); const DBU dy = std::max( (*this)[LOWER][Y], rect[LOWER][Y] ) - std::min( (*this)[UPPER][Y], rect[UPPER][Y] ); return (dx<0 && dy<0) ? dx*dy : 0; } // end method DBU getCoordinate(const Boundary bound, const Dimension dim ) const { return (*this)[bound][dim]; } DBUxy getCoordinate(const Boundary bound ) const { return (*this)[bound]; } DBU getX() const { return (*this)[LOWER][X]; } DBU getY() const { return (*this)[LOWER][Y]; } DBU getWidth() const { return computeLength(X); } DBU getHeight() const { return computeLength(Y); } DBUxy getLower() const { return (*this)[LOWER]; } DBUxy getUpper() const { return (*this)[UPPER]; } bool overlap(const Bounds &rect) const { const DBU dx = std::max( (*this)[LOWER][X], rect[LOWER][X] ) - std::min( (*this)[UPPER][X], rect[UPPER][X] ); const DBU dy = std::max( (*this)[LOWER][Y], rect[LOWER][Y] ) - std::min( (*this)[UPPER][Y], rect[UPPER][Y] ); return (dx<0 && dy<0); } // end method // Returns the rectangle formed by the intersection of this and other // rectangle. If they don't overlap returns a degenerated rectangle (zero // area) at half way between the two rectangles. Bounds overlapRectangle(const Bounds &rect) const { const DBU dx = std::max( (*this)[LOWER][X], rect[LOWER][X] ) - std::min( (*this)[UPPER][X], rect[UPPER][X] ); const DBU dy = std::max( (*this)[LOWER][Y], rect[LOWER][Y] ) - std::min( (*this)[UPPER][Y], rect[UPPER][Y] ); Bounds overlap; if ( dx<0 && dy<0 ) { overlap[LOWER] = max( (*this)[LOWER], rect[LOWER] ); overlap[UPPER] = min( (*this)[UPPER], rect[UPPER] ); } else { // Returns a zero-area rectangle at half the way of the two // rectangles. const DBUxy upper = max( (*this)[LOWER], rect[LOWER] ); const DBUxy lower = min( (*this)[UPPER], rect[UPPER] ); overlap[LOWER] = (upper+lower) / 2; overlap[UPPER] = overlap[LOWER]; } // end else return overlap; } // end method // Returns the dimension length overlap of this and other rectangle. Otherwise, returns zero DBU overlapDimensionLength(const Bounds &rect, const Dimension dim ) const { const DBU delta = std::max( (*this)[LOWER][dim], rect[LOWER][dim] ) - std::min( (*this)[UPPER][dim], rect[UPPER][dim] ); return delta < 0 ? -delta : 0; } // end method // Check if a value is in between the lower and upper bounds of this // rectangle. bool between( const DBU pos, const Dimension DIMENSION ) const { return ( pos >= (*this)[LOWER][DIMENSION] && pos <= (*this)[UPPER][DIMENSION] ); } // end method // Check if a point is inside this rectangle. bool inside( const DBU x, const DBU y ) const { return ( x >= (*this)[LOWER][X] && x <= (*this)[UPPER][X] ) && ( y >= (*this)[LOWER][Y] && y <= (*this)[UPPER][Y] ); } // end method bool inside( const DBUxy pos ) const { return between(pos[X],X) && between(pos[Y],Y); } // end method bool inside( const Bounds & bounds ) const { return inside(bounds[LOWER]) && inside(bounds[UPPER]); } // end method // Change the position of this rectangle. void moveTo( const DBU position, const Dimension DIMENSION ) { const DBU length = computeLength(DIMENSION); (*this)[LOWER][DIMENSION] = position; (*this)[UPPER][DIMENSION] = position + length; } // end method void moveTo( const DBUxy position ) { const DBUxy length = computeLength(); (*this)[LOWER] = position; (*this)[UPPER] = position + length; } // end method void moveCenterTo( const DBUxy position ) { const DBUxy halfLength = computeLength() / 2; (*this)[LOWER] = position - halfLength; (*this)[UPPER] = position + halfLength; } // end method void translate( const DBUxy displacement ) { (*this)[LOWER] += displacement; (*this)[UPPER] += displacement; } // end method void moveTo( const DBU x, const DBU y ) { moveTo(DBUxy(x,y)); } void moveCenterTo( const DBU x, const DBU y ) { moveCenterTo(DBUxy(x,y)); } void translate( const DBU x, const DBU y ) { translate(DBUxy(x,y)); } Bounds getTranslated(const DBUxy displacement) const { Bounds bounds = *this; bounds.translate(displacement); return bounds; } // end method Bounds getTranslated(const DBU x, const DBU y) const { return getTranslated(DBUxy(x, y)); } // end method // Multiple each coordinates by a scale factor. Useful when change the // coordinate system. void scaleCoordinates(const FloatingPointDBU scaling) { clsPoints[LOWER].scale(scaling); clsPoints[UPPER].scale(scaling); } // end method // Scale this rectangle using its center as the point of reference. Note // that this will keep the center of the rectangle in the same position. void scaleCentralized(const FloatingPointDBU xFactor, const FloatingPointDBU yFactor) { const DBUxy p = computeCenter(); translate(-p); clsPoints[LOWER].scale(xFactor, yFactor); clsPoints[UPPER].scale(xFactor, yFactor); translate(+p); } // end method void scaleCentralized(const FloatingPointDBU factor) { scaleCentralized(factor, factor); } // end method // Change size. void setLength(const Dimension DIMENSION, const DBU length) { clsPoints[UPPER][DIMENSION] = clsPoints[LOWER][DIMENSION] + length; } // end method // Check if this rectangle is valid, that is the lower coordinates are // smaller than the upper coordinates. bool isValid() const { return (*this)[LOWER][X] <= (*this)[UPPER][X] && (*this)[LOWER][Y] <= (*this)[UPPER][Y]; } // end method // Get the point inside the rectangle which is closest to p. DBUxy closestPoint(const DBUxy p) const { DBUxy lower = getCoordinate(LOWER); DBUxy upper = getCoordinate(UPPER); return max(min(p, upper), lower); } // end method // Make the lower be +inf and upper be -inf. Useful when computing the // bounding box of a set of points. void degenerate() { (*this)[LOWER][X] = std::numeric_limits::max(); (*this)[LOWER][Y] = std::numeric_limits::max(); (*this)[UPPER][X] = std::numeric_limits::min(); (*this)[UPPER][Y] = std::numeric_limits::min(); } // end method // Increases this rectangle so that the point x, y will be inside it. void stretchToFit(const DBU x, const DBU y) { (*this)[LOWER] = min((*this)[LOWER], DBUxy(x, y)); (*this)[UPPER] = max((*this)[UPPER], DBUxy(x, y)); } // end method void stretchToFit(const DBUxy p) { stretchToFit(p.x, p.y); } // end method void clear () { clsPoints[0].clear(); clsPoints[1].clear(); } // end method }; // end struct #endif ================================================ FILE: rsyn/src/rsyn/util/Color.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: Color.h * Author: jucemar * * Created on March 19, 2015, 1:52 PM */ #ifndef COLOR_H #define COLOR_H class Color { public: unsigned char r, g, b; bool operator == (const Color& c) const { return r == c.r && g == c.g && b == c.b; }; bool transparent; Color() { r = 255; g = 255; b = 255; transparent = false; } Color(const unsigned char red, const unsigned char green, const unsigned char blue) { setRGB(red, green, blue); } void setRGB(const unsigned char red, const unsigned char green, const unsigned char blue) { r = red; g = green; b = blue; } // end method void setRGB(Color color) { r = color.r; g = color.g; b = color.b; } // end method }; // end class #endif /* COLOR_H */ ================================================ FILE: rsyn/src/rsyn/util/Colorize.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef COLORIZE_H #define COLORIZE_H #include #include // Diverging Color Maps for Scientific Visualization // http://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf class Colorize { public: static void colorTemperature( const double weight, int &r, int &g, int &b ) { // Mangeta <-> Blue <-> Cian <-> Green <-> Yellow <-> Red const int numColors = 6; static const int R[numColors] = { 255, 0, 0, 0, 255, 255 }; static const int G[numColors] = { 0, 0, 255, 255, 255, 0 }; static const int B[numColors] = { 255, 255, 255, 0, 0, 0 }; /* Color Range based on weight * 1.0 -> Vermelho - Red * 0.9 -> Laranja - Orange * 0.8 -> Amarelo - Yellow * 0.7 -> Verde Claro - Light Green * 0.6 -> Verde Harlequin - Harlequin green * 0.5 -> Verde Spring - Spring Green * 0.4 -> Azul Ciano - Ciano Blue * 0.3 -> Azul Azure - Azure Blue * 0.2 -> Azul - Blue * 0.1 -> Azul Indigo - Indigo Blue * 0.0 -> Rosa - Pink */ // // Baseado no mapa de cores "jet" do Matlab // const int numColors = 16; // static const int R[numColors] = { 0, 0, 0, 0, 0, 0, 66, 132, 189, 255, 255, 255, 255, 255, 189, 132}; // static const int G[numColors] = { 0, 0, 66, 132, 189, 255, 255, 255, 255, 255, 189, 132, 66, 0, 0, 0}; // static const int B[numColors] = { 189, 255, 255, 255, 255, 255, 189, 132, 66, 0, 0, 0, 0, 0, 0, 0}; double temp; if ( std::isnan(weight) ) { r = g = b = 0; } else if ( std::isinf(weight) ) { r = g = b = 255; } else { if ( weight > 1.0 ) temp = (numColors-1); else if ( weight < 0 ) temp = 0; else temp = (numColors-1)*weight; const int i0 = (int) std::floor( temp ); const int i1 = (int) std::ceil( temp ); const double alpha = temp - (int)(temp); r = (int) std::floor( R[i0]*(1-alpha) + R[i1]*(alpha) + 0.5 ); g = (int) std::floor( G[i0]*(1-alpha) + G[i1]*(alpha) + 0.5 ); b = (int) std::floor( B[i0]*(1-alpha) + B[i1]*(alpha) + 0.5 ); } // end else } // end method static void colorTemperatureWarmCold( const double weight, int &r, int &g, int &b ) { static const std::array R{59, 68, 77, 87, 98, 108, 119, 130, 141, 152, 163, 174, 184, 194, 204, 213, 221, 229, 236, 241, 245, 247, 247, 247, 244, 241, 236, 229, 222, 213, 203, 192, 180}; static const std::array G{76, 90, 104, 117, 130, 142, 154, 165, 176, 185, 194, 201, 208, 213, 217, 219, 221, 216, 211, 204, 196, 187, 177, 166, 154, 141, 127, 112, 96, 80, 62, 40, 4}; static const std::array B{192, 204, 215, 225, 234, 241, 247, 251, 254, 255, 255, 253, 249, 244, 238, 230, 221, 209, 197, 185, 173, 160, 148, 135, 123, 111, 99, 88, 77, 66, 56, 47, 38}; const int numColors = R.size(); double temp; if ( std::isnan(weight) ) { r = g = b = 0; } else if ( std::isinf(weight) ) { r = g = b = 255; } else { if ( weight > 1.0 ) temp = (numColors-1); else if ( weight < 0 ) temp = 0; else temp = (numColors-1)*weight; const int i0 = (int) std::floor( temp ); const int i1 = (int) std::ceil( temp ); const double alpha = temp - (int)(temp); r = (int) std::floor( R[i0]*(1-alpha) + R[i1]*(alpha) + 0.5 ); g = (int) std::floor( G[i0]*(1-alpha) + G[i1]*(alpha) + 0.5 ); b = (int) std::floor( B[i0]*(1-alpha) + B[i1]*(alpha) + 0.5 ); } // end else } // end method }; #endif ================================================ FILE: rsyn/src/rsyn/util/Debug.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_ASSERT_H #define RSYN_ASSERT_H #include #define rsynAbort(msg) \ std::cout << "\n"; \ std::cout << "ASSERTION: " << msg << "\n"; \ std::cout << __FILE__ << ":" << __LINE__ << "\n"; \ std::cout << std::flush; \ std::exit(1); #define rsynAssert(condition, msg) \ if (!(condition)) { \ std::cout << "\n"; \ std::cout << "ASSERTION: " << #condition << "\n"; \ std::cout << __FILE__ << ":" << __LINE__ << "\n"; \ std::cout << msg << "\n"; \ std::cout << std::flush; \ std::exit(1); \ } // end if #endif ================================================ FILE: rsyn/src/rsyn/util/DoubleRectangle.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_DOUBLE_RECTANGLE_H #define RSYN_DOUBLE_RECTANGLE_H #include using std::max; using std::min; #include #include "dim.h" #include "double2.h" #include "Bounds.h" // ----------------------------------------------------------------------------- class DoubleRectangle { friend ostream &operator<<( ostream &out, const DoubleRectangle &r ) { return out << "[" << r[LOWER] << ", " << r[UPPER] << "]"; } // end function private: double2 clsPoints[2]; public: DoubleRectangle() { clsPoints[0] = double2(); clsPoints[1] = double2(); } DoubleRectangle(const double xmin, const double ymin, const double xmax, const double ymax ) { (*this)[LOWER].set(xmin,ymin); (*this)[UPPER].set(xmax,ymax); } // end constructor DoubleRectangle(const double2 pmin, const double2 pmax ) { (*this)[LOWER] = pmin; (*this)[UPPER] = pmax; } // end constructor DoubleRectangle(const Bounds &bounds) { operator=(bounds); } // end constructor void operator=(const Bounds &bounds) { clsPoints[0].x = bounds[0].x; clsPoints[0].y = bounds[0].y; clsPoints[1].x = bounds[1].x; clsPoints[1].y = bounds[1].y; } // end constructor Bounds scaleAndConvertToDbu(const double scale, const RoundingStrategy roundingLower, const RoundingStrategy roundingUpper) const { DoubleRectangle copy = *this; copy.scaleCoordinates(scale); return copy.convertToDbu(roundingLower, roundingUpper); } // end method Bounds convertToDbu( const RoundingStrategy roundingLower, const RoundingStrategy roundingUpper) const { return Bounds(clsPoints[0].convertToDbu(roundingLower), clsPoints[1].convertToDbu(roundingUpper)); } // end method Bounds scaleAndConvertToDbu(const double scale, const RoundingStrategy rounding = ROUND_DOWN) const { return scaleAndConvertToDbu(scale, rounding, rounding); } // end method Bounds convertToDbu(const RoundingStrategy rounding = ROUND_DOWN) const { return convertToDbu(rounding, rounding); } // end method void updatePoints(const double2 pmin, const double2 pmax){ (*this)[LOWER] = pmin; (*this)[UPPER] = pmax; } void updatePoints(const double xMin, const double yMin, const double xMax, const double yMax){ (*this)[LOWER][X] = xMin; (*this)[LOWER][Y] = yMin; (*this)[UPPER][X] = xMax; (*this)[UPPER][Y] = yMax; } double2 &operator[](const int boundary) { return clsPoints[boundary]; } const double2 &operator[](const int boundary) const { return clsPoints[boundary]; } double computeLength(const int dimension) const { return (*this)[UPPER][dimension] - (*this)[LOWER][dimension]; } double2 computeLength() const { return (*this)[UPPER] - (*this)[LOWER]; } double computeDiagonal() const { return std::sqrt( std::pow(computeLength(X), 2.0) + std::pow(computeLength(Y), 2.0) ); } double computeCenter(const int dimension) const { return ( (*this)[UPPER][dimension] + (*this)[LOWER][dimension] ) / 2.0; } double2 computeCenter() const { return ( (*this)[UPPER] + (*this)[LOWER] ) / 2.0; } double computeArea() const { return computeLength(0)*computeLength(1); } double computeSemiperimeter() const { return computeLength(0)+computeLength(1); } double randomInnerPoint(const int dimension) const { const double random = rand()/double(RAND_MAX); return (*this)[LOWER][dimension] + random*computeLength(dimension); } // end method double overlapArea( const DoubleRectangle &rect ) const { const double dx = max( (*this)[LOWER][X], rect[LOWER][X] ) - min( (*this)[UPPER][X], rect[UPPER][X] ); const double dy = max( (*this)[LOWER][Y], rect[LOWER][Y] ) - min( (*this)[UPPER][Y], rect[UPPER][Y] ); return (dx<0 && dy<0) ? dx*dy : 0; } // end method double getCoordinate(const Boundary bound, const Dimension dim ) const { return (*this)[bound][dim]; } double2 getCoordinate(const Boundary bound ) const { return (*this)[bound]; } bool overlap( const DoubleRectangle &rect ) const { const double dx = max( (*this)[LOWER][X], rect[LOWER][X] ) - min( (*this)[UPPER][X], rect[UPPER][X] ); const double dy = max( (*this)[LOWER][Y], rect[LOWER][Y] ) - min( (*this)[UPPER][Y], rect[UPPER][Y] ); return (dx<0 && dy<0); } // end method // Returns the rectangle formed by the intersection of this and other // rectangle. If they don't overlap returns a degenerated rectangle (zero // area) at half way between the two rectangles. DoubleRectangle overlapRectangle( const DoubleRectangle &rect ) const { const double dx = max( (*this)[LOWER][X], rect[LOWER][X] ) - min( (*this)[UPPER][X], rect[UPPER][X] ); const double dy = max( (*this)[LOWER][Y], rect[LOWER][Y] ) - min( (*this)[UPPER][Y], rect[UPPER][Y] ); DoubleRectangle overlap; if ( dx<0 && dy<0 ) { overlap[LOWER] = max( (*this)[LOWER], rect[LOWER] ); overlap[UPPER] = min( (*this)[UPPER], rect[UPPER] ); } else { // Returns a zero-area rectangle at half the way of the two // rectangles. const double2 upper = max( (*this)[LOWER], rect[LOWER] ); const double2 lower = min( (*this)[UPPER], rect[UPPER] ); overlap[LOWER] = (upper+lower) / 2.0; overlap[UPPER] = overlap[LOWER]; } // end else return overlap; } // end method // Check if a value is in between the lower and upper bounds of this // rectangle. bool between( const double pos, const Dimension DIMENSION ) const { return ( pos >= (*this)[LOWER][DIMENSION] && pos <= (*this)[UPPER][DIMENSION] ); } // end method // Check if a point is inside this rectangle. bool inside( const double x, const double y ) const { return ( x >= (*this)[LOWER][X] && x <= (*this)[UPPER][X] ) && ( y >= (*this)[LOWER][Y] && y <= (*this)[UPPER][Y] ); } // end method bool inside( const double2 pos ) const { return between(pos[X],X) && between(pos[Y],Y); } // end method // Change the position of this rectangle. void moveTo( const double position, const Dimension DIMENSION ) { const double length = computeLength(DIMENSION); (*this)[LOWER][DIMENSION] = position; (*this)[UPPER][DIMENSION] = position + length; } // end method void moveTo( const double2 position ) { const double2 length = computeLength(); (*this)[LOWER] = position; (*this)[UPPER] = position + length; } // end method void moveCenterTo( const double2 position ) { const double2 halfLength = computeLength() / 2.0; (*this)[LOWER] = position - halfLength; (*this)[UPPER] = position + halfLength; } // end method void translate( const double2 displacement ) { (*this)[LOWER] += displacement; (*this)[UPPER] += displacement; } // end method void moveTo( const double x, const double y ) { moveTo(double2(x,y)); } void moveCenterTo( const double x, const double y ) { moveCenterTo(double2(x,y)); } void translate( const double x, const double y ) { translate(double2(x,y)); } // Multiple each coordinates by a scale factor. Useful when change the // coordinate system. void scaleCoordinates(const double numb){ clsPoints[LOWER].scale(numb); clsPoints[UPPER].scale(numb); } // end method // Scale this rectangle using its center as the point of reference. Note // that this will keep the center of the rectangle in the same position. void scaleCentralized(const double2 factor) { const double2 p = computeCenter(); translate(-p); clsPoints[LOWER] *= factor; clsPoints[UPPER] *= factor; translate(+p); } // end method void scaleCentralized(const double factor) { scaleCentralized(double2(factor, factor)); } // end method // Check if this rectangle is valid, that is the lower coordinates are // smaller than the upper coordinates. bool isValid() const { return (*this)[LOWER][X] <= (*this)[UPPER][X] && (*this)[LOWER][Y] <= (*this)[UPPER][Y]; } // end method // Get the point inside the rectangle which is closest to p. double2 closestPoint(const double2 p) const { double2 lower = getCoordinate(LOWER); double2 upper = getCoordinate(UPPER); return max(min(p, upper), lower); } // end method // Make the lower be +inf and upper be -inf. Useful when computing the // bounding box of a set of points. void degenerate() { (*this)[LOWER][X] = +std::numeric_limits::infinity(); (*this)[LOWER][Y] = +std::numeric_limits::infinity(); (*this)[UPPER][X] = -std::numeric_limits::infinity(); (*this)[UPPER][Y] = -std::numeric_limits::infinity(); } // end method // Increases this rectangle so that the point x, y will be inside it. void stretchToFit(const double x, const double y) { (*this)[LOWER] = min((*this)[LOWER], double2(x, y)); (*this)[UPPER] = max((*this)[UPPER], double2(x, y)); } // end method void stretchToFit(const double2 p) { stretchToFit(p.x, p.y); } // end method void clear () { clsPoints[0].clear(); clsPoints[1].clear(); } // end method }; // end struct #endif ================================================ FILE: rsyn/src/rsyn/util/Environment.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * File: Environment.h * Author: gaflach * * Created on February 25, 2016, 6:56 PM */ #ifndef UTIL_ENVIRONMENT_H #define UTIL_ENVIRONMENT_H #include #include class Environment { private: template static bool parse(const std::string &str, T &data) { std::istringstream iss( str ); iss >> data; return !iss.fail(); } // end method template static T get(const std::string &name, const T &defaultValue) { T data; const char *value = std::getenv(name.c_str()); return value && parse(value, data)? data : defaultValue; } // end method public: static int getBoolean(const std::string &name, const bool defaultValue) { return get(name, defaultValue); } static int getInteger(const std::string &name, const int defaultValue) { return get(name, defaultValue); } static float getFloat(const std::string &name, const float defaultValue) { return get(name, defaultValue); } static double getDouble(const std::string &name, const double defaultValue) { return get(name, defaultValue); } static std::string getString(const std::string &name, const std::string &defaultValue) { return get(name, defaultValue); } }; // end class #endif ================================================ FILE: rsyn/src/rsyn/util/Exception.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef EXCEPTION_H #define EXCEPTION_H #include #include #include class Exception: public std::exception { friend std::ostream &operator<<(std::ostream &out, const Exception &e) { return out << e.what(); } // end method public: explicit Exception(const std::string& message) : clsMsg(message) {} virtual ~Exception() throw (){} virtual const char* what() const throw (){ return clsMsg.c_str(); } // end method protected: std::string clsMsg; }; // end class #endif ================================================ FILE: rsyn/src/rsyn/util/FloatRectangle.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_FLOAT_RECTANGLE_H #define RSYN_FLOAT_RECTANGLE_H #include using std::max; using std::min; #include #include "dim.h" #include "float2.h" #include "Bounds.h" // ----------------------------------------------------------------------------- class FloatRectangle { friend ostream &operator<<( ostream &out, const FloatRectangle &r ) { return out << "[" << r[LOWER] << ", " << r[UPPER] << "]"; } // end function private: float2 clsPoints[2]; public: FloatRectangle() { clsPoints[0] = float2(); clsPoints[1] = float2(); } FloatRectangle(const float xmin, const float ymin, const float xmax, const float ymax ) { (*this)[LOWER].set(xmin,ymin); (*this)[UPPER].set(xmax,ymax); } // end constructor FloatRectangle(const float2 pmin, const float2 pmax ) { (*this)[LOWER] = pmin; (*this)[UPPER] = pmax; } // end constructor FloatRectangle(const Bounds &bounds) { operator=(bounds); } // end constructor void operator=(const Bounds &bounds) { clsPoints[0].x = bounds[0].x; clsPoints[0].y = bounds[0].y; clsPoints[1].x = bounds[1].x; clsPoints[1].y = bounds[1].y; } // end constructor Bounds scaleAndConvertToDbu(const float scale, const RoundingStrategy roundingLower, const RoundingStrategy roundingUpper) const { FloatRectangle copy = *this; copy.scaleCoordinates(scale); return copy.convertToDbu(roundingLower, roundingUpper); } // end method Bounds convertToDbu( const RoundingStrategy roundingLower, const RoundingStrategy roundingUpper) const { return Bounds(clsPoints[0].convertToDbu(roundingLower), clsPoints[1].convertToDbu(roundingUpper)); } // end method Bounds scaleAndConvertToDbu(const float scale, const RoundingStrategy rounding = ROUND_DOWN) const { return scaleAndConvertToDbu(scale, rounding, rounding); } // end method Bounds convertToDbu(const RoundingStrategy rounding = ROUND_DOWN) const { return convertToDbu(rounding, rounding); } // end method void updatePoints(const float2 pmin, const float2 pmax){ (*this)[LOWER] = pmin; (*this)[UPPER] = pmax; } void updatePoints(const float xMin, const float yMin, const float xMax, const float yMax){ (*this)[LOWER][X] = xMin; (*this)[LOWER][Y] = yMin; (*this)[UPPER][X] = xMax; (*this)[UPPER][Y] = yMax; } float2 &operator[](const int boundary) { return clsPoints[boundary]; } const float2 &operator[](const int boundary) const { return clsPoints[boundary]; } float computeLength(const int dimension) const { return (*this)[UPPER][dimension] - (*this)[LOWER][dimension]; } float2 computeLength() const { return (*this)[UPPER] - (*this)[LOWER]; } float computeDiagonal() const { return std::sqrt( std::pow(computeLength(X), 2.0f) + std::pow(computeLength(Y), 2.0f) ); } float computeCenter(const int dimension) const { return ( (*this)[UPPER][dimension] + (*this)[LOWER][dimension] ) / 2.0f; } float2 computeCenter() const { return ( (*this)[UPPER] + (*this)[LOWER] ) / 2.0f; } float computeArea() const { return computeLength(0)*computeLength(1); } float computeSemiperimeter() const { return computeLength(0)+computeLength(1); } float randomInnerPoint(const int dimension) const { const float random = rand()/float(RAND_MAX); return (*this)[LOWER][dimension] + random*computeLength(dimension); } // end method float overlapArea( const FloatRectangle &rect ) const { const float dx = max( (*this)[LOWER][X], rect[LOWER][X] ) - min( (*this)[UPPER][X], rect[UPPER][X] ); const float dy = max( (*this)[LOWER][Y], rect[LOWER][Y] ) - min( (*this)[UPPER][Y], rect[UPPER][Y] ); return (dx<0 && dy<0) ? dx*dy : 0; } // end method float getCoordinate(const Boundary bound, const Dimension dim ) const { return (*this)[bound][dim]; } float2 getCoordinate(const Boundary bound ) const { return (*this)[bound]; } bool overlap( const FloatRectangle &rect ) const { const float dx = max( (*this)[LOWER][X], rect[LOWER][X] ) - min( (*this)[UPPER][X], rect[UPPER][X] ); const float dy = max( (*this)[LOWER][Y], rect[LOWER][Y] ) - min( (*this)[UPPER][Y], rect[UPPER][Y] ); return (dx<0 && dy<0); } // end method // Returns the rectangle formed by the intersection of this and other // rectangle. If they don't overlap returns a degenerated rectangle (zero // area) at half way between the two rectangles. FloatRectangle overlapRectangle( const FloatRectangle &rect ) const { const float dx = max( (*this)[LOWER][X], rect[LOWER][X] ) - min( (*this)[UPPER][X], rect[UPPER][X] ); const float dy = max( (*this)[LOWER][Y], rect[LOWER][Y] ) - min( (*this)[UPPER][Y], rect[UPPER][Y] ); FloatRectangle overlap; if ( dx<0 && dy<0 ) { overlap[LOWER] = max( (*this)[LOWER], rect[LOWER] ); overlap[UPPER] = min( (*this)[UPPER], rect[UPPER] ); } else { // Returns a zero-area rectangle at half the way of the two // rectangles. const float2 upper = max( (*this)[LOWER], rect[LOWER] ); const float2 lower = min( (*this)[UPPER], rect[UPPER] ); overlap[LOWER] = (upper+lower) / 2.0; overlap[UPPER] = overlap[LOWER]; } // end else return overlap; } // end method // Check if a value is in between the lower and upper bounds of this // rectangle. bool between( const float pos, const Dimension DIMENSION ) const { return ( pos >= (*this)[LOWER][DIMENSION] && pos <= (*this)[UPPER][DIMENSION] ); } // end method // Check if a point is inside this rectangle. bool inside( const float x, const float y ) const { return ( x >= (*this)[LOWER][X] && x <= (*this)[UPPER][X] ) && ( y >= (*this)[LOWER][Y] && y <= (*this)[UPPER][Y] ); } // end method bool inside( const float2 pos ) const { return between(pos[X],X) && between(pos[Y],Y); } // end method // Change the position of this rectangle. void moveTo( const float position, const Dimension DIMENSION ) { const float length = computeLength(DIMENSION); (*this)[LOWER][DIMENSION] = position; (*this)[UPPER][DIMENSION] = position + length; } // end method void moveTo( const float2 position ) { const float2 length = computeLength(); (*this)[LOWER] = position; (*this)[UPPER] = position + length; } // end method void moveCenterTo( const float2 position ) { const float2 halfLength = computeLength() / 2.0; (*this)[LOWER] = position - halfLength; (*this)[UPPER] = position + halfLength; } // end method void translate( const float2 displacement ) { (*this)[LOWER] += displacement; (*this)[UPPER] += displacement; } // end method void moveTo( const float x, const float y ) { moveTo(float2(x,y)); } void moveCenterTo( const float x, const float y ) { moveCenterTo(float2(x,y)); } void translate( const float x, const float y ) { translate(float2(x,y)); } // Multiple each coordinates by a scale factor. Useful when change the // coordinate system. void scaleCoordinates(const float numb){ clsPoints[LOWER].scale(numb); clsPoints[UPPER].scale(numb); } // end method // Scale this rectangle using its center as the point of reference. Note // that this will keep the center of the rectangle in the same position. void scaleCentralized(const float2 factor) { const float2 p = computeCenter(); translate(-p); clsPoints[LOWER] *= factor; clsPoints[UPPER] *= factor; translate(+p); } // end method void scaleCentralized(const float factor) { scaleCentralized(float2(factor, factor)); } // end method // Check if this rectangle is valid, that is the lower coordinates are // smaller than the upper coordinates. bool isValid() const { return (*this)[LOWER][X] <= (*this)[UPPER][X] && (*this)[LOWER][Y] <= (*this)[UPPER][Y]; } // end method // Get the point inside the rectangle which is closest to p. float2 closestPoint(const float2 p) const { float2 lower = getCoordinate(LOWER); float2 upper = getCoordinate(UPPER); return max(min(p, upper), lower); } // end method // Make the lower be +inf and upper be -inf. Useful when computing the // bounding box of a set of points. void degenerate() { (*this)[LOWER][X] = +std::numeric_limits::infinity(); (*this)[LOWER][Y] = +std::numeric_limits::infinity(); (*this)[UPPER][X] = -std::numeric_limits::infinity(); (*this)[UPPER][Y] = -std::numeric_limits::infinity(); } // end method // Increases this rectangle so that the point x, y will be inside it. void stretchToFit(const float x, const float y) { (*this)[LOWER] = min((*this)[LOWER], float2(x, y)); (*this)[UPPER] = max((*this)[UPPER], float2(x, y)); } // end method void stretchToFit(const float2 p) { stretchToFit(p.x, p.y); } // end method void clear () { clsPoints[0].clear(); clsPoints[1].clear(); } // end method }; // end struct #endif ================================================ FILE: rsyn/src/rsyn/util/FloatingPoint.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_FLOATING_POINT_H #define RSYN_FLOATING_POINT_H #include #include #include enum RoundingStrategy { ROUND_DOWN, ROUND_UP, ROUND_NEAREST }; // end enum namespace Rsyn { class Uninit { public: operator float() const { return std::numeric_limits::quiet_NaN();} operator double() const { return std::numeric_limits::quiet_NaN();} }; // end class class Infinity { public: operator float() const { return std::numeric_limits::infinity();} operator double() const { return std::numeric_limits::infinity();} }; // end class } // end namespace class FloatingPoint { public: template static bool approximatelyZero(const T a, const T precision = 1e-6f) { return std::abs(a) <= precision; } // end method template static bool notApproximatelyZero(const T a, const T precision = 1e-6f) { return !approximatelyZero(a); } // end method // Source: The Art of Computer Programming by Knuth // [TODO] It seems these functions break down when one operator is zero (0). // [TODO] Those function may not work with infinity! template static bool approximatelyEqual(const T a, const T b, const T precision = 1e-6f) { return std::abs(a - b) <= ((std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * precision); } // end method template static bool notApproximatelyEqual(const T a, const T b, const T precision = 1e-6f) { return !approximatelyEqual(a, b, precision); } // end method template static bool definitelyGreaterThan(const T a, const T b, const T precision = 1e-6f) { return (a - b) > ((std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * precision); } // end method template // added by Jucemar. Check if is correct static bool definitelyGreaterEqualThan(const T a, const T b, const T precision = 1e-6f) { return (a - b) >= ((std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * precision); } // end method template static bool definitelyLessThan(const T a, const T b, const T precision = 1e-6f) { return (b - a) > ((std::abs(a) < std::abs(b) ? std::abs(b) : std::abs(a)) * precision); } // end method static bool isInit(const float value) {return isInit(value);} static bool isInit(const double value) {return isInit(value);} static bool isUninit(const float value) {return isUninit(value);} static bool isUninit(const double value) {return isUninit(value);} static bool isInfinity(const float value) {return isInfinity(value);} static bool isInfinity(const double value) {return isInfinity(value);} static int round(const float value, const RoundingStrategy roudingStrategy) {return round(value, roudingStrategy);} static long round(const double value, const RoundingStrategy roudingStrategy) {return round(value, roudingStrategy);} static Rsyn::Infinity getInfinity() {return Rsyn::Infinity();} static Rsyn::Uninit getUninit() {return Rsyn::Uninit();} private: template inline static R round(const T value, const RoundingStrategy roudingStrategy) { switch (roudingStrategy) { case ROUND_DOWN: return (R) std::floor(value); case ROUND_UP: return (R) std::ceil (value); case ROUND_NEAREST: return (R) std::round(value); default: assert(false); return 0; } // end switch } // end method template static bool isInit(const T value) { return !std::isnan(value); } // end method template static bool isUninit(const T value) { return std::isnan(value); } // end method template static bool isInfinity(const T value) { return std::isinf(value); } // end method }; // end class #endif ================================================ FILE: rsyn/src/rsyn/util/Json.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_JSON_H #define RSYN_JSON_H #include "rsyn/3rdparty/json/json.hpp" namespace Rsyn { typedef nlohmann::json Json; } // end namespace #endif /* JSON_H */ ================================================ FILE: rsyn/src/rsyn/util/MD5.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* MD5 converted to C++ class by Frank Thilo (thilo@unix-ag.org) for bzflag (http://www.bzflag.org) based on: md5.h and md5.c reference implementation of RFC 1321 Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ #ifndef BZF_MD5_H #define BZF_MD5_H #include #include #include //////////////////////////////////////////////////////////////////////////////// // Interface //////////////////////////////////////////////////////////////////////////////// // a small class for calculating MD5 hashes of strings or byte arrays // it is not meant to be fast or secure // // usage: 1) feed it blocks of uchars with update() // 2) finalize() // 3) get hexdigest() string // or // MD5(std::string).hexdigest() // // assumes that char is 8 bit and int is 32 bit class MD5 { public: typedef unsigned int size_type; // must be 32bit MD5(); MD5(const std::string& text); void update(const unsigned char *buf, size_type length); void update(const char *buf, size_type length); MD5& finalize(); std::string hexdigest() const; friend std::ostream& operator<<(std::ostream&, MD5 md5); private: void init(); typedef unsigned char uint1; // 8bit typedef unsigned int uint4; // 32bit enum {blocksize = 64}; // VC6 won't eat a const static int here void transform(const uint1 block[blocksize]); static void decode(uint4 output[], const uint1 input[], size_type len); static void encode(uint1 output[], const uint4 input[], size_type len); bool finalized; uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk uint4 count[2]; // 64bit counter for number of bits (lo, hi) uint4 state[4]; // digest so far uint1 digest[16]; // the result // low level logic operations static inline uint4 F(uint4 x, uint4 y, uint4 z); static inline uint4 G(uint4 x, uint4 y, uint4 z); static inline uint4 H(uint4 x, uint4 y, uint4 z); static inline uint4 I(uint4 x, uint4 y, uint4 z); static inline uint4 rotate_left(uint4 x, int n); static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); }; //////////////////////////////////////////////////////////////////////////////// // Implementation //////////////////////////////////////////////////////////////////////////////// /* MD5 converted to C++ class by Frank Thilo (thilo@unix-ag.org) for bzflag (http://www.bzflag.org) based on: md5.h and md5.c reference implemantion of RFC 1321 Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ // Constants for MD5Transform routine. #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 /////////////////////////////////////////////// // F, G, H and I are basic MD5 functions. inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) { return x&y | ~x&z; } inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) { return x&z | y&~z; } inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) { return x^y^z; } inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) { return y ^ (x | ~z); } // rotate_left rotates x left n bits. inline MD5::uint4 MD5::rotate_left(uint4 x, int n) { return (x << n) | (x >> (32-n)); } // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. // Rotation is separate from addition to prevent recomputation. inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { a = rotate_left(a+ F(b,c,d) + x + ac, s) + b; } inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { a = rotate_left(a + G(b,c,d) + x + ac, s) + b; } inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { a = rotate_left(a + H(b,c,d) + x + ac, s) + b; } inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { a = rotate_left(a + I(b,c,d) + x + ac, s) + b; } ////////////////////////////////////////////// // default ctor, just initailize inline MD5::MD5() { init(); } ////////////////////////////////////////////// // nifty shortcut ctor, compute MD5 for string and finalize it right away inline MD5::MD5(const std::string &text) { init(); update(text.c_str(), text.length()); finalize(); } ////////////////////////////// inline void MD5::init() { finalized=false; count[0] = 0; count[1] = 0; // load magic initialization constants. state[0] = 0x67452301; state[1] = 0xefcdab89; state[2] = 0x98badcfe; state[3] = 0x10325476; } ////////////////////////////// // decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4. inline void MD5::decode(uint4 output[], const uint1 input[], size_type len) { for (unsigned int i = 0, j = 0; j < len; i++, j += 4) output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) | (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24); } ////////////////////////////// // encodes input (uint4) into output (unsigned char). Assumes len is // a multiple of 4. inline void MD5::encode(uint1 output[], const uint4 input[], size_type len) { for (size_type i = 0, j = 0; j < len; i++, j += 4) { output[j] = input[i] & 0xff; output[j+1] = (input[i] >> 8) & 0xff; output[j+2] = (input[i] >> 16) & 0xff; output[j+3] = (input[i] >> 24) & 0xff; } } ////////////////////////////// // apply MD5 algo on a block inline void MD5::transform(const uint1 block[blocksize]) { uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; decode (x, block, blocksize); /* Round 1 */ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; // Zeroize sensitive information. memset(x, 0, sizeof x); } ////////////////////////////// // MD5 block update operation. Continues an MD5 message-digest // operation, processing another message block inline void MD5::update(const unsigned char input[], size_type length) { // compute number of bytes mod 64 size_type index = count[0] / 8 % blocksize; // Update number of bits if ((count[0] += (length << 3)) < (length << 3)) count[1]++; count[1] += (length >> 29); // number of bytes we need to fill in buffer size_type firstpart = 64 - index; size_type i; // transform as many times as possible. if (length >= firstpart) { // fill buffer first, transform memcpy(&buffer[index], input, firstpart); transform(buffer); // transform chunks of blocksize (64 bytes) for (i = firstpart; i + blocksize <= length; i += blocksize) transform(&input[i]); index = 0; } else i = 0; // buffer remaining input memcpy(&buffer[index], &input[i], length-i); } ////////////////////////////// // for convenience provide a verson with signed char inline void MD5::update(const char input[], size_type length) { update((const unsigned char*)input, length); } ////////////////////////////// // MD5 finalization. Ends an MD5 message-digest operation, writing the // the message digest and zeroizing the context. inline MD5& MD5::finalize() { static unsigned char padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (!finalized) { // Save number of bits unsigned char bits[8]; encode(bits, count, 8); // pad out to 56 mod 64. size_type index = count[0] / 8 % 64; size_type padLen = (index < 56) ? (56 - index) : (120 - index); update(padding, padLen); // Append length (before padding) update(bits, 8); // Store state in digest encode(digest, state, 16); // Zeroize sensitive information. memset(buffer, 0, sizeof buffer); memset(count, 0, sizeof count); finalized=true; } return *this; } ////////////////////////////// // return hex representation of digest as string inline std::string MD5::hexdigest() const { if (!finalized) return ""; char buf[33]; for (int i=0; i<16; i++) sprintf(buf+i*2, "%02x", digest[i]); buf[32]=0; return std::string(buf); } ////////////////////////////// inline std::ostream& operator<<(std::ostream& out, MD5 md5) { return out << md5.hexdigest(); } ////////////////////////////// inline std::string md5(const std::string str) { MD5 md5 = MD5(str); return md5.hexdigest(); } #endif ================================================ FILE: rsyn/src/rsyn/util/MemoryUsage.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MEMORY_USAGE_H #define MEMORY_USAGE_H #ifdef __linux__ #include #include class MemoryUsage { public: // Retrieve memory usage in MB. static int getMemoryUsage() { struct rusage usage; int ret; ret = getrusage(RUSAGE_SELF, &usage); return usage.ru_maxrss / 1000; } // end method }; // end class #else class MemoryUsage { public: static int getMemoryUsage() { return 0; } }; // end class #endif #endif ================================================ FILE: rsyn/src/rsyn/util/Proxy.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_PROXY_H #define RSYN_PROXY_H namespace Rsyn { template class Proxy { friend struct std::hash>; protected: T * data; T *operator->() { return data; } const T *operator->() const { return data; } // For some reason the compiler allows ElementPointer to be silently casted // to int, which led to hard to find bugs. Now we explicitly tell the // compiler to not allow such conversion by making the cast operator // private. operator int() const; // not implemented // Returns the pointer to the data stored by this proxy. T *getData() { return data; } const T *getData() const { return data; } public: Proxy() : data(nullptr) {} Proxy(std::nullptr_t) : data(nullptr) {} Proxy(T * data) : data(data) {} bool operator!() const { return data == nullptr; }; operator bool() const { return data; } bool operator==(const Proxy &other) const { return data == other.data; } bool operator!=(const Proxy &other) const { return data != other.data; } // Used in map-like data structures. friend bool operator<(const Proxy &left, const Proxy &right) { // [IMPORTANT] We don't use the pointer (e) directly to avoid // non-determinism behavior. Note that the pointer address may change // from execution to execution and hence the mapping function may return // elements in different order leading to different results. return left.data->id < right.data->id; } // end method }; // end class } // end namespace namespace std { //! @brief Specialization of hash functor to allow Rsyn objects to be used //! in unordered collections. template struct hash> { size_t operator()(const Rsyn::Proxy &proxy) const { return hash()(proxy.data->id); } // end operator }; // end struct } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/util/RangeBasedLoop.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef UTIL_RANGEBASEDLOOP_H #define UTIL_RANGEBASEDLOOP_H //////////////////////////////////////////////////////////////////////////////// // Author: Guilherme Flach // Date: 2015-02-17 // // Description // ----------- // This class makes it easier to create range-based loops. // // How To Use It // ------------- // Create a class/struct with the following methods: // 1) Object current() {...} // 2) void next() {...} // 3) bool filter() {...} // 4) bool stop() {...} // // which the following meaning // // 1) returns the current object in the collection; // 2) moves to the next object in the collection; // 3) indicates if the current object should be filtered (i.e. not // processed), this class will call next() until filter() returns true // or the end of collection is reached; // 4) indicates if we reached the end of the collection. // // Example // ------- // Traverse only non-zero elements of a vector (i.e. filter out zeros): // // // This is the class the user (you) needs to provide to create a // // ranged-based loop. // class NonZeroElementsCollection { // private: // const std::vector &v; // std::size_t index; // public: // NonZeroElementsCollection(const std::vector &v) // : v(v), index(0) {} // // int current() {return v[index];} // void next() {index++;} // bool filter() {return current() == 0;} // bool stop() {return index >= v.size();} // }; // end class // // // Give it a nice name... // typedef Range allNonZeroElements; // // // Testing... // int main() { // std::vector v = {0, 1, 0, 2, 0, 3, 4, 0, 0, 0, 5}; // // for (int value : allNonZeroElements(v)) { // std::cout << value << " "; // } // end for // std::cout << "\n"; // // return 1; // } // end function // //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // According to the C++11 standard, the following range-loop statement // // for ( declaration : expression ) statement // // is equivalent to the the following statament // // { // auto&& __range = expression; // for (auto __begin = begin-expression, // __end = end-expression; // __begin != __end; // ++__begin // ) { // declaration = *__begin; // statement // } // } // // So that, we can override the operator != of an iterator to make it // return false whenever the stop condition was reached in the begin // iterator in code above. // // Source: http://en.cppreference.com/w/cpp/language/range-for //////////////////////////////////////////////////////////////////////////////// template class Range { private: Collection collection; struct RangeIterator { Collection *collection; RangeIterator() : collection(nullptr) {} RangeIterator(Collection &collection_) : collection(&collection_) { while (!collection->stop() && collection->filter()) { // stop must be first collection->next(); } // end while } // end constructor void operator++() { do { collection->next(); } while (!collection->stop() && collection->filter()); // stop must be first } // end method bool operator!=(const RangeIterator &) { return !collection->stop(); } // end method auto operator*() -> decltype(collection->current()) { return collection->current(); } // end method }; // end class public: Range(Collection &&collection) : collection(collection) {} RangeIterator begin() { return RangeIterator(collection); } RangeIterator end() { return RangeIterator(); /*dummy, not used */} }; // end class //////////////////////////////////////////////////////////////////////////////// // Traverse a collection backwards. //////////////////////////////////////////////////////////////////////////////// template class BackwardsCollection { private: const Collection &collection; public: explicit BackwardsCollection(const Collection &t) : collection(t) {} typename Collection::const_reverse_iterator begin() const { return collection.rbegin(); } typename Collection::const_reverse_iterator end() const { return collection.rend(); } }; // end class #endif ================================================ FILE: rsyn/src/rsyn/util/Stipple.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_STIPPLE_MASK_H #define RSYN_STIPPLE_MASK_H enum LineStippleMask : std::uint8_t { LINE_STIPPLE_NONE, LINE_STIPPLE_SOLID, LINE_STIPPLE_DASHED }; enum FillStippleMask : std::uint8_t { STIPPLE_MASK_EMPTY, STIPPLE_MASK_FILL, STIPPLE_MASK_YACIF1, STIPPLE_MASK_YACIF2, STIPPLE_MASK_YACIF3, STIPPLE_MASK_YACIF4, STIPPLE_MASK_YACIF5, STIPPLE_MASK_YACIF6, STIPPLE_MASK_CROSS, STIPPLE_MASK_HALFTONE, STIPPLE_MASK_CHESS, STIPPLE_MASK_DOT, STIPPLE_MASK_DIAGONAL_DOWN_1, STIPPLE_MASK_DIAGONAL_DOWN_2, STIPPLE_MASK_DIAGONAL_DOWN_3, STIPPLE_MASK_DIAGONAL_DOWN_4, STIPPLE_MASK_DIAGONAL_DOWN_5, STIPPLE_MASK_DIAGONAL_UP_1, STIPPLE_MASK_DIAGONAL_UP_2, STIPPLE_MASK_DIAGONAL_UP_3, STIPPLE_MASK_DIAGONAL_UP_4, STIPPLE_MASK_DIAGONAL_UP_5, STIPPLE_MASK_NUM_MASKS }; const unsigned char STIPPLE_MASKS[ STIPPLE_MASK_NUM_MASKS ][4*32] = { { // Empty 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // Fill, no stipple 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, { // Yacif Texture 1 192, 192, 192, 192, 64, 192, 192, 192, 12, 12, 12, 12, 12, 12, 12, 12, 192, 192, 192, 192, 192, 192, 192, 192, 12, 12, 12, 12, 12, 12, 12, 12, 192, 192, 192, 192, 192, 192, 192, 192, 12, 12, 12, 12, 12, 12, 12, 12, 192, 192, 192, 192, 192, 192, 192, 192, 12, 12, 12, 12, 12, 12, 12, 12, 192, 192, 192, 192, 192, 192, 192, 192, 12, 12, 12, 12, 12, 12, 12, 12, 192, 192, 192, 192, 192, 192, 192, 192, 12, 12, 12, 12, 12, 12, 12, 12, 192, 192, 192, 192, 192, 192, 192, 192, 12, 12, 12, 12, 12, 12, 12, 12, 192, 192, 192, 192, 192, 192, 192, 192, 12, 12, 12, 12, 12, 12, 12, 12 }, { // Yacif Texture 2 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 240, 0, 0, 15, 240, 0, 0, 15, 240, 0, 0, 15, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 255, 255, 15, 15, 255, 255, 15, 15, 255, 255, 15, 15, 255, 255, 15, 15, 255, 255, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 0 }, { // Yacif Texture 3 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0, 123, 0 }, { // Yacif Texture 4 (not implemented yet) 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { // Yacif Texture 5 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 15, 255, 240, 255, 15, 255, 240, 255, 15, 255, 240, 255, 15, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 15, 255, 240, 255, 15, 255, 240, 255, 15, 255, 240, 255, 15, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 15, 255, 240, 255, 15, 255, 240, 255, 15, 255, 240, 255, 15, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 15, 255, 240, 255, 15, 255, 240, 255, 15, 255, 240, 255, 15, 255, 240 }, { // Yacif Texture 6 0, 0, 255, 240, 0, 0, 255, 240, 0, 0, 255, 240, 0, 0, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // Cross 85, 85, 85, 85, 238, 238, 238, 238, 85, 85, 85, 85, 187, 187, 187, 187, 85, 85, 85, 85, 238, 238, 238, 238, 85, 85, 85, 85, 187, 187, 187, 187, 85, 85, 85, 85, 238, 238, 238, 238, 85, 85, 85, 85, 187, 187, 187, 187, 85, 85, 85, 85, 238, 238, 238, 238, 85, 85, 85, 85, 187, 187, 187, 187, 85, 85, 85, 85, 238, 238, 238, 238, 85, 85, 85, 85, 187, 187, 187, 187, 85, 85, 85, 85, 238, 238, 238, 238, 85, 85, 85, 85, 187, 187, 187, 187, 85, 85, 85, 85, 238, 238, 238, 238, 85, 85, 85, 85, 187, 187, 187, 187, 85, 85, 85, 85, 238, 238, 238, 238, 85, 85, 85, 85, 187, 187, 187, 187 }, { // Halftone 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170 }, { // Chess 153, 153, 153, 153, 153, 153, 153, 153, 102, 102, 102, 102, 102, 102, 102, 102, 153, 153, 153, 153, 153, 153, 153, 153, 102, 102, 102, 102, 102, 102, 102, 102, 153, 153, 153, 153, 153, 153, 153, 153, 102, 102, 102, 102, 102, 102, 102, 102, 153, 153, 153, 153, 153, 153, 153, 153, 102, 102, 102, 102, 102, 102, 102, 102, 153, 153, 153, 153, 153, 153, 153, 153, 102, 102, 102, 102, 102, 102, 102, 102, 153, 153, 153, 153, 153, 153, 153, 153, 102, 102, 102, 102, 102, 102, 102, 102, 153, 153, 153, 153, 153, 153, 153, 153, 102, 102, 102, 102, 102, 102, 102, 102, 153, 153, 153, 153, 153, 153, 153, 153, 102, 102, 102, 102, 102, 102, 102, 102 }, { // dot 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 0, 0, 68, 68, 68, 68, 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 0, 0, 68, 68, 68, 68, 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 0, 0, 68, 68, 68, 68, 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 0, 0, 68, 68, 68, 68, 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 0, 0, 68, 68, 68, 68, 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 0, 0, 68, 68, 68, 68, 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 0, 0, 68, 68, 68, 68, 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 0, 0, 68, 68, 68, 68 }, { // Diagonal Down 1 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170 }, { // Diagonal Down 2 34, 34, 34, 34, 17, 17, 17, 17, 136, 136, 136, 136, 68, 68, 68, 68, 34, 34, 34, 34, 17, 17, 17, 17, 136, 136, 136, 136, 68, 68, 68, 68, 34, 34, 34, 34, 17, 17, 17, 17, 136, 136, 136, 136, 68, 68, 68, 68, 34, 34, 34, 34, 17, 17, 17, 17, 136, 136, 136, 136, 68, 68, 68, 68, 34, 34, 34, 34, 17, 17, 17, 17, 136, 136, 136, 136, 68, 68, 68, 68, 34, 34, 34, 34, 17, 17, 17, 17, 136, 136, 136, 136, 68, 68, 68, 68, 34, 34, 34, 34, 17, 17, 17, 17, 136, 136, 136, 136, 68, 68, 68, 68, 34, 34, 34, 34, 17, 17, 17, 17, 136, 136, 136, 136, 68, 68, 68, 68 }, { // Diagonal Down 3 8, 8, 8, 8, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 128, 128, 128, 128, 64, 64, 64, 64, 32, 32, 32, 32, 16, 16, 16, 16 }, { // Diagonal Down 4 0, 128, 0, 128, 0, 64, 0, 64, 0, 32, 0, 32, 0, 16, 0, 16, 0, 8, 0, 8, 0, 4, 0, 4, 0, 2, 0, 2, 0, 1, 0, 1, 128, 0, 128, 0, 64, 0, 64, 0, 32, 0, 32, 0, 16, 0, 16, 0, 8, 0, 8, 0, 4, 0, 4, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, 128, 0, 128, 0, 64, 0, 64, 0, 32, 0, 32, 0, 16, 0, 16, 0, 8, 0, 8, 0, 4, 0, 4, 0, 2, 0, 2, 0, 1, 0, 1, 128, 0, 128, 0, 64, 0, 64, 0, 32, 0, 32, 0, 16, 0, 16, 0, 8, 0, 8, 0, 4, 0, 4, 0, 2, 0, 2, 0, 1, 0, 1, 0 }, { // Diagonal Down 5 0, 0, 128, 0, 0, 0, 64, 0, 0, 0, 32, 0, 0, 0, 16, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 128, 0, 0, 0, 64, 0, 0, 0, 32, 0, 0, 0, 16, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 1, 128, 0, 0, 0, 64, 0, 0, 0, 32, 0, 0, 0, 16, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 128, 0, 0, 0, 64, 0, 0, 0, 32, 0, 0, 0, 16, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0 }, { // Diagonal Up 1 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85, 170, 170, 170, 170, 85, 85, 85, 85 }, { // Diagonal Up 2 68, 68, 68, 68, 136, 136, 136, 136, 17, 17, 17, 17, 34, 34, 34, 34, 68, 68, 68, 68, 136, 136, 136, 136, 17, 17, 17, 17, 34, 34, 34, 34, 68, 68, 68, 68, 136, 136, 136, 136, 17, 17, 17, 17, 34, 34, 34, 34, 68, 68, 68, 68, 136, 136, 136, 136, 17, 17, 17, 17, 34, 34, 34, 34, 68, 68, 68, 68, 136, 136, 136, 136, 17, 17, 17, 17, 34, 34, 34, 34, 68, 68, 68, 68, 136, 136, 136, 136, 17, 17, 17, 17, 34, 34, 34, 34, 68, 68, 68, 68, 136, 136, 136, 136, 17, 17, 17, 17, 34, 34, 34, 34, 68, 68, 68, 68, 136, 136, 136, 136, 17, 17, 17, 17, 34, 34, 34, 34 }, { // Diagonal Up 3 16, 16, 16, 16, 32, 32, 32, 32, 64, 64, 64, 64, 128, 128, 128, 128, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 8, 8, 8, 8, 16, 16, 16, 16, 32, 32, 32, 32, 64, 64, 64, 64, 128, 128, 128, 128, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 8, 8, 8, 8, 16, 16, 16, 16, 32, 32, 32, 32, 64, 64, 64, 64, 128, 128, 128, 128, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 8, 8, 8, 8, 16, 16, 16, 16, 32, 32, 32, 32, 64, 64, 64, 64, 128, 128, 128, 128, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 8, 8, 8, 8 }, { // Diagonal Up 4 1, 0, 1, 0, 2, 0, 2, 0, 4, 0, 4, 0, 8, 0, 8, 0, 16, 0, 16, 0, 32, 0, 32, 0, 64, 0, 64, 0, 128, 0, 128, 0, 0, 1, 0, 1, 0, 2, 0, 2, 0, 4, 0, 4, 0, 8, 0, 8, 0, 16, 0, 16, 0, 32, 0, 32, 0, 64, 0, 64, 0, 128, 0, 128, 1, 0, 1, 0, 2, 0, 2, 0, 4, 0, 4, 0, 8, 0, 8, 0, 16, 0, 16, 0, 32, 0, 32, 0, 64, 0, 64, 0, 128, 0, 128, 0, 0, 1, 0, 1, 0, 2, 0, 2, 0, 4, 0, 4, 0, 8, 0, 8, 0, 16, 0, 16, 0, 32, 0, 32, 0, 64, 0, 64, 0, 128, 0, 128 }, { // Diagonal Up 5 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 64, 0, 0, 0, 128, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 64, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 64, 0, 0, 0, 128, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 16, 0, 0, 0, 32, 0, 0, 0, 64, 0, 0, 0, 128, 0 } }; #endif ================================================ FILE: rsyn/src/rsyn/util/Stopwatch.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef STOPWATCH_H #define STOPWATCH_H // UFRGS - Guilherme Flach // This class was based on http://pocoproject.org/. #if _WIN32 #include #include #else #include #include #include #include #endif #include #include using std::ostringstream; #include using std::string; #include using std::setfill; using std::setw; class Stopwatch { private: #if _WIN32 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 #else #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL #endif struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; inline int gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ft; unsigned __int64 tmpres = 0; static int tzflag; if (NULL != tv) { GetSystemTimeAsFileTime(&ft); tmpres |= ft.dwHighDateTime; tmpres <<= 32; tmpres |= ft.dwLowDateTime; /*converting file time to unix epoch*/ tmpres -= DELTA_EPOCH_IN_MICROSECS; tmpres /= 10; /*convert into microseconds*/ tv->tv_sec = (long)(tmpres / 1000000UL); tv->tv_usec = (long)(tmpres % 1000000UL); } if (NULL != tz) { if (!tzflag) { _tzset(); tzflag++; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } // end function #endif bool clsRunning; double clsElapsedTime; timeval clsCheckpoint; void update() { gettimeofday( &clsCheckpoint, NULL ); } // end method double computeElapsedTimeWithRespectToCurrentTime() const { timeval t; gettimeofday( &t, NULL ); return ( t.tv_sec - clsCheckpoint.tv_sec ) + ( t.tv_usec - clsCheckpoint.tv_usec )/1000000.0; } // end method public: Stopwatch() { reset(); } void reset() { clsElapsedTime = 0; clsRunning = false; } // end method void start() { clsRunning = true; update(); } // end method void restart() { reset(); start(); } // end method void stop() { clsRunning = false; clsElapsedTime += computeElapsedTimeWithRespectToCurrentTime(); } // end method double getElapsedTime() const { if ( clsRunning ) return computeElapsedTimeWithRespectToCurrentTime(); else return clsElapsedTime; } // end method string getFormattedTime() const { const double hours = getElapsedTime()/(60*60); const double minutes = (hours - floor(hours)) * 60; const double seconds = (minutes - floor(minutes)) * 60; const int hh = (int) hours; const int mm = (int) minutes; const int ss = (int) seconds; ostringstream oss; oss << setfill('0') << hh << ":" << setw(2) << mm << ":" << setw(2) << ss; return oss.str(); } // end method bool isRunning() const { return clsRunning; } }; // end class // ----------------------------------------------------------------------------- class StopwatchGuard { private: Stopwatch &clsStopwatch; public: StopwatchGuard(Stopwatch &stopwatch) : clsStopwatch(stopwatch) {clsStopwatch.start(); } ~StopwatchGuard() { clsStopwatch.stop(); } }; // end class #endif ================================================ FILE: rsyn/src/rsyn/util/String.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef UTIL_STRING_H #define UTIL_STRING_H #include #include #include #include class String { public: template< typename T > static bool parse(const std::string &str, T &data) { std::istringstream iss( str ); iss >> data; return !iss.fail(); } // end function static bool parse(const std::string &str, std::string &data) { return (data=str, true); } // end function static void printCentered(std::ostream &out, const std::string &text, const int width = 80) { // DOES NOT WORKS WHEN TEXT HAS \t const int start = (width - text.size()) / 2; if ( start > 0 ) out << std::setw(start) << std::setfill( ' ' ) << ' '; out << text; } // end function }; // end class #endif ================================================ FILE: rsyn/src/rsyn/util/ThreadPool.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef UTIL_THREAD_POOL_H #define UTIL_THREAD_POOL_H //////////////////////////////////////////////////////////////////////////////// // Guilherme Flach: 2012-02-24 // // This code was an adaptation from // https://github.com/progschj/ThreadPool/ // // The main change I did was to make to task not required to return a // std::future and added a method to wait for all threads to finish. Note that // with std::future one did not need a wait method. But this was weird when the // task should not return anything (i.e. void). //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Example //////////////////////////////////////////////////////////////////////////////// // // ThreadPool pool; // for (int i = 0; i < 10; ++i) { // pool.addTask([i] { // std::cout << "hello " << i << std::endl; // std::this_thread::sleep_for(std::chrono::seconds(1)); // std::cout << "world " << i << std::endl; // }); // } // end for // // pool.wait(); // wait for all tasks to be finished // //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include class ThreadPool { public: // Start the thread pool with the number of available threads in the // computer (using std::thread::hardware_concurrency()). If it fails to // query the number of threads, the thread pool is initialized with 2 // threads ThreadPool(); // Start the thread pool with the specified number of threads. ThreadPool(const std::size_t numThreads); // Add a task. template void addTask(F&& f, Args&&... args); // Wait for all threads to finish. void wait(); // Get the number of working threads. std::size_t getNumThreads() const { return workers.size(); } // Stop all threads. ~ThreadPool(); private: // need to keep track of threads so we can join them std::vector workers; // the task queue std::queue> tasks; // synchronization std::mutex queue_mutex; std::condition_variable condition; std::condition_variable condition_wait_task; bool stop; std::atomic running; // Manage workers. void startWorkers(const std::size_t numThreads); void stopWorkers(); }; // end class // ----------------------------------------------------------------------------- inline ThreadPool::ThreadPool(const std::size_t numThreads) { startWorkers(numThreads); } // end method // ----------------------------------------------------------------------------- inline ThreadPool::ThreadPool() { startWorkers(std::max(2u, std::thread::hardware_concurrency())); } // end method // ----------------------------------------------------------------------------- inline void ThreadPool::startWorkers(const std::size_t numThreads) { stop = false; running = 0; for (std::size_t i = 0; i < numThreads; i++) { workers.emplace_back([this] { while (true) { std::function task; { // mutual exclusion block std::unique_lock lock(queue_mutex); condition.wait(lock, [this] {return stop || !tasks.empty();}); if (stop && tasks.empty()) return; task = std::move(tasks.front()); tasks.pop(); } // end block running++; task(); running--; condition_wait_task.notify_one(); } // end while }); } // end method } // end method // ----------------------------------------------------------------------------- inline void ThreadPool::stopWorkers() { { // mutual exclusion block std::unique_lock lock(queue_mutex); stop = true; } // end block condition.notify_all(); for (std::thread &worker : workers) { worker.join(); } // end for } // end method // ----------------------------------------------------------------------------- template void ThreadPool::addTask(F&& f, Args&&... args) { auto task = std::make_shared>( std::bind(std::forward(f), std::forward(args)...)); { // mutual exclusion block std::unique_lock lock(queue_mutex); // don't allow enqueueing after stopping the pool if (stop) { throw std::runtime_error("Adding a task on a stopped ThreadPool."); } // end if tasks.emplace([task](){(*task)();}); } // end block condition.notify_one(); } // end method // ----------------------------------------------------------------------------- inline void ThreadPool::wait() { std::unique_lock lock(queue_mutex); condition_wait_task.wait(lock, [this] {return running == 0;}); } // end method // ----------------------------------------------------------------------------- inline ThreadPool::~ThreadPool() { stopWorkers(); } // end destructor #endif ================================================ FILE: rsyn/src/rsyn/util/TristateFlag.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_TRISTATE_FLAG_H #define RSYN_TRISTATE_FLAG_H namespace Rsyn { class TristateFlag { private: bool specified : 1; bool flag : 1; public: TristateFlag() : specified(false), flag(false) {} TristateFlag(const bool value) : specified(true), flag(value) {} bool get() const { return flag; } // end method void set(const bool value) { specified = true; flag = value; } // end method void clear() { specified = false; flag = false; } // end method bool isSpecified() const { return specified; } // end method bool isNotSpecified() const { return !specified; } // end method operator bool() const { return get(); } // end method }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/util/Units.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_INTERNAL_UNITS_H #define RSYN_INTERNAL_UNITS_H #include #include namespace Rsyn { enum Measure { MEASURE_INVALID = -1, MEASURE_POWER, // mW MEASURE_CURRENT, // mA MEASURE_CAPACITANCE, // fF MEASURE_RESISTANCE, // kOhm MEASURE_TIME, // ps Note: Time(ps) = Resistance(kOhm) * Capacitance(fF) MEASURE_DISTANCE, // dbu Note: no prefix, not measured in meters MEASURE_VOLTAGE, // V Note: no prefix NUM_MEASURES }; // end enum enum UnitPrefix { YOCTO = -24, ZEPTO = -21, ATTO = -18, FEMTO = -15, PICO = -12, NANO = -9, MICRO = -6, MILLI = -3, CENTI = -2, DECI = -1, NO_UNIT_PREFIX = 0, DEKA = 1, HECTO = 2, KILO = 3, MEGA = 6, GIGA = 9, TERA = 12, PETA = 15, EXA = 18, ZETTA = 21, YOTTA = 24 }; // end enum class Units { public: static UnitPrefix getInternalUnitPrefix(const Measure measure) { switch (measure) { case MEASURE_POWER: return MILLI; case MEASURE_CURRENT: return MILLI; case MEASURE_CAPACITANCE: return FEMTO; case MEASURE_RESISTANCE: return KILO; case MEASURE_TIME: return PICO; case MEASURE_DISTANCE: return NO_UNIT_PREFIX; case MEASURE_VOLTAGE: return NO_UNIT_PREFIX; default: assert(false); } // end switch return NO_UNIT_PREFIX; // just for warning sake } // end method static std::string getMeasureSymbol(const Measure measure) { switch (measure) { case MEASURE_POWER: return "W"; case MEASURE_CAPACITANCE: return "C"; case MEASURE_CURRENT: return "A"; case MEASURE_RESISTANCE: return "Ohm"; case MEASURE_TIME: return "s"; case MEASURE_DISTANCE: return "dbu"; case MEASURE_VOLTAGE: return "V"; default: assert(false); } // end switch return ""; // just for warning sake } // end method static std::string getUnitPrefixSymbol(const UnitPrefix prefix) { switch (prefix) { case YOCTO : return "y"; case ZEPTO : return "z"; case ATTO : return "a"; case FEMTO : return "f"; case PICO : return "p"; case NANO : return "n"; case MICRO : return "u"; case MILLI : return "m"; case CENTI : return "c"; case DECI : return "d"; case NO_UNIT_PREFIX : return ""; case DEKA : return "da"; case HECTO : return "h"; case KILO : return "k"; case MEGA : return "M"; case GIGA : return "G"; case TERA : return "T"; case PETA : return "P"; case EXA : return "E"; case ZETTA : return "Z"; case YOTTA : return "Y"; default : assert(false); } // end switch return ""; // just for warning sake } // end method //! @brief Returns the default unit string given a measure. For instance, //! return "fC" for capacitance and "mW" for power. static std::string getDefaultInternalUnitString(const Measure measure) { return getUnitPrefixSymbol(getInternalUnitPrefix(measure)) + getMeasureSymbol(measure); } // end method static double convertUnits( const double sourceValue, const UnitPrefix sourceUnitPrefix, const UnitPrefix targetUnitPrefix) { return sourceValue * std::pow(10, sourceUnitPrefix - targetUnitPrefix); } // end method static double convertToInternalUnits( const Measure measure, const double sourceValue, const UnitPrefix sourceUnitPrefix) { const UnitPrefix targetUnitPrefix = getInternalUnitPrefix(measure); return convertUnits(sourceValue, sourceUnitPrefix, targetUnitPrefix); } // end method static double convertFromInternalUnits( const Measure measure, const double sourceValue, const UnitPrefix targetUnitPrefix) { const UnitPrefix sourceUnitPrefix = getInternalUnitPrefix(measure); return convertUnits(sourceValue, sourceUnitPrefix, targetUnitPrefix); } // end method }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/util/dbu.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_DBU_H #define RSYN_DBU_H #include #include #include using std::max; using std::min; #include using std::ostream; #include "dim.h" // ----------------------------------------------------------------------------- typedef std::int64_t DBU; typedef double FloatingPointDBU; // ----------------------------------------------------------------------------- #define MAKE_SELF_OPERATOR( OP ) \ inline void operator OP ( const DBUxy right ) { x OP right.x; y OP right.y; } #define MAKE_OPERATOR( OP ) \ inline DBUxy operator OP ( const DBUxy v0, const DBUxy v1 ) { \ return DBUxy( v0.x OP v1.x, v0.y OP v1.y ); \ } #define MAKE_FUNCTION_1( FUNC ) \ inline DBUxy FUNC ( const DBUxy v ) { \ return DBUxy( FUNC (v.x), FUNC (v.y) ); \ } #define MAKE_FUNCTION_2( FUNC ) \ inline DBUxy FUNC ( const DBUxy v0, const DBUxy v1 ) { \ return DBUxy( FUNC (v0.x, v1.x), FUNC (v0.y, v1.y) ); \ } struct DBUxy { friend ostream &operator<<( ostream &out, const DBUxy &v ) { return out << "(" << v.x << ", " << v.y << ")"; } // end function union { struct { DBU x, y; }; DBU xy[2]; }; // Construtctors. DBUxy(): x(0), y(0) {} DBUxy( const DBU x, const DBU y ) : x(x), y(y) {} explicit DBUxy( const DBU scalar ) : x(scalar), y(scalar) {} // explicit to avoid accidentally assigning to scalar // Operators. MAKE_SELF_OPERATOR( += ); MAKE_SELF_OPERATOR( -= ); MAKE_SELF_OPERATOR( *= ); MAKE_SELF_OPERATOR( /= ); MAKE_SELF_OPERATOR( = ); inline const bool operator == ( const DBUxy v ) const { return x == v.x && y == v.y; } // end method inline const bool operator != ( const DBUxy v ) const { return x != v.x || y != v.y; } // end method inline void operator *= ( const FloatingPointDBU scalar) { x = (DBU) (x * scalar); y = (DBU) (y * scalar); } // end method inline void operator /= ( const FloatingPointDBU scalar) { x = (DBU) (x / scalar); y = (DBU) (y / scalar); } // end method DBU &operator[](const int dimension) { return xy[dimension]; } const DBU &operator[](const int dimension) const { return xy[dimension]; } // Methods. FloatingPointDBU norm() const { return std::sqrt( x*x + y*y ); } // end method DBUxy normalized() const { const FloatingPointDBU v = norm(); return DBUxy( (DBU) (x/v), (DBU) (y/v) ); } // end method DBUxy safeNormalized() const { const FloatingPointDBU v = norm(); if ( v == 0.0 ) return DBUxy(0,0); else return DBUxy( (DBU) (x/v), (DBU) (y/v) ); } // end method void apply(const DBU scalar) { x = scalar; y = scalar; } // end method void set(const DBU x, const DBU y ) { this->x = x; this->y = y; } // end method void scale(const FloatingPointDBU xScaling, const FloatingPointDBU yScaling){ x = (DBU) (x*xScaling); y = (DBU) (y*yScaling); } // end method void scale(const FloatingPointDBU scaling){ x = (DBU) (x*scaling); y = (DBU) (y*scaling); } // end method DBU aggregated() const { return x + y; } // end method void abs() { x = std::abs(x); y = std::abs(y); } // end method void clear () { x = 0; y = 0; } // end method static DBU computeManhattanDistance(const DBUxy p0, const DBUxy p1) { return std::abs(p0.x - p1.x) + std::abs(p0.y - p1.y); } // end method }; // end struct MAKE_OPERATOR( + ); MAKE_OPERATOR( - ); MAKE_OPERATOR( * ); MAKE_OPERATOR( / ); // Guilherme Flach - 2017/03/18 // These template functions were added to resolve ambiguity related to trying to // cast int to DBU (aka std::int64_t) or FloatingPointDBU (aka double). template DBUxy operator*( const T scalar, const DBUxy v ) { static_assert(std::is_arithmetic::value, "Arithmetic value required."); static_assert(std::is_integral::value || std::is_floating_point::value, "Integer or floating point required."); // Cast must be performed after the multiplication to avoid wrong results // when the scaling factor is in the (0, 1) range. return DBUxy( (DBU) (v.x * scalar), (DBU) (v.y * scalar) ); } // end method template DBUxy operator*( const DBUxy v, const T scalar ) { return scalar*v; } // end method template DBUxy operator/( const T scalar, const DBUxy v ) { static_assert(std::is_arithmetic::value, "Arithmetic value required."); static_assert(std::is_integral::value || std::is_floating_point::value, "Integer or floating point required."); // Cast must be performed after the division to avoid wrong results // when the scaling factor is in the (0, 1) range. return DBUxy( (DBU) (v.x / scalar), (DBU) (v.y / scalar) ); } // end method template DBUxy operator/( const DBUxy v, const T scalar ) { return scalar/v; } // end method MAKE_FUNCTION_2(max); MAKE_FUNCTION_2(min); // Unary operators. inline DBUxy operator-( const DBUxy value ) { return DBUxy( -value.x, -value.y ); } // end operator inline DBUxy operator+( const DBUxy value ) { return DBUxy( +value.x, +value.y ); } // end operator // ----------------------------------------------------------------------------- // TODO: Move to a better place... template inline T roundedUpIntegralDivision(const T numerator, const T denominator) { static_assert(std::is_integral::value, "Integer required."); return numerator / denominator + (numerator % denominator? 1 : 0); } // end function // ----------------------------------------------------------------------------- #undef MAKE_OPERATOR #undef MAKE_OPERATOR_SCALAR #undef MAKE_SELF_OPERATOR #undef MAKE_SELF_OPERATOR_SCALAR #undef MAKE_FUNCTION_1 #undef MAKE_FUNCTION_2 #endif ================================================ FILE: rsyn/src/rsyn/util/dim.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_DIM_H #define RSYN_DIM_H #include // ----------------------------------------------------------------------------- // [NOTE] Although this class use indexing for accessing data members, most of // time the indexing can be resolved in compiling time so that there's // no overhead. When it's not possible to do so, by using indexing an // "if" is likely to be avoided which is good for code optimization since // it prevents the pipeline to be flushed. // ----------------------------------------------------------------------------- enum Dimension { X = 0, Y = 1 }; // end enum inline std::string getDimension(const Dimension dim ) { switch(dim) { case X : return "X"; case Y : return "Y"; default : return "?"; } // end switch } // end method const Dimension REVERSE_DIMENSION[2] = {Y,X}; #define for_each_dimension(variable) for ( int variable = 0; variable < 2; variable++ ) // ----------------------------------------------------------------------------- enum Boundary { LOWER = 0, UPPER = 1, INNER = 2, OUTER = 3 }; // end enum #define for_each_boundary(variable) for ( int variable = 0; variable < 2; variable++ ) #endif /* DIM_H */ ================================================ FILE: rsyn/src/rsyn/util/double2.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_DOUBLE2_H #define RSYN_DOUBLE2_H #include #include using std::max; using std::min; #include using std::ostream; #include using std::vector; #include "dim.h" #include "dbu.h" #include "FloatingPoint.h" // ----------------------------------------------------------------------------- #define MAKE_SELF_OPERATOR( OP ) \ inline void operator OP ( const double2 right ) { x OP right.x; y OP right.y; } #define MAKE_SELF_OPERATOR_SCALAR( OP ) \ inline void operator OP ( const double right ) { x OP right; y OP right; } #define MAKE_OPERATOR( OP ) \ inline double2 operator OP ( const double2 v0, const double2 v1 ) { \ return double2( v0.x OP v1.x, v0.y OP v1.y ); \ } #define MAKE_OPERATOR_SCALAR( OP ) \ inline double2 operator OP ( const double scalar, const double2 v ) { \ return double2( v.x OP scalar, v.y OP scalar ); \ } \ inline double2 operator OP ( const double2 v, const double scalar ) { \ return double2( v.x OP scalar, v.y OP scalar ); \ } #define MAKE_FUNCTION_1( FUNC ) \ inline double2 FUNC ( const double2 v ) { \ return double2( FUNC (v.x), FUNC (v.y) ); \ } #define MAKE_FUNCTION_2( FUNC ) \ inline double2 FUNC ( const double2 v0, const double2 v1 ) { \ return double2( FUNC (v0.x, v1.x), FUNC (v0.y, v1.y) ); \ } struct double2 { friend ostream &operator<<( ostream &out, const double2 &v ) { return out << "(" << v.x << ", " << v.y << ")"; } // end function union { struct { double x, y; }; double xy[2]; }; // Construtctors. double2(): x(0.0), y(0.0) {} double2( const double x, const double y ) : x(x), y(y) {} explicit double2( const DBUxy &xy ) : x(xy.x), y(xy.y) {} explicit double2( const double scalar ) : x(scalar), y(scalar) {} // explicit to avoid accidentally assigning to scalar DBUxy scaleAndConvertToDbu(const double scale, const RoundingStrategy roundingStrategy = ROUND_DOWN) const { return DBUxy( (DBU) FloatingPoint::round(x*scale, roundingStrategy), (DBU) FloatingPoint::round(y*scale, roundingStrategy)); } // end method DBUxy convertToDbu(const RoundingStrategy roundingStrategy = ROUND_DOWN) const { return DBUxy( (DBU) FloatingPoint::round(x, roundingStrategy), (DBU) FloatingPoint::round(y, roundingStrategy)); } // end method // Operators. MAKE_SELF_OPERATOR( += ); MAKE_SELF_OPERATOR( -= ); MAKE_SELF_OPERATOR( *= ); MAKE_SELF_OPERATOR( /= ); MAKE_SELF_OPERATOR( = ); inline const bool operator == ( const double2 v ) const { return x == v.x && y == v.y; } // end method inline const bool operator != ( const double2 v ) const { return x != v.x || y != v.y; } // end method MAKE_SELF_OPERATOR_SCALAR( *= ); MAKE_SELF_OPERATOR_SCALAR( /= ); double &operator[](const int dimension) { return xy[dimension]; } const double &operator[](const int dimension) const { return xy[dimension]; } // Methods. double norm() const { return sqrt( x*x + y*y ); } // end method double2 normalized() const { const double v = norm(); return double2( x/v, y/v ); } // end method double2 safeNormalized() const { const double v = norm(); if ( v == 0.0 ) return double2(0,0); else return double2( x/v, y/v ); } // end method void apply(const double scalar) { x = scalar; y = scalar; } // end method void set( const double x, const double y ) { this->x = x; this->y = y; } // end method void scale(const double numb){ x = x*numb; y = y*numb; } // end method double aggregated() const { return x + y; } // end method void abs () { x = std::abs(x); y = std::abs(y); } // end method void clear () { x = 0; y = 0; } // end method inline bool approximatelyEqual(const double2 other, const double precision = 1e-6) const; }; // end struct MAKE_OPERATOR( + ); MAKE_OPERATOR( - ); MAKE_OPERATOR( * ); MAKE_OPERATOR( / ); MAKE_OPERATOR_SCALAR( * ); MAKE_OPERATOR_SCALAR( / ); MAKE_FUNCTION_2(max); MAKE_FUNCTION_2(min); MAKE_FUNCTION_1(sqrt); // Unary operators. inline double2 operator-( const double2 value ) { return double2( -value.x, -value.y ); } // end operator inline double2 operator+( const double2 value ) { return double2( +value.x, +value.y ); } // end operator // Element-wise power. inline double2 pow( const double2 base, const double exp ) { return double2( pow( base.x, exp ), pow( base.y, exp ) ); } // end function // ----------------------------------------------------------------------------- inline bool double2::approximatelyEqual(const double2 other, const double precision) const { return (*this - other).norm() <= precision; } // end method // ----------------------------------------------------------------------------- // The split vector class emulates in some extent a vector. However // x and y values are stored in two separated arrays (vector). When // accessing elements through [] operator, the split vector class creates a // special reference to double2 which allows seamlessly operation with double2 // variables. But, as x and y are split, the split vector class keeps // compatibility with frameworks which do not support double2 (e.g. linear // algebra ones). // @note Deprecated... class double2_split_vector { public: struct double2_ref { double &x; double &y; double2_ref( double &x, double &y ) : x(x), y(y) {} MAKE_SELF_OPERATOR( += ); MAKE_SELF_OPERATOR( -= ); MAKE_SELF_OPERATOR( *= ); MAKE_SELF_OPERATOR( /= ); MAKE_SELF_OPERATOR( = ); double &operator[](const int dimension) { return (dimension==X)? x : ( (dimension==Y)? y : *((double *)NULL) ); } const double &operator[](const int dimension) const { return (dimension==X)? x : ( (dimension==Y)? y : *((double *)NULL) ); } // Returns a const double2 to avoid accidentally trying to assign to a // temporary. operator const double2() const { return double2(x,y); } }; // end struct vector xy[2]; const double2 operator[](const int index) const { return double2(xy[0][index],xy[1][index]); } double2_ref operator[](const int index) { return double2_ref(xy[0][index],xy[1][index]); } void resize(size_t size) { xy[0].resize(size); xy[1].resize(size); } void resize(size_t size, double2 val) { xy[0].resize(size, val.x); xy[1].resize(size, val.y); } void assign(size_t n, double2 val ) { xy[0].assign(n, val.x); xy[1].assign(n, val.y); } void clear() { xy[0].clear(); xy[1].clear(); } size_t size() const { return xy[0].size(); } }; // end class // ----------------------------------------------------------------------------- #undef MAKE_OPERATOR #undef MAKE_OPERATOR_SCALAR #undef MAKE_SELF_OPERATOR #undef MAKE_SELF_OPERATOR_SCALAR #undef MAKE_FUNCTION_1 #undef MAKE_FUNCTION_2 #endif ================================================ FILE: rsyn/src/rsyn/util/float2.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_FLOAT2_H #define RSYN_FLOAT2_H #include #include using std::max; using std::min; #include using std::ostream; #include using std::vector; #include "dim.h" #include "dbu.h" #include "FloatingPoint.h" // ----------------------------------------------------------------------------- #define MAKE_SELF_OPERATOR( OP ) \ inline void operator OP ( const float2 right ) { x OP right.x; y OP right.y; } #define MAKE_SELF_OPERATOR_SCALAR( OP ) \ inline void operator OP ( const float right ) { x OP right; y OP right; } #define MAKE_OPERATOR( OP ) \ inline float2 operator OP ( const float2 v0, const float2 v1 ) { \ return float2( v0.x OP v1.x, v0.y OP v1.y ); \ } #define MAKE_OPERATOR_SCALAR( OP ) \ inline float2 operator OP ( const float scalar, const float2 v ) { \ return float2( v.x OP scalar, v.y OP scalar ); \ } \ inline float2 operator OP ( const float2 v, const float scalar ) { \ return float2( v.x OP scalar, v.y OP scalar ); \ } #define MAKE_FUNCTION_1( FUNC ) \ inline float2 FUNC ( const float2 v ) { \ return float2( std::FUNC (v.x), std::FUNC (v.y) ); \ } #define MAKE_FUNCTION_2( FUNC ) \ inline float2 FUNC ( const float2 v0, const float2 v1 ) { \ return float2( std::FUNC (v0.x, v1.x), std::FUNC (v0.y, v1.y) ); \ } struct float2 { friend ostream &operator<<( ostream &out, const float2 &v ) { return out << "(" << v.x << ", " << v.y << ")"; } // end function union { struct { float x, y; }; float xy[2]; }; // Construtctors. float2(): x(0), y(0) {} float2( const float x, const float y ) : x(x), y(y) {} explicit float2( const DBUxy &xy ) : x(xy.x), y(xy.y) {} explicit float2( const float scalar ) : x(scalar), y(scalar) {} // explicit to avoid accidentally assigning to scalar DBUxy scaleAndConvertToDbu(const float scale, const RoundingStrategy roundingStrategy = ROUND_DOWN) const { return DBUxy( (DBU) FloatingPoint::round(x*scale, roundingStrategy), (DBU) FloatingPoint::round(y*scale, roundingStrategy)); } // end method DBUxy convertToDbu(const RoundingStrategy roundingStrategy = ROUND_DOWN) const { return DBUxy( (DBU) FloatingPoint::round(x, roundingStrategy), (DBU) FloatingPoint::round(y, roundingStrategy)); } // end method // Operators. MAKE_SELF_OPERATOR( += ); MAKE_SELF_OPERATOR( -= ); MAKE_SELF_OPERATOR( *= ); MAKE_SELF_OPERATOR( /= ); MAKE_SELF_OPERATOR( = ); inline const bool operator == ( const float2 v ) const { return x == v.x && y == v.y; } // end method inline const bool operator != ( const float2 v ) const { return x != v.x || y != v.y; } // end method MAKE_SELF_OPERATOR_SCALAR( *= ); MAKE_SELF_OPERATOR_SCALAR( /= ); float &operator[](const int dimension) { return xy[dimension]; } const float &operator[](const int dimension) const { return xy[dimension]; } // Methods. float norm() const { return std::sqrt( x*x + y*y ); } // end method float2 normalized() const { const float v = norm(); return float2( x/v, y/v ); } // end method float2 safeNormalized() const { const float v = norm(); if ( v == 0.0 ) return float2(0,0); else return float2( x/v, y/v ); } // end method // clockwise float2 perpendicular() const { return float2( y, -x ); } // end method void apply(const float scalar) { x = scalar; y = scalar; } // end method void set( const float x, const float y ) { this->x = x; this->y = y; } // end method void scale(const float numb){ x = x*numb; y = y*numb; } // end method float aggregated() const { return x + y; } // end method void abs () { x = std::abs(x); y = std::abs(y); } // end method void clear () { x = 0; y = 0; } // end method inline bool approximatelyEqual(const float2 other, const float precision = 1e-6f) const; }; // end struct MAKE_OPERATOR( + ); MAKE_OPERATOR( - ); MAKE_OPERATOR( * ); MAKE_OPERATOR( / ); MAKE_OPERATOR_SCALAR( * ); MAKE_OPERATOR_SCALAR( / ); MAKE_FUNCTION_2(max); MAKE_FUNCTION_2(min); MAKE_FUNCTION_1(sqrt); // Unary operators. inline float2 operator-( const float2 value ) { return float2( -value.x, -value.y ); } // end operator inline float2 operator+( const float2 value ) { return float2( +value.x, +value.y ); } // end operator // Element-wise power. inline float2 pow( const float2 base, const float exp ) { return float2( std::pow( base.x, exp ), std::pow( base.y, exp ) ); } // end function // ----------------------------------------------------------------------------- inline bool float2::approximatelyEqual(const float2 other, const float precision) const { return (*this - other).norm() <= precision; } // end method // ----------------------------------------------------------------------------- #undef MAKE_OPERATOR #undef MAKE_OPERATOR_SCALAR #undef MAKE_SELF_OPERATOR #undef MAKE_SELF_OPERATOR_SCALAR #undef MAKE_FUNCTION_1 #undef MAKE_FUNCTION_2 #endif ================================================ FILE: rsyn/src/rsyn/util/geometry/Point.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_GEOMETRY_POINT_H #define RSYN_GEOMETRY_POINT_H #include #include #include #include "rsyn/util/dbu.h" namespace Rsyn { class Point { public: Point() {} Point(const DBU x, const DBU y) : clsX(x), clsY(y) {} Point(const DBUxy p) : clsX(p.x), clsY(p.y) {} DBU getX() const {return clsX;} DBU getY() const {return clsY;} void setX(const DBU x) {clsX = x;} void setY(const DBU y) {clsY = y;} //! @brief Translates this point by (dx, dy). void translate(const DBU dx, const DBU dy) { clsX += dx; clsY += dy; } // end method //! @brief Translates this point by displacement. void translate(const DBUxy displacement) { translate(displacement.x, displacement.y); } // end method //! @brief Returns copy of this point translated by (dx, dy). Point translated(const DBU dx, const DBU dy) const { Point point = *this; point.translate(dx, dy); return point; } // end method //! @brief Returns copy of this point translated by displacement. Point translated(const DBUxy displacement) const { return translated(displacement.x, displacement.y); } // end method operator DBUxy() const {return DBUxy(clsX, clsY);} private: DBU clsX = 0; DBU clsY = 0; }; // end class } // end namespace BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(Rsyn::Point, DBU, boost::geometry::cs::cartesian, getX, getY, setX, setY); #endif ================================================ FILE: rsyn/src/rsyn/util/geometry/Polygon.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Polygon.h" #include // Note: Comment the macro below if you have some problems with // boost::geometry::strategy::buffer. #define USE_BOOST_TO_CONVERT_LINE_STRING_TO_POLYGON // ----------------------------------------------------------------------------- namespace Rsyn { // ----------------------------------------------------------------------------- void Polygon::translate(const DBU dx, const DBU dy) { for (Point &point : clsBoostPolygon.outer()) { point.translate(dx, dy); } // end for } // end method // ----------------------------------------------------------------------------- Polygon Polygon::translated(const DBU dx, const DBU dy) const { Polygon poly = *this; poly.translate(dx, dy); return poly; } // end method // ----------------------------------------------------------------------------- } // end namespace // ############################################################################# #ifdef USE_BOOST_TO_CONVERT_LINE_STRING_TO_POLYGON // ############################################################################# #include #include #include namespace Rsyn { Polygon Polygon::createFromLineString(const std::vector &points, const DBU width) { Polygon rsynPolygon; typedef double coordinate_type; typedef boost::geometry::model::d2::point_xy point; typedef boost::geometry::model::polygon polygon; // Declare strategies const double buffer_distance = width/2.0; boost::geometry::strategy::buffer::distance_symmetric distance_strategy(buffer_distance); boost::geometry::strategy::buffer::join_miter join_strategy; boost::geometry::strategy::buffer::end_flat end_strategy; boost::geometry::strategy::buffer::point_square point_strategy; boost::geometry::strategy::buffer::side_straight side_strategy; // Declare output boost::geometry::model::multi_polygon result; // Declare/fill a linestring boost::geometry::model::linestring ls; for (const DBUxy &p : points) boost::geometry::append(ls, point(p.x, p.y)); // Create the buffer of a linestring boost::geometry::buffer(ls, result, distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy); for (const polygon &poly : result) { for (const point &p : poly.outer()) { rsynPolygon.addPoint(DBUxy( static_cast(std::round(p.x())), static_cast(std::round(p.y())))); } // end for // Defensive programming: this operation should not return more than one // polygon. break; } // end for return rsynPolygon; } // end method } // end namespace #endif // ############################################################################# #ifndef USE_BOOST_TO_CONVERT_LINE_STRING_TO_POLYGON // ############################################################################# // Uses the old way to convert a line string to a thick polygon inherited from // wxSightGL implemented by Marilena Maule (Lenna) and Guilherme Flach at UFRGS // around 2007. // // Use this only if you have issues using boost::geometry::strategy::buffer, // which is a more robust implementation and hence the preferred method. // ############################################################################# #include "rsyn/util/float2.h" namespace Rsyn { float2 findIntersection( float2 p1, float2 p2, float2 d1, float2 d2 ) { const float a = p1.x; const float e = p1.y; const float b = d1.x; const float f = d1.y; const float c = p2.x; const float g = p2.y; const float d = d2.x; const float h = d2.y; float t; if ((b * h - d * f) == 0) t = 0; else t = ((c - a) * h + (e - g) * d) / (b * h - d * f); float2 q = p1 + (d1 * t); bool bug; if ((t < 0 || t > 1)) { bug = true; } else { bug = false; } // end else return q; } // end function // ----------------------------------------------------------------------------- bool findPoint( float2 v0, float2 v1, float2 v2, const float thickness, std::vector &outlinePoints ) { // Direction vectors. float2 d1 = v1 - v0; float2 d2 = v2 - v1; // Points over the lines. float2 p1 = v1 + (d1.perpendicular().normalized()) * thickness; float2 p2 = v1 + (d2.perpendicular().normalized()) * thickness; float m1 = (v0.x - v1.x) == 0 ? (v0.y - v1.y) : (v0.y - v1.y) / (v0.x - v1.x); float m2 = (v1.x - v2.x) == 0 ? (v1.y - v2.y) : (v1.y - v2.y) / (v1.x - v2.x); float tg = (m1 - m2) / (1 + m1 * m2); float distancia = std::sqrt(std::pow((p1.x - p2.x), 2.0f) + std::pow((p1.y - p2.y), 2.0f)); float limite = std::sqrt(2.0f * std::pow(thickness, 2.0f)); if (distancia > limite && tg > 0.0f) { // dois outlinePoints.push_back(p1); outlinePoints.push_back(p2); return true; } else { float2 q = findIntersection(p1, p2, d1, d2); // um outlinePoints.push_back(q); return true; }//end else } // end method // ----------------------------------------------------------------------------- void tracePathOutline( const std::vector &pathPoints, const float halfThickness, std::vector &outlinePoints ) { // Historical Note: This function was adapted from wxSightGL developed by // Lenna and Guilherme around 2007. float2 v1; // First point v1 = float2( pathPoints[0] ) + ( float2( pathPoints[1] ) - float2( pathPoints[0] ) ).perpendicular().normalized() * halfThickness; outlinePoints.push_back(v1); // Forward traversal. bool control = true; for( size_t i = 1; i < pathPoints.size() - 1; i++){ control = findPoint( float2(pathPoints[i-1]), float2(pathPoints[i ]), float2(pathPoints[i+1]), halfThickness, outlinePoints); } // end for // Control point. if (control) { v1 = float2(pathPoints.back()) + float2( float2( pathPoints.back() ) - float2( pathPoints[pathPoints.size()-2] ) ).perpendicular().normalized() * halfThickness ; outlinePoints.push_back(v1); } // end if // Last point. v1 = float2( pathPoints.back() ) + float2( float2( pathPoints[pathPoints.size()-2] ) - float2( pathPoints.back() ) ).perpendicular().normalized() * halfThickness; outlinePoints.push_back(v1); // Backward traversal. for( int i = pathPoints.size() - 2; i >= 1; i--){ findPoint( float2(pathPoints[i+1]), float2(pathPoints[i ]), float2(pathPoints[i-1]), halfThickness, outlinePoints ); } // end if v1 = float2( pathPoints[0] ) + float2( float2( pathPoints[0] ) - float2( pathPoints[1] ) ).perpendicular().normalized() * halfThickness ; outlinePoints.push_back(v1); v1 = float2( pathPoints[0] ) + float2( float2( pathPoints[1] ) - float2( pathPoints[0] ) ).perpendicular().normalized() * halfThickness ; outlinePoints.push_back(v1); } // end method // ----------------------------------------------------------------------------- Polygon Polygon::createFromLineString(const std::vector &points, const DBU width) { std::vector outline; tracePathOutline(points, width/2.0, outline); Polygon rsynPolygon; for (const float2 &p : outline) { rsynPolygon.addPoint(DBUxy( static_cast(std::round(p.x)), static_cast(std::round(p.y)))); } // end for return rsynPolygon; } // end method } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/util/geometry/Polygon.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_GEOMETRY_POLYGON_H #define RSYN_GEOMETRY_POLYGON_H #include #include #include #include "rsyn/util/dbu.h" #include #include namespace Rsyn { class Polygon { public: Polygon() : clsDirty(true) {} //! @brief Creates a polygon from a line string. static Polygon createFromLineString(const std::vector &points, const DBU width); //! @brief Returns true if this a non-empty polygon. bool isValid() const { return getNumPoints() > 0; } // end method //! @brief Adds a point to this polygon. void addPoint(const DBU x, const DBU y) { addPoint(Point(x, y)); } // end method //! @brief Adds a point to this polygon. void addPoint(const Point &point) { boost::geometry::append(clsBoostPolygon.outer(), point); clsDirty = true; } // end method //! @brief Translates this polygon by (dx, dy). void translate(const DBU dx, const DBU dy); //! @brief Translates this polygon by displacement. void translate(const DBUxy displacement) { translate(displacement.x, displacement.y); } // end method //! @brief Returns copy of this polygon translated by (dx, dy). Polygon translated(const DBU dx, const DBU dy) const; //! @brief Returns copy of this polygon translated by displacement. Polygon translated(const DBUxy displacement) const { return translated(displacement.x, displacement.y); } // end method //! @brief Returns true if (x, y) is inside this polygon. bool contains(const DBU x, const DBU y) const { return contains(Point(x, y)); } // end method //! @brief Returns true if point is inside this polygon. bool contains(const Point &point) const { correct(); return boost::geometry::within(point, clsBoostPolygon); } // end method //! @brief Returns the shortest distance from (x, y) to this polygon. FloatingPointDBU distance(const DBU x, const DBU y) const { correct(); return distance(Point(x, y)); } // end method //! @brief Returns the shortest distance from a point to this polygon. FloatingPointDBU distance(const Point &point) const { correct(); return boost::geometry::distance(point, clsBoostPolygon); } // end method //! @brief Returns the shortest distance from a rectangle to this polygon. FloatingPointDBU distance(const Rect &rect) const { correct(); return boost::geometry::distance(rect, clsBoostPolygon); } // end method //! @brief Returns the shortest distance from a polygon to this polygon. FloatingPointDBU distance(const Polygon &poly) const { correct(); return boost::geometry::distance(poly.clsBoostPolygon, clsBoostPolygon); } // end method //! @brief Returns true if a polygon to overlaps this polygon. bool overlaps(const Rect &rect) const { correct(); // Boost 1.58 does not support overlap among a box and a polygon // directly so we first convert the rectangle to an equivalent polygon. return boost::geometry::overlaps(rect.toPolygon().clsBoostPolygon, clsBoostPolygon); } // end method //! @brief Returns true if a polygon to overlaps this polygon. bool overlaps(const Polygon &poly) const { correct(); return boost::geometry::overlaps(poly.clsBoostPolygon, clsBoostPolygon); } // end method //! @brief Removes all points from this polygon. void clear() { clsBoostPolygon.clear(); clsDirty = true; } // end method //! @brief Returns the number of points in this polygon. int getNumPoints() const { return boost::geometry::num_points(clsBoostPolygon); } // end method //! @brief Gets the i-th point of this polygon. //! @note Currently the points maybe stored in a different order than //! inserted as the points are corrected to be in the order boost::geometry //! assumes they to be. Point getPoint(const int index) const { correct(); return clsBoostPolygon.outer()[index]; } // end method //! @brief Returns a vector with all points in this polygon. const std::vector &getPoints() const { correct(); return clsBoostPolygon.outer(); } // end method //! @brief Used to iterate over all points using for-ranged loops. const std::vector &allPoints() const { correct(); return clsBoostPolygon.outer(); } // end method private: // @todo change to boost::geometry::model::ring typedef boost::geometry::model::polygon BoostPolygon; //! @brief Corrects the order of points in this polygon. //! @note This is necessary to comply with boost::geometry, which assumes //! the points of polygons are given in a specific order (e.g. clockwise). void correct() const { if (clsDirty) { boost::geometry::correct(clsBoostPolygon); clsDirty = false; } // end if } // end method //! @brief Indicates that this polygon may need correction as boost requires //! the point of a polygon to be in a certain order (e.g. clockwise). mutable bool clsDirty : 1; //! @brief The underlying Boost polygon. mutable BoostPolygon clsBoostPolygon; }; // end class } // end namespace #endif ================================================ FILE: rsyn/src/rsyn/util/geometry/Rect.cpp ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Rect.h" #include "Polygon.h" namespace Rsyn { // ----------------------------------------------------------------------------- bool Rect::overlaps(const Polygon &polygon) const { return polygon.overlaps(*this); } // end method // ----------------------------------------------------------------------------- Polygon Rect::toPolygon() const { Polygon polygon; polygon.addPoint(getLower().getX(), getLower().getY()); polygon.addPoint(getUpper().getX(), getLower().getY()); polygon.addPoint(getUpper().getX(), getUpper().getY()); polygon.addPoint(getLower().getX(), getUpper().getY()); return polygon; } // end method } // end namespace ================================================ FILE: rsyn/src/rsyn/util/geometry/Rect.h ================================================ /* Copyright 2014-2018 Rsyn * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef RSYN_GEOMETRY_RECT_H #define RSYN_GEOMETRY_RECT_H #include #include #include #include "rsyn/util/dbu.h" #include "rsyn/util/Bounds.h" #include "Point.h" namespace Rsyn { class Polygon; class Rect { public: Rect() : clsLower(0, 0), clsUpper(0, 0) {} Rect(const DBU x, const DBU y, const DBU w, const DBU h) : clsLower(x, y), clsUpper(x + w, y + h) {} Rect(const Bounds &bounds) : clsLower(bounds.getLower()), clsUpper(bounds.getUpper()) {} DBU getX() const {return clsLower.getX();} DBU getY() const {return clsLower.getY();} DBU getWidth() const {return clsUpper.getX() - clsLower.getX();} DBU getHeight() const {return clsUpper.getY() - clsLower.getY();} Point getLower() const {return clsLower;} Point getUpper() const {return clsUpper;} DBU getArea() const {return getWidth() * getHeight();} void setX(const DBU x) { const DBU w = getWidth(); clsLower.setX(x); clsUpper.setX(x + w); } // end method void setY(const DBU y) { const DBU h = getHeight(); clsLower.setY(y); clsUpper.setY(y + h); } // end method void setWidth(const DBU w) { clsUpper.setX(clsLower.getX() + w); } // end method void setHeight(const DBU h) { clsUpper.setY(clsLower.getY() + h); } // end method //! @brief Translates this rectangle by (dx, dy). void translate(const DBU dx, const DBU dy) { clsLower.translate(dx, dy); clsUpper.translate(dx, dy); } // end method //! @brief Translates this rectangle by displacement. void translate(const DBUxy displacement) { translate(displacement.x, displacement.y); } // end method //! @brief Returns copy of this rectangle translated by (dx, dy). Rect translated(const DBU dx, const DBU dy) const { Rect rect = *this; rect.translate(dx, dy); return rect; } // end method //! @brief Returns copy of this rectangle translated by displacement. Rect translated(const DBUxy displacement) const { return translated(displacement.x, displacement.y); } // end method bool contains(const DBU x, const DBU y) const { return (x >= clsLower.getX() && x <= clsUpper.getX()) && (y >= clsLower.getY() && y <= clsUpper.getY()); } // end method bool contains(const Point &point) const { return contains(point.getX(), point.getY()); } // end method bool overlaps(const Rect &rect) const { const DBU dx = std::max(getLower().getX(), rect.getLower().getX()) - std::min(getUpper().getX(), rect.getUpper().getX()); const DBU dy = std::max(getLower().getY(), rect.getLower().getY()) - std::min(getUpper().getY(), rect.getUpper().getY()); return (dx<=0 && dy<=0); } // end method bool overlaps(const Polygon &polygon) const; operator Bounds() const {return Bounds(getLower(), getUpper());} Bounds getBounds() const { return Bounds(getLower(), getUpper()); } Polygon toPolygon() const; private: Point clsUpper; Point clsLower; }; // end class } // end namespace BOOST_GEOMETRY_REGISTER_BOX(Rsyn::Rect, Rsyn::Point, getLower(), getUpper()); #endif ================================================ FILE: scripts/build.py ================================================ #!/usr/bin/env python import argparse import os all_targets = ['iccad19gr'] run_files = 'scripts/*.py ispd18eval ispd19eval drcu' def run(command): if args.print_commands: print(command) if os.system(command) is not 0: if not args.print_commands: print(command) quit() # cmake & copy run files # for sanitize, need to remove -static from src/CMakeLists.txt mode_cmake_options = { None: '', 'debug': '-DCMAKE_BUILD_TYPE=Debug', 'release': '-DCMAKE_BUILD_TYPE=Release', 'profile': '-DCMAKE_CXX_FLAGS=-pg', 'release_profile': '-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-pg', 'asan': '-DCMAKE_CXX_FLAGS=-fsanitize=address', 'debug_asan': '-DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS=-fsanitize=address', 'tsan': '-DCMAKE_CXX_FLAGS=-fsanitize=thread', 'debug_tsan': '-DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS=-fsanitize=thread' } # argparse parser = argparse.ArgumentParser(description='Build iccad19gr in Linux') parser.add_argument('-t', '--targets', choices=all_targets, nargs='+') parser.add_argument('-o', '--mode', choices=mode_cmake_options.keys()) parser.add_argument('-c', '--cmake_options', default='') parser.add_argument('-m', '--make_options', default='-j 6') parser.add_argument('-u', '--unittest', action='store_true') parser.add_argument('-p', '--print_commands', action='store_true') parser.add_argument('-b', '--build_dir', default='build') parser.add_argument('-r', '--run_dir', default='run') args = parser.parse_args() # targets if args.unittest: build_targets = ['unittest_salt'] elif args.targets is None: build_targets = [''] else: build_targets = args.targets run('cmake src -B{} {} {}'.format(args.build_dir, mode_cmake_options[args.mode], args.cmake_options)) run('mkdir -p {}'.format(args.run_dir)) run('cp -u -R {} {}'.format(run_files, args.run_dir)) # make for target in build_targets: run('cmake --build {} --target {} -- {}'.format(args.build_dir, target, args.make_options)) cp_targets = all_targets if build_targets == [''] else build_targets for target in cp_targets: run('cp -u {}/{} {}'.format(args.build_dir, target, args.run_dir)) # flute LUT run('cp src/flute/*.dat {}'.format(args.run_dir)) # unit test if args.unittest: root_dir = os.path.curdir os.chdir(args.run_dir) run('./{}'.format('unittest_salt')) os.chdir(root_dir) ================================================ FILE: scripts/gprof2dot.py ================================================ #!/usr/bin/env python3 # # Copyright 2008-2017 Jose Fonseca # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # """Generate a dot graph from the output of several profilers.""" __author__ = "Jose Fonseca et al" import sys import math import os.path import re import textwrap import optparse import xml.parsers.expat import collections import locale import json import fnmatch # Python 2.x/3.x compatibility if sys.version_info[0] >= 3: PYTHON_3 = True def compat_iteritems(x): return x.items() # No iteritems() in Python 3 def compat_itervalues(x): return x.values() # No itervalues() in Python 3 def compat_keys(x): return list(x.keys()) # keys() is a generator in Python 3 basestring = str # No class basestring in Python 3 unichr = chr # No unichr in Python 3 xrange = range # No xrange in Python 3 else: PYTHON_3 = False def compat_iteritems(x): return x.iteritems() def compat_itervalues(x): return x.itervalues() def compat_keys(x): return x.keys() ######################################################################## # Model MULTIPLICATION_SIGN = unichr(0xd7) def times(x): return "%u%s" % (x, MULTIPLICATION_SIGN) def percentage(p): return "%.02f%%" % (p*100.0,) def add(a, b): return a + b def fail(a, b): assert False tol = 2 ** -23 def ratio(numerator, denominator): try: ratio = float(numerator)/float(denominator) except ZeroDivisionError: # 0/0 is undefined, but 1.0 yields more useful results return 1.0 if ratio < 0.0: if ratio < -tol: sys.stderr.write('warning: negative ratio (%s/%s)\n' % (numerator, denominator)) return 0.0 if ratio > 1.0: if ratio > 1.0 + tol: sys.stderr.write('warning: ratio greater than one (%s/%s)\n' % (numerator, denominator)) return 1.0 return ratio class UndefinedEvent(Exception): """Raised when attempting to get an event which is undefined.""" def __init__(self, event): Exception.__init__(self) self.event = event def __str__(self): return 'unspecified event %s' % self.event.name class Event(object): """Describe a kind of event, and its basic operations.""" def __init__(self, name, null, aggregator, formatter = str): self.name = name self._null = null self._aggregator = aggregator self._formatter = formatter def __eq__(self, other): return self is other def __hash__(self): return id(self) def null(self): return self._null def aggregate(self, val1, val2): """Aggregate two event values.""" assert val1 is not None assert val2 is not None return self._aggregator(val1, val2) def format(self, val): """Format an event value.""" assert val is not None return self._formatter(val) CALLS = Event("Calls", 0, add, times) SAMPLES = Event("Samples", 0, add, times) SAMPLES2 = Event("Samples", 0, add, times) # Count of samples where a given function was either executing or on the stack. # This is used to calculate the total time ratio according to the # straightforward method described in Mike Dunlavey's answer to # stackoverflow.com/questions/1777556/alternatives-to-gprof, item 4 (the myth # "that recursion is a tricky confusing issue"), last edited 2012-08-30: it's # just the ratio of TOTAL_SAMPLES over the number of samples in the profile. # # Used only when totalMethod == callstacks TOTAL_SAMPLES = Event("Samples", 0, add, times) TIME = Event("Time", 0.0, add, lambda x: '(' + str(x) + ')') TIME_RATIO = Event("Time ratio", 0.0, add, lambda x: '(' + percentage(x) + ')') TOTAL_TIME = Event("Total time", 0.0, fail) TOTAL_TIME_RATIO = Event("Total time ratio", 0.0, fail, percentage) totalMethod = 'callratios' class Object(object): """Base class for all objects in profile which can store events.""" def __init__(self, events=None): if events is None: self.events = {} else: self.events = events def __hash__(self): return id(self) def __eq__(self, other): return self is other def __lt__(self, other): return id(self) < id(other) def __contains__(self, event): return event in self.events def __getitem__(self, event): try: return self.events[event] except KeyError: raise UndefinedEvent(event) def __setitem__(self, event, value): if value is None: if event in self.events: del self.events[event] else: self.events[event] = value class Call(Object): """A call between functions. There should be at most one call object for every pair of functions. """ def __init__(self, callee_id): Object.__init__(self) self.callee_id = callee_id self.ratio = None self.weight = None class Function(Object): """A function.""" def __init__(self, id, name): Object.__init__(self) self.id = id self.name = name self.module = None self.process = None self.calls = {} self.called = None self.weight = None self.cycle = None self.filename = None def add_call(self, call): if call.callee_id in self.calls: sys.stderr.write('warning: overwriting call from function %s to %s\n' % (str(self.id), str(call.callee_id))) self.calls[call.callee_id] = call def get_call(self, callee_id): if not callee_id in self.calls: call = Call(callee_id) call[SAMPLES] = 0 call[SAMPLES2] = 0 call[CALLS] = 0 self.calls[callee_id] = call return self.calls[callee_id] _parenthesis_re = re.compile(r'\([^()]*\)') _angles_re = re.compile(r'<[^<>]*>') _const_re = re.compile(r'\s+const$') def stripped_name(self): """Remove extraneous information from C++ demangled function names.""" name = self.name # Strip function parameters from name by recursively removing paired parenthesis while True: name, n = self._parenthesis_re.subn('', name) if not n: break # Strip const qualifier name = self._const_re.sub('', name) # Strip template parameters from name by recursively removing paired angles while True: name, n = self._angles_re.subn('', name) if not n: break return name # TODO: write utility functions def __repr__(self): return self.name class Cycle(Object): """A cycle made from recursive function calls.""" def __init__(self): Object.__init__(self) self.functions = set() def add_function(self, function): assert function not in self.functions self.functions.add(function) if function.cycle is not None: for other in function.cycle.functions: if function not in self.functions: self.add_function(other) function.cycle = self class Profile(Object): """The whole profile.""" def __init__(self): Object.__init__(self) self.functions = {} self.cycles = [] def add_function(self, function): if function.id in self.functions: sys.stderr.write('warning: overwriting function %s (id %s)\n' % (function.name, str(function.id))) self.functions[function.id] = function def add_cycle(self, cycle): self.cycles.append(cycle) def validate(self): """Validate the edges.""" for function in compat_itervalues(self.functions): for callee_id in compat_keys(function.calls): assert function.calls[callee_id].callee_id == callee_id if callee_id not in self.functions: sys.stderr.write('warning: call to undefined function %s from function %s\n' % (str(callee_id), function.name)) del function.calls[callee_id] def find_cycles(self): """Find cycles using Tarjan's strongly connected components algorithm.""" # Apply the Tarjan's algorithm successively until all functions are visited stack = [] data = {} order = 0 for function in compat_itervalues(self.functions): order = self._tarjan(function, order, stack, data) cycles = [] for function in compat_itervalues(self.functions): if function.cycle is not None and function.cycle not in cycles: cycles.append(function.cycle) self.cycles = cycles if 0: for cycle in cycles: sys.stderr.write("Cycle:\n") for member in cycle.functions: sys.stderr.write("\tFunction %s\n" % member.name) def prune_root(self, roots, depth=-1): visited = set() frontier = set([(root_node, depth) for root_node in roots]) while len(frontier) > 0: node, node_depth = frontier.pop() visited.add(node) if node_depth == 0: continue f = self.functions[node] newNodes = set(f.calls.keys()) - visited frontier = frontier.union({(new_node, node_depth - 1) for new_node in newNodes}) subtreeFunctions = {} for n in visited: f = self.functions[n] newCalls = {} for c in f.calls.keys(): if c in visited: newCalls[c] = f.calls[c] f.calls = newCalls subtreeFunctions[n] = f self.functions = subtreeFunctions def prune_leaf(self, leafs, depth=-1): edgesUp = collections.defaultdict(set) for f in self.functions.keys(): for n in self.functions[f].calls.keys(): edgesUp[n].add(f) # build the tree up visited = set() frontier = set([(leaf_node, depth) for leaf_node in leafs]) while len(frontier) > 0: node, node_depth = frontier.pop() visited.add(node) if node_depth == 0: continue newNodes = edgesUp[node] - visited frontier = frontier.union({(new_node, node_depth - 1) for new_node in newNodes}) downTree = set(self.functions.keys()) upTree = visited path = downTree.intersection(upTree) pathFunctions = {} for n in path: f = self.functions[n] newCalls = {} for c in f.calls.keys(): if c in path: newCalls[c] = f.calls[c] f.calls = newCalls pathFunctions[n] = f self.functions = pathFunctions def getFunctionIds(self, funcName): function_names = {v.name: k for (k, v) in self.functions.items()} return [function_names[name] for name in fnmatch.filter(function_names.keys(), funcName)] def getFunctionId(self, funcName): for f in self.functions: if self.functions[f].name == funcName: return f return False class _TarjanData: def __init__(self, order): self.order = order self.lowlink = order self.onstack = False def _tarjan(self, function, order, stack, data): """Tarjan's strongly connected components algorithm. See also: - http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm """ try: func_data = data[function.id] return order except KeyError: func_data = self._TarjanData(order) data[function.id] = func_data order += 1 pos = len(stack) stack.append(function) func_data.onstack = True for call in compat_itervalues(function.calls): try: callee_data = data[call.callee_id] if callee_data.onstack: func_data.lowlink = min(func_data.lowlink, callee_data.order) except KeyError: callee = self.functions[call.callee_id] order = self._tarjan(callee, order, stack, data) callee_data = data[call.callee_id] func_data.lowlink = min(func_data.lowlink, callee_data.lowlink) if func_data.lowlink == func_data.order: # Strongly connected component found members = stack[pos:] del stack[pos:] if len(members) > 1: cycle = Cycle() for member in members: cycle.add_function(member) data[member.id].onstack = False else: for member in members: data[member.id].onstack = False return order def call_ratios(self, event): # Aggregate for incoming calls cycle_totals = {} for cycle in self.cycles: cycle_totals[cycle] = 0.0 function_totals = {} for function in compat_itervalues(self.functions): function_totals[function] = 0.0 # Pass 1: function_total gets the sum of call[event] for all # incoming arrows. Same for cycle_total for all arrows # that are coming into the *cycle* but are not part of it. for function in compat_itervalues(self.functions): for call in compat_itervalues(function.calls): if call.callee_id != function.id: callee = self.functions[call.callee_id] if event in call.events: function_totals[callee] += call[event] if callee.cycle is not None and callee.cycle is not function.cycle: cycle_totals[callee.cycle] += call[event] else: sys.stderr.write("call_ratios: No data for " + function.name + " call to " + callee.name + "\n") # Pass 2: Compute the ratios. Each call[event] is scaled by the # function_total of the callee. Calls into cycles use the # cycle_total, but not calls within cycles. for function in compat_itervalues(self.functions): for call in compat_itervalues(function.calls): assert call.ratio is None if call.callee_id != function.id: callee = self.functions[call.callee_id] if event in call.events: if callee.cycle is not None and callee.cycle is not function.cycle: total = cycle_totals[callee.cycle] else: total = function_totals[callee] call.ratio = ratio(call[event], total) else: # Warnings here would only repeat those issued above. call.ratio = 0.0 def integrate(self, outevent, inevent): """Propagate function time ratio along the function calls. Must be called after finding the cycles. See also: - http://citeseer.ist.psu.edu/graham82gprof.html """ # Sanity checking assert outevent not in self for function in compat_itervalues(self.functions): assert outevent not in function assert inevent in function for call in compat_itervalues(function.calls): assert outevent not in call if call.callee_id != function.id: assert call.ratio is not None # Aggregate the input for each cycle for cycle in self.cycles: total = inevent.null() for function in compat_itervalues(self.functions): total = inevent.aggregate(total, function[inevent]) self[inevent] = total # Integrate along the edges total = inevent.null() for function in compat_itervalues(self.functions): total = inevent.aggregate(total, function[inevent]) self._integrate_function(function, outevent, inevent) self[outevent] = total def _integrate_function(self, function, outevent, inevent): if function.cycle is not None: return self._integrate_cycle(function.cycle, outevent, inevent) else: if outevent not in function: total = function[inevent] for call in compat_itervalues(function.calls): if call.callee_id != function.id: total += self._integrate_call(call, outevent, inevent) function[outevent] = total return function[outevent] def _integrate_call(self, call, outevent, inevent): assert outevent not in call assert call.ratio is not None callee = self.functions[call.callee_id] subtotal = call.ratio *self._integrate_function(callee, outevent, inevent) call[outevent] = subtotal return subtotal def _integrate_cycle(self, cycle, outevent, inevent): if outevent not in cycle: # Compute the outevent for the whole cycle total = inevent.null() for member in cycle.functions: subtotal = member[inevent] for call in compat_itervalues(member.calls): callee = self.functions[call.callee_id] if callee.cycle is not cycle: subtotal += self._integrate_call(call, outevent, inevent) total += subtotal cycle[outevent] = total # Compute the time propagated to callers of this cycle callees = {} for function in compat_itervalues(self.functions): if function.cycle is not cycle: for call in compat_itervalues(function.calls): callee = self.functions[call.callee_id] if callee.cycle is cycle: try: callees[callee] += call.ratio except KeyError: callees[callee] = call.ratio for member in cycle.functions: member[outevent] = outevent.null() for callee, call_ratio in compat_iteritems(callees): ranks = {} call_ratios = {} partials = {} self._rank_cycle_function(cycle, callee, ranks) self._call_ratios_cycle(cycle, callee, ranks, call_ratios, set()) partial = self._integrate_cycle_function(cycle, callee, call_ratio, partials, ranks, call_ratios, outevent, inevent) # Ensure `partial == max(partials.values())`, but with round-off tolerance max_partial = max(partials.values()) assert abs(partial - max_partial) <= 1e-7*max_partial assert abs(call_ratio*total - partial) <= 0.001*call_ratio*total return cycle[outevent] def _rank_cycle_function(self, cycle, function, ranks): """Dijkstra's shortest paths algorithm. See also: - http://en.wikipedia.org/wiki/Dijkstra's_algorithm """ import heapq Q = [] Qd = {} p = {} visited = set([function]) ranks[function] = 0 for call in compat_itervalues(function.calls): if call.callee_id != function.id: callee = self.functions[call.callee_id] if callee.cycle is cycle: ranks[callee] = 1 item = [ranks[callee], function, callee] heapq.heappush(Q, item) Qd[callee] = item while Q: cost, parent, member = heapq.heappop(Q) if member not in visited: p[member]= parent visited.add(member) for call in compat_itervalues(member.calls): if call.callee_id != member.id: callee = self.functions[call.callee_id] if callee.cycle is cycle: member_rank = ranks[member] rank = ranks.get(callee) if rank is not None: if rank > 1 + member_rank: rank = 1 + member_rank ranks[callee] = rank Qd_callee = Qd[callee] Qd_callee[0] = rank Qd_callee[1] = member heapq._siftdown(Q, 0, Q.index(Qd_callee)) else: rank = 1 + member_rank ranks[callee] = rank item = [rank, member, callee] heapq.heappush(Q, item) Qd[callee] = item def _call_ratios_cycle(self, cycle, function, ranks, call_ratios, visited): if function not in visited: visited.add(function) for call in compat_itervalues(function.calls): if call.callee_id != function.id: callee = self.functions[call.callee_id] if callee.cycle is cycle: if ranks[callee] > ranks[function]: call_ratios[callee] = call_ratios.get(callee, 0.0) + call.ratio self._call_ratios_cycle(cycle, callee, ranks, call_ratios, visited) def _integrate_cycle_function(self, cycle, function, partial_ratio, partials, ranks, call_ratios, outevent, inevent): if function not in partials: partial = partial_ratio*function[inevent] for call in compat_itervalues(function.calls): if call.callee_id != function.id: callee = self.functions[call.callee_id] if callee.cycle is not cycle: assert outevent in call partial += partial_ratio*call[outevent] else: if ranks[callee] > ranks[function]: callee_partial = self._integrate_cycle_function(cycle, callee, partial_ratio, partials, ranks, call_ratios, outevent, inevent) call_ratio = ratio(call.ratio, call_ratios[callee]) call_partial = call_ratio*callee_partial try: call[outevent] += call_partial except UndefinedEvent: call[outevent] = call_partial partial += call_partial partials[function] = partial try: function[outevent] += partial except UndefinedEvent: function[outevent] = partial return partials[function] def aggregate(self, event): """Aggregate an event for the whole profile.""" total = event.null() for function in compat_itervalues(self.functions): try: total = event.aggregate(total, function[event]) except UndefinedEvent: return self[event] = total def ratio(self, outevent, inevent): assert outevent not in self assert inevent in self for function in compat_itervalues(self.functions): assert outevent not in function assert inevent in function function[outevent] = ratio(function[inevent], self[inevent]) for call in compat_itervalues(function.calls): assert outevent not in call if inevent in call: call[outevent] = ratio(call[inevent], self[inevent]) self[outevent] = 1.0 def prune(self, node_thres, edge_thres, paths, color_nodes_by_selftime): """Prune the profile""" # compute the prune ratios for function in compat_itervalues(self.functions): try: function.weight = function[TOTAL_TIME_RATIO] except UndefinedEvent: pass for call in compat_itervalues(function.calls): callee = self.functions[call.callee_id] if TOTAL_TIME_RATIO in call: # handle exact cases first call.weight = call[TOTAL_TIME_RATIO] else: try: # make a safe estimate call.weight = min(function[TOTAL_TIME_RATIO], callee[TOTAL_TIME_RATIO]) except UndefinedEvent: pass # prune the nodes for function_id in compat_keys(self.functions): function = self.functions[function_id] if function.weight is not None: if function.weight < node_thres: del self.functions[function_id] # prune file paths for function_id in compat_keys(self.functions): function = self.functions[function_id] if paths and not any(function.filename.startswith(path) for path in paths): del self.functions[function_id] # prune the egdes for function in compat_itervalues(self.functions): for callee_id in compat_keys(function.calls): call = function.calls[callee_id] if callee_id not in self.functions or call.weight is not None and call.weight < edge_thres: del function.calls[callee_id] if color_nodes_by_selftime: weights = [] for function in compat_itervalues(self.functions): try: weights.append(function[TIME_RATIO]) except UndefinedEvent: pass max_ratio = max(weights or [1]) # apply rescaled weights for coloriung for function in compat_itervalues(self.functions): try: function.weight = function[TIME_RATIO] / max_ratio except (ZeroDivisionError, UndefinedEvent): pass def dump(self): for function in compat_itervalues(self.functions): sys.stderr.write('Function %s:\n' % (function.name,)) self._dump_events(function.events) for call in compat_itervalues(function.calls): callee = self.functions[call.callee_id] sys.stderr.write(' Call %s:\n' % (callee.name,)) self._dump_events(call.events) for cycle in self.cycles: sys.stderr.write('Cycle:\n') self._dump_events(cycle.events) for function in cycle.functions: sys.stderr.write(' Function %s\n' % (function.name,)) def _dump_events(self, events): for event, value in compat_iteritems(events): sys.stderr.write(' %s: %s\n' % (event.name, event.format(value))) ######################################################################## # Parsers class Struct: """Masquerade a dictionary with a structure-like behavior.""" def __init__(self, attrs = None): if attrs is None: attrs = {} self.__dict__['_attrs'] = attrs def __getattr__(self, name): try: return self._attrs[name] except KeyError: raise AttributeError(name) def __setattr__(self, name, value): self._attrs[name] = value def __str__(self): return str(self._attrs) def __repr__(self): return repr(self._attrs) class ParseError(Exception): """Raised when parsing to signal mismatches.""" def __init__(self, msg, line): Exception.__init__(self) self.msg = msg # TODO: store more source line information self.line = line def __str__(self): return '%s: %r' % (self.msg, self.line) class Parser: """Parser interface.""" stdinInput = True multipleInput = False def __init__(self): pass def parse(self): raise NotImplementedError class JsonParser(Parser): """Parser for a custom JSON representation of profile data. See schema.json for details. """ def __init__(self, stream): Parser.__init__(self) self.stream = stream def parse(self): obj = json.load(self.stream) assert obj['version'] == 0 profile = Profile() profile[SAMPLES] = 0 fns = obj['functions'] for functionIndex in range(len(fns)): fn = fns[functionIndex] function = Function(functionIndex, fn['name']) try: function.module = fn['module'] except KeyError: pass try: function.process = fn['process'] except KeyError: pass function[SAMPLES] = 0 profile.add_function(function) for event in obj['events']: callchain = [] for functionIndex in event['callchain']: function = profile.functions[functionIndex] callchain.append(function) cost = event['cost'][0] callee = callchain[0] callee[SAMPLES] += cost profile[SAMPLES] += cost for caller in callchain[1:]: try: call = caller.calls[callee.id] except KeyError: call = Call(callee.id) call[SAMPLES2] = cost caller.add_call(call) else: call[SAMPLES2] += cost callee = caller if False: profile.dump() # compute derived data profile.validate() profile.find_cycles() profile.ratio(TIME_RATIO, SAMPLES) profile.call_ratios(SAMPLES2) profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) return profile class LineParser(Parser): """Base class for parsers that read line-based formats.""" def __init__(self, stream): Parser.__init__(self) self._stream = stream self.__line = None self.__eof = False self.line_no = 0 def readline(self): line = self._stream.readline() if not line: self.__line = '' self.__eof = True else: self.line_no += 1 line = line.rstrip('\r\n') if not PYTHON_3: encoding = self._stream.encoding if encoding is None: encoding = locale.getpreferredencoding() line = line.decode(encoding) self.__line = line def lookahead(self): assert self.__line is not None return self.__line def consume(self): assert self.__line is not None line = self.__line self.readline() return line def eof(self): assert self.__line is not None return self.__eof XML_ELEMENT_START, XML_ELEMENT_END, XML_CHARACTER_DATA, XML_EOF = range(4) class XmlToken: def __init__(self, type, name_or_data, attrs = None, line = None, column = None): assert type in (XML_ELEMENT_START, XML_ELEMENT_END, XML_CHARACTER_DATA, XML_EOF) self.type = type self.name_or_data = name_or_data self.attrs = attrs self.line = line self.column = column def __str__(self): if self.type == XML_ELEMENT_START: return '<' + self.name_or_data + ' ...>' if self.type == XML_ELEMENT_END: return '' if self.type == XML_CHARACTER_DATA: return self.name_or_data if self.type == XML_EOF: return 'end of file' assert 0 class XmlTokenizer: """Expat based XML tokenizer.""" def __init__(self, fp, skip_ws = True): self.fp = fp self.tokens = [] self.index = 0 self.final = False self.skip_ws = skip_ws self.character_pos = 0, 0 self.character_data = '' self.parser = xml.parsers.expat.ParserCreate() self.parser.StartElementHandler = self.handle_element_start self.parser.EndElementHandler = self.handle_element_end self.parser.CharacterDataHandler = self.handle_character_data def handle_element_start(self, name, attributes): self.finish_character_data() line, column = self.pos() token = XmlToken(XML_ELEMENT_START, name, attributes, line, column) self.tokens.append(token) def handle_element_end(self, name): self.finish_character_data() line, column = self.pos() token = XmlToken(XML_ELEMENT_END, name, None, line, column) self.tokens.append(token) def handle_character_data(self, data): if not self.character_data: self.character_pos = self.pos() self.character_data += data def finish_character_data(self): if self.character_data: if not self.skip_ws or not self.character_data.isspace(): line, column = self.character_pos token = XmlToken(XML_CHARACTER_DATA, self.character_data, None, line, column) self.tokens.append(token) self.character_data = '' def next(self): size = 16*1024 while self.index >= len(self.tokens) and not self.final: self.tokens = [] self.index = 0 data = self.fp.read(size) self.final = len(data) < size self.parser.Parse(data, self.final) if self.index >= len(self.tokens): line, column = self.pos() token = XmlToken(XML_EOF, None, None, line, column) else: token = self.tokens[self.index] self.index += 1 return token def pos(self): return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber class XmlTokenMismatch(Exception): def __init__(self, expected, found): Exception.__init__(self) self.expected = expected self.found = found def __str__(self): return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found)) class XmlParser(Parser): """Base XML document parser.""" def __init__(self, fp): Parser.__init__(self) self.tokenizer = XmlTokenizer(fp) self.consume() def consume(self): self.token = self.tokenizer.next() def match_element_start(self, name): return self.token.type == XML_ELEMENT_START and self.token.name_or_data == name def match_element_end(self, name): return self.token.type == XML_ELEMENT_END and self.token.name_or_data == name def element_start(self, name): while self.token.type == XML_CHARACTER_DATA: self.consume() if self.token.type != XML_ELEMENT_START: raise XmlTokenMismatch(XmlToken(XML_ELEMENT_START, name), self.token) if self.token.name_or_data != name: raise XmlTokenMismatch(XmlToken(XML_ELEMENT_START, name), self.token) attrs = self.token.attrs self.consume() return attrs def element_end(self, name): while self.token.type == XML_CHARACTER_DATA: self.consume() if self.token.type != XML_ELEMENT_END: raise XmlTokenMismatch(XmlToken(XML_ELEMENT_END, name), self.token) if self.token.name_or_data != name: raise XmlTokenMismatch(XmlToken(XML_ELEMENT_END, name), self.token) self.consume() def character_data(self, strip = True): data = '' while self.token.type == XML_CHARACTER_DATA: data += self.token.name_or_data self.consume() if strip: data = data.strip() return data class GprofParser(Parser): """Parser for GNU gprof output. See also: - Chapter "Interpreting gprof's Output" from the GNU gprof manual http://sourceware.org/binutils/docs-2.18/gprof/Call-Graph.html#Call-Graph - File "cg_print.c" from the GNU gprof source code http://sourceware.org/cgi-bin/cvsweb.cgi/~checkout~/src/gprof/cg_print.c?rev=1.12&cvsroot=src """ def __init__(self, fp): Parser.__init__(self) self.fp = fp self.functions = {} self.cycles = {} def readline(self): line = self.fp.readline() if not line: sys.stderr.write('error: unexpected end of file\n') sys.exit(1) line = line.rstrip('\r\n') return line _int_re = re.compile(r'^\d+$') _float_re = re.compile(r'^\d+\.\d+$') def translate(self, mo): """Extract a structure from a match object, while translating the types in the process.""" attrs = {} groupdict = mo.groupdict() for name, value in compat_iteritems(groupdict): if value is None: value = None elif self._int_re.match(value): value = int(value) elif self._float_re.match(value): value = float(value) attrs[name] = (value) return Struct(attrs) _cg_header_re = re.compile( # original gprof header r'^\s+called/total\s+parents\s*$|' + r'^index\s+%time\s+self\s+descendents\s+called\+self\s+name\s+index\s*$|' + r'^\s+called/total\s+children\s*$|' + # GNU gprof header r'^index\s+%\s+time\s+self\s+children\s+called\s+name\s*$' ) _cg_ignore_re = re.compile( # spontaneous r'^\s+\s*$|' # internal calls (such as "mcount") r'^.*\((\d+)\)$' ) _cg_primary_re = re.compile( r'^\[(?P\d+)\]?' + r'\s+(?P\d+\.\d+)' + r'\s+(?P\d+\.\d+)' + r'\s+(?P\d+\.\d+)' + r'\s+(?:(?P\d+)(?:\+(?P\d+))?)?' + r'\s+(?P\S.*?)' + r'(?:\s+\d+)>)?' + r'\s\[(\d+)\]$' ) _cg_parent_re = re.compile( r'^\s+(?P\d+\.\d+)?' + r'\s+(?P\d+\.\d+)?' + r'\s+(?P\d+)(?:/(?P\d+))?' + r'\s+(?P\S.*?)' + r'(?:\s+\d+)>)?' + r'\s\[(?P\d+)\]$' ) _cg_child_re = _cg_parent_re _cg_cycle_header_re = re.compile( r'^\[(?P\d+)\]?' + r'\s+(?P\d+\.\d+)' + r'\s+(?P\d+\.\d+)' + r'\s+(?P\d+\.\d+)' + r'\s+(?:(?P\d+)(?:\+(?P\d+))?)?' + r'\s+\d+)\sas\sa\swhole>' + r'\s\[(\d+)\]$' ) _cg_cycle_member_re = re.compile( r'^\s+(?P\d+\.\d+)?' + r'\s+(?P\d+\.\d+)?' + r'\s+(?P\d+)(?:\+(?P\d+))?' + r'\s+(?P\S.*?)' + r'(?:\s+\d+)>)?' + r'\s\[(?P\d+)\]$' ) _cg_sep_re = re.compile(r'^--+$') def parse_function_entry(self, lines): parents = [] children = [] while True: if not lines: sys.stderr.write('warning: unexpected end of entry\n') line = lines.pop(0) if line.startswith('['): break # read function parent line mo = self._cg_parent_re.match(line) if not mo: if self._cg_ignore_re.match(line): continue sys.stderr.write('warning: unrecognized call graph entry: %r\n' % line) else: parent = self.translate(mo) parents.append(parent) # read primary line mo = self._cg_primary_re.match(line) if not mo: sys.stderr.write('warning: unrecognized call graph entry: %r\n' % line) return else: function = self.translate(mo) while lines: line = lines.pop(0) # read function subroutine line mo = self._cg_child_re.match(line) if not mo: if self._cg_ignore_re.match(line): continue sys.stderr.write('warning: unrecognized call graph entry: %r\n' % line) else: child = self.translate(mo) children.append(child) function.parents = parents function.children = children self.functions[function.index] = function def parse_cycle_entry(self, lines): # read cycle header line line = lines[0] mo = self._cg_cycle_header_re.match(line) if not mo: sys.stderr.write('warning: unrecognized call graph entry: %r\n' % line) return cycle = self.translate(mo) # read cycle member lines cycle.functions = [] for line in lines[1:]: mo = self._cg_cycle_member_re.match(line) if not mo: sys.stderr.write('warning: unrecognized call graph entry: %r\n' % line) continue call = self.translate(mo) cycle.functions.append(call) self.cycles[cycle.cycle] = cycle def parse_cg_entry(self, lines): if lines[0].startswith("["): self.parse_cycle_entry(lines) else: self.parse_function_entry(lines) def parse_cg(self): """Parse the call graph.""" # skip call graph header while not self._cg_header_re.match(self.readline()): pass line = self.readline() while self._cg_header_re.match(line): line = self.readline() # process call graph entries entry_lines = [] while line != '\014': # form feed if line and not line.isspace(): if self._cg_sep_re.match(line): self.parse_cg_entry(entry_lines) entry_lines = [] else: entry_lines.append(line) line = self.readline() def parse(self): self.parse_cg() self.fp.close() profile = Profile() profile[TIME] = 0.0 cycles = {} for index in self.cycles: cycles[index] = Cycle() for entry in compat_itervalues(self.functions): # populate the function function = Function(entry.index, entry.name) function[TIME] = entry.self if entry.called is not None: function.called = entry.called if entry.called_self is not None: call = Call(entry.index) call[CALLS] = entry.called_self function.called += entry.called_self # populate the function calls for child in entry.children: call = Call(child.index) assert child.called is not None call[CALLS] = child.called if child.index not in self.functions: # NOTE: functions that were never called but were discovered by gprof's # static call graph analysis dont have a call graph entry so we need # to add them here missing = Function(child.index, child.name) function[TIME] = 0.0 function.called = 0 profile.add_function(missing) function.add_call(call) profile.add_function(function) if entry.cycle is not None: try: cycle = cycles[entry.cycle] except KeyError: sys.stderr.write('warning: entry missing\n' % entry.cycle) cycle = Cycle() cycles[entry.cycle] = cycle cycle.add_function(function) profile[TIME] = profile[TIME] + function[TIME] for cycle in compat_itervalues(cycles): profile.add_cycle(cycle) # Compute derived events profile.validate() profile.ratio(TIME_RATIO, TIME) profile.call_ratios(CALLS) profile.integrate(TOTAL_TIME, TIME) profile.ratio(TOTAL_TIME_RATIO, TOTAL_TIME) return profile # Clone&hack of GprofParser for VTune Amplifier XE 2013 gprof-cc output. # Tested only with AXE 2013 for Windows. # - Use total times as reported by AXE. # - In the absence of call counts, call ratios are faked from the relative # proportions of total time. This affects only the weighting of the calls. # - Different header, separator, and end marker. # - Extra whitespace after function names. # - You get a full entry for , which does not have parents. # - Cycles do have parents. These are saved but unused (as they are # for functions). # - Disambiguated "unrecognized call graph entry" error messages. # Notes: # - Total time of functions as reported by AXE passes the val3 test. # - CPU Time:Children in the input is sometimes a negative number. This # value goes to the variable descendants, which is unused. # - The format of gprof-cc reports is unaffected by the use of # -knob enable-call-counts=true (no call counts, ever), or # -show-as=samples (results are quoted in seconds regardless). class AXEParser(Parser): "Parser for VTune Amplifier XE 2013 gprof-cc report output." def __init__(self, fp): Parser.__init__(self) self.fp = fp self.functions = {} self.cycles = {} def readline(self): line = self.fp.readline() if not line: sys.stderr.write('error: unexpected end of file\n') sys.exit(1) line = line.rstrip('\r\n') return line _int_re = re.compile(r'^\d+$') _float_re = re.compile(r'^\d+\.\d+$') def translate(self, mo): """Extract a structure from a match object, while translating the types in the process.""" attrs = {} groupdict = mo.groupdict() for name, value in compat_iteritems(groupdict): if value is None: value = None elif self._int_re.match(value): value = int(value) elif self._float_re.match(value): value = float(value) attrs[name] = (value) return Struct(attrs) _cg_header_re = re.compile( '^Index |' '^-----+ ' ) _cg_footer_re = re.compile(r'^Index\s+Function\s*$') _cg_primary_re = re.compile( r'^\[(?P\d+)\]?' + r'\s+(?P\d+\.\d+)' + r'\s+(?P\d+\.\d+)' + r'\s+(?P\d+\.\d+)' + r'\s+(?P\S.*?)' + r'(?:\s+\d+)>)?' + r'\s+\[(\d+)\]' + r'\s*$' ) _cg_parent_re = re.compile( r'^\s+(?P\d+\.\d+)?' + r'\s+(?P\d+\.\d+)?' + r'\s+(?P\S.*?)' + r'(?:\s+\d+)>)?' + r'(?:\s+\[(?P\d+)\]\s*)?' + r'\s*$' ) _cg_child_re = _cg_parent_re _cg_cycle_header_re = re.compile( r'^\[(?P\d+)\]?' + r'\s+(?P\d+\.\d+)' + r'\s+(?P\d+\.\d+)' + r'\s+(?P\d+\.\d+)' + r'\s+\d+)\sas\sa\swhole>' + r'\s+\[(\d+)\]' + r'\s*$' ) _cg_cycle_member_re = re.compile( r'^\s+(?P\d+\.\d+)?' + r'\s+(?P\d+\.\d+)?' + r'\s+(?P\S.*?)' + r'(?:\s+\d+)>)?' + r'\s+\[(?P\d+)\]' + r'\s*$' ) def parse_function_entry(self, lines): parents = [] children = [] while True: if not lines: sys.stderr.write('warning: unexpected end of entry\n') return line = lines.pop(0) if line.startswith('['): break # read function parent line mo = self._cg_parent_re.match(line) if not mo: sys.stderr.write('warning: unrecognized call graph entry (1): %r\n' % line) else: parent = self.translate(mo) if parent.name != '': parents.append(parent) # read primary line mo = self._cg_primary_re.match(line) if not mo: sys.stderr.write('warning: unrecognized call graph entry (2): %r\n' % line) return else: function = self.translate(mo) while lines: line = lines.pop(0) # read function subroutine line mo = self._cg_child_re.match(line) if not mo: sys.stderr.write('warning: unrecognized call graph entry (3): %r\n' % line) else: child = self.translate(mo) if child.name != '': children.append(child) if function.name != '': function.parents = parents function.children = children self.functions[function.index] = function def parse_cycle_entry(self, lines): # Process the parents that were not there in gprof format. parents = [] while True: if not lines: sys.stderr.write('warning: unexpected end of cycle entry\n') return line = lines.pop(0) if line.startswith('['): break mo = self._cg_parent_re.match(line) if not mo: sys.stderr.write('warning: unrecognized call graph entry (6): %r\n' % line) else: parent = self.translate(mo) if parent.name != '': parents.append(parent) # read cycle header line mo = self._cg_cycle_header_re.match(line) if not mo: sys.stderr.write('warning: unrecognized call graph entry (4): %r\n' % line) return cycle = self.translate(mo) # read cycle member lines cycle.functions = [] for line in lines[1:]: mo = self._cg_cycle_member_re.match(line) if not mo: sys.stderr.write('warning: unrecognized call graph entry (5): %r\n' % line) continue call = self.translate(mo) cycle.functions.append(call) cycle.parents = parents self.cycles[cycle.cycle] = cycle def parse_cg_entry(self, lines): if any("as a whole" in linelooper for linelooper in lines): self.parse_cycle_entry(lines) else: self.parse_function_entry(lines) def parse_cg(self): """Parse the call graph.""" # skip call graph header line = self.readline() while self._cg_header_re.match(line): line = self.readline() # process call graph entries entry_lines = [] # An EOF in readline terminates the program without returning. while not self._cg_footer_re.match(line): if line.isspace(): self.parse_cg_entry(entry_lines) entry_lines = [] else: entry_lines.append(line) line = self.readline() def parse(self): sys.stderr.write('warning: for axe format, edge weights are unreliable estimates derived from function total times.\n') self.parse_cg() self.fp.close() profile = Profile() profile[TIME] = 0.0 cycles = {} for index in self.cycles: cycles[index] = Cycle() for entry in compat_itervalues(self.functions): # populate the function function = Function(entry.index, entry.name) function[TIME] = entry.self function[TOTAL_TIME_RATIO] = entry.percentage_time / 100.0 # populate the function calls for child in entry.children: call = Call(child.index) # The following bogus value affects only the weighting of # the calls. call[TOTAL_TIME_RATIO] = function[TOTAL_TIME_RATIO] if child.index not in self.functions: # NOTE: functions that were never called but were discovered by gprof's # static call graph analysis dont have a call graph entry so we need # to add them here # FIXME: Is this applicable? missing = Function(child.index, child.name) function[TIME] = 0.0 profile.add_function(missing) function.add_call(call) profile.add_function(function) if entry.cycle is not None: try: cycle = cycles[entry.cycle] except KeyError: sys.stderr.write('warning: entry missing\n' % entry.cycle) cycle = Cycle() cycles[entry.cycle] = cycle cycle.add_function(function) profile[TIME] = profile[TIME] + function[TIME] for cycle in compat_itervalues(cycles): profile.add_cycle(cycle) # Compute derived events. profile.validate() profile.ratio(TIME_RATIO, TIME) # Lacking call counts, fake call ratios based on total times. profile.call_ratios(TOTAL_TIME_RATIO) # The TOTAL_TIME_RATIO of functions is already set. Propagate that # total time to the calls. (TOTAL_TIME is neither set nor used.) for function in compat_itervalues(profile.functions): for call in compat_itervalues(function.calls): if call.ratio is not None: callee = profile.functions[call.callee_id] call[TOTAL_TIME_RATIO] = call.ratio * callee[TOTAL_TIME_RATIO] return profile class CallgrindParser(LineParser): """Parser for valgrind's callgrind tool. See also: - http://valgrind.org/docs/manual/cl-format.html """ _call_re = re.compile(r'^calls=\s*(\d+)\s+((\d+|\+\d+|-\d+|\*)\s+)+$') def __init__(self, infile): LineParser.__init__(self, infile) # Textual positions self.position_ids = {} self.positions = {} # Numeric positions self.num_positions = 1 self.cost_positions = ['line'] self.last_positions = [0] # Events self.num_events = 0 self.cost_events = [] self.profile = Profile() self.profile[SAMPLES] = 0 def parse(self): # read lookahead self.readline() self.parse_key('version') self.parse_key('creator') while self.parse_part(): pass if not self.eof(): sys.stderr.write('warning: line %u: unexpected line\n' % self.line_no) sys.stderr.write('%s\n' % self.lookahead()) # compute derived data self.profile.validate() self.profile.find_cycles() self.profile.ratio(TIME_RATIO, SAMPLES) self.profile.call_ratios(SAMPLES2) self.profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) return self.profile def parse_part(self): if not self.parse_header_line(): return False while self.parse_header_line(): pass if not self.parse_body_line(): return False while self.parse_body_line(): pass return True def parse_header_line(self): return \ self.parse_empty() or \ self.parse_comment() or \ self.parse_part_detail() or \ self.parse_description() or \ self.parse_event_specification() or \ self.parse_cost_line_def() or \ self.parse_cost_summary() _detail_keys = set(('cmd', 'pid', 'thread', 'part')) def parse_part_detail(self): return self.parse_keys(self._detail_keys) def parse_description(self): return self.parse_key('desc') is not None def parse_event_specification(self): event = self.parse_key('event') if event is None: return False return True def parse_cost_line_def(self): pair = self.parse_keys(('events', 'positions')) if pair is None: return False key, value = pair items = value.split() if key == 'events': self.num_events = len(items) self.cost_events = items if key == 'positions': self.num_positions = len(items) self.cost_positions = items self.last_positions = [0]*self.num_positions return True def parse_cost_summary(self): pair = self.parse_keys(('summary', 'totals')) if pair is None: return False return True def parse_body_line(self): return \ self.parse_empty() or \ self.parse_comment() or \ self.parse_cost_line() or \ self.parse_position_spec() or \ self.parse_association_spec() __subpos_re = r'(0x[0-9a-fA-F]+|\d+|\+\d+|-\d+|\*)' _cost_re = re.compile(r'^' + __subpos_re + r'( +' + __subpos_re + r')*' + r'( +\d+)*' + '$') def parse_cost_line(self, calls=None): line = self.lookahead().rstrip() mo = self._cost_re.match(line) if not mo: return False function = self.get_function() if calls is None: # Unlike other aspects, call object (cob) is relative not to the # last call object, but to the caller's object (ob), so try to # update it when processing a functions cost line try: self.positions['cob'] = self.positions['ob'] except KeyError: pass values = line.split() assert len(values) <= self.num_positions + self.num_events positions = values[0 : self.num_positions] events = values[self.num_positions : ] events += ['0']*(self.num_events - len(events)) for i in range(self.num_positions): position = positions[i] if position == '*': position = self.last_positions[i] elif position[0] in '-+': position = self.last_positions[i] + int(position) elif position.startswith('0x'): position = int(position, 16) else: position = int(position) self.last_positions[i] = position events = [float(event) for event in events] if calls is None: function[SAMPLES] += events[0] self.profile[SAMPLES] += events[0] else: callee = self.get_callee() callee.called += calls try: call = function.calls[callee.id] except KeyError: call = Call(callee.id) call[CALLS] = calls call[SAMPLES2] = events[0] function.add_call(call) else: call[CALLS] += calls call[SAMPLES2] += events[0] self.consume() return True def parse_association_spec(self): line = self.lookahead() if not line.startswith('calls='): return False _, values = line.split('=', 1) values = values.strip().split() calls = int(values[0]) call_position = values[1:] self.consume() self.parse_cost_line(calls) return True _position_re = re.compile(r'^(?P[cj]?(?:ob|fl|fi|fe|fn))=\s*(?:\((?P\d+)\))?(?:\s*(?P.+))?') _position_table_map = { 'ob': 'ob', 'fl': 'fl', 'fi': 'fl', 'fe': 'fl', 'fn': 'fn', 'cob': 'ob', 'cfl': 'fl', 'cfi': 'fl', 'cfe': 'fl', 'cfn': 'fn', 'jfi': 'fl', } _position_map = { 'ob': 'ob', 'fl': 'fl', 'fi': 'fl', 'fe': 'fl', 'fn': 'fn', 'cob': 'cob', 'cfl': 'cfl', 'cfi': 'cfl', 'cfe': 'cfl', 'cfn': 'cfn', 'jfi': 'jfi', } def parse_position_spec(self): line = self.lookahead() if line.startswith('jump=') or line.startswith('jcnd='): self.consume() return True mo = self._position_re.match(line) if not mo: return False position, id, name = mo.groups() if id: table = self._position_table_map[position] if name: self.position_ids[(table, id)] = name else: name = self.position_ids.get((table, id), '') self.positions[self._position_map[position]] = name self.consume() return True def parse_empty(self): if self.eof(): return False line = self.lookahead() if line.strip(): return False self.consume() return True def parse_comment(self): line = self.lookahead() if not line.startswith('#'): return False self.consume() return True _key_re = re.compile(r'^(\w+):') def parse_key(self, key): pair = self.parse_keys((key,)) if not pair: return None key, value = pair return value def parse_keys(self, keys): line = self.lookahead() mo = self._key_re.match(line) if not mo: return None key, value = line.split(':', 1) if key not in keys: return None value = value.strip() self.consume() return key, value def make_function(self, module, filename, name): # FIXME: module and filename are not being tracked reliably #id = '|'.join((module, filename, name)) id = name try: function = self.profile.functions[id] except KeyError: function = Function(id, name) if module: function.module = os.path.basename(module) function[SAMPLES] = 0 function.called = 0 self.profile.add_function(function) return function def get_function(self): module = self.positions.get('ob', '') filename = self.positions.get('fl', '') function = self.positions.get('fn', '') return self.make_function(module, filename, function) def get_callee(self): module = self.positions.get('cob', '') filename = self.positions.get('cfi', '') function = self.positions.get('cfn', '') return self.make_function(module, filename, function) def readline(self): # Override LineParser.readline to ignore comment lines while True: LineParser.readline(self) if self.eof() or not self.lookahead().startswith('#'): break class PerfParser(LineParser): """Parser for linux perf callgraph output. It expects output generated with perf record -g perf script | gprof2dot.py --format=perf """ def __init__(self, infile): LineParser.__init__(self, infile) self.profile = Profile() def readline(self): # Override LineParser.readline to ignore comment lines while True: LineParser.readline(self) if self.eof() or not self.lookahead().startswith('#'): break def parse(self): # read lookahead self.readline() profile = self.profile profile[SAMPLES] = 0 while not self.eof(): self.parse_event() # compute derived data profile.validate() profile.find_cycles() profile.ratio(TIME_RATIO, SAMPLES) profile.call_ratios(SAMPLES2) if totalMethod == "callratios": # Heuristic approach. TOTAL_SAMPLES is unused. profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) elif totalMethod == "callstacks": # Use the actual call chains for functions. profile[TOTAL_SAMPLES] = profile[SAMPLES] profile.ratio(TOTAL_TIME_RATIO, TOTAL_SAMPLES) # Then propagate that total time to the calls. for function in compat_itervalues(profile.functions): for call in compat_itervalues(function.calls): if call.ratio is not None: callee = profile.functions[call.callee_id] call[TOTAL_TIME_RATIO] = call.ratio * callee[TOTAL_TIME_RATIO] else: assert False return profile def parse_event(self): if self.eof(): return line = self.consume() assert line callchain = self.parse_callchain() if not callchain: return callee = callchain[0] callee[SAMPLES] += 1 self.profile[SAMPLES] += 1 for caller in callchain[1:]: try: call = caller.calls[callee.id] except KeyError: call = Call(callee.id) call[SAMPLES2] = 1 caller.add_call(call) else: call[SAMPLES2] += 1 callee = caller # Increment TOTAL_SAMPLES only once on each function. stack = set(callchain) for function in stack: function[TOTAL_SAMPLES] += 1 def parse_callchain(self): callchain = [] while self.lookahead(): function = self.parse_call() if function is None: break callchain.append(function) if self.lookahead() == '': self.consume() return callchain call_re = re.compile(r'^\s+(?P
[0-9a-fA-F]+)\s+(?P.*)\s+\((?P.*)\)$') addr2_re = re.compile(r'\+0x[0-9a-fA-F]+$') def parse_call(self): line = self.consume() mo = self.call_re.match(line) assert mo if not mo: return None function_name = mo.group('symbol') # If present, amputate program counter from function name. if function_name: function_name = re.sub(self.addr2_re, '', function_name) if not function_name or function_name == '[unknown]': function_name = mo.group('address') module = mo.group('module') function_id = function_name + ':' + module try: function = self.profile.functions[function_id] except KeyError: function = Function(function_id, function_name) function.module = os.path.basename(module) function[SAMPLES] = 0 function[TOTAL_SAMPLES] = 0 self.profile.add_function(function) return function class OprofileParser(LineParser): """Parser for oprofile callgraph output. See also: - http://oprofile.sourceforge.net/doc/opreport.html#opreport-callgraph """ _fields_re = { 'samples': r'(\d+)', '%': r'(\S+)', 'linenr info': r'(?P\(no location information\)|\S+:\d+)', 'image name': r'(?P\S+(?:\s\(tgid:[^)]*\))?)', 'app name': r'(?P\S+)', 'symbol name': r'(?P\(no symbols\)|.+?)', } def __init__(self, infile): LineParser.__init__(self, infile) self.entries = {} self.entry_re = None def add_entry(self, callers, function, callees): try: entry = self.entries[function.id] except KeyError: self.entries[function.id] = (callers, function, callees) else: callers_total, function_total, callees_total = entry self.update_subentries_dict(callers_total, callers) function_total.samples += function.samples self.update_subentries_dict(callees_total, callees) def update_subentries_dict(self, totals, partials): for partial in compat_itervalues(partials): try: total = totals[partial.id] except KeyError: totals[partial.id] = partial else: total.samples += partial.samples def parse(self): # read lookahead self.readline() self.parse_header() while self.lookahead(): self.parse_entry() profile = Profile() reverse_call_samples = {} # populate the profile profile[SAMPLES] = 0 for _callers, _function, _callees in compat_itervalues(self.entries): function = Function(_function.id, _function.name) function[SAMPLES] = _function.samples profile.add_function(function) profile[SAMPLES] += _function.samples if _function.application: function.process = os.path.basename(_function.application) if _function.image: function.module = os.path.basename(_function.image) total_callee_samples = 0 for _callee in compat_itervalues(_callees): total_callee_samples += _callee.samples for _callee in compat_itervalues(_callees): if not _callee.self: call = Call(_callee.id) call[SAMPLES2] = _callee.samples function.add_call(call) # compute derived data profile.validate() profile.find_cycles() profile.ratio(TIME_RATIO, SAMPLES) profile.call_ratios(SAMPLES2) profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) return profile def parse_header(self): while not self.match_header(): self.consume() line = self.lookahead() fields = re.split(r'\s\s+', line) entry_re = r'^\s*' + r'\s+'.join([self._fields_re[field] for field in fields]) + r'(?P\s+\[self\])?$' self.entry_re = re.compile(entry_re) self.skip_separator() def parse_entry(self): callers = self.parse_subentries() if self.match_primary(): function = self.parse_subentry() if function is not None: callees = self.parse_subentries() self.add_entry(callers, function, callees) self.skip_separator() def parse_subentries(self): subentries = {} while self.match_secondary(): subentry = self.parse_subentry() subentries[subentry.id] = subentry return subentries def parse_subentry(self): entry = Struct() line = self.consume() mo = self.entry_re.match(line) if not mo: raise ParseError('failed to parse', line) fields = mo.groupdict() entry.samples = int(mo.group(1)) if 'source' in fields and fields['source'] != '(no location information)': source = fields['source'] filename, lineno = source.split(':') entry.filename = filename entry.lineno = int(lineno) else: source = '' entry.filename = None entry.lineno = None entry.image = fields.get('image', '') entry.application = fields.get('application', '') if 'symbol' in fields and fields['symbol'] != '(no symbols)': entry.symbol = fields['symbol'] else: entry.symbol = '' if entry.symbol.startswith('"') and entry.symbol.endswith('"'): entry.symbol = entry.symbol[1:-1] entry.id = ':'.join((entry.application, entry.image, source, entry.symbol)) entry.self = fields.get('self', None) != None if entry.self: entry.id += ':self' if entry.symbol: entry.name = entry.symbol else: entry.name = entry.image return entry def skip_separator(self): while not self.match_separator(): self.consume() self.consume() def match_header(self): line = self.lookahead() return line.startswith('samples') def match_separator(self): line = self.lookahead() return line == '-'*len(line) def match_primary(self): line = self.lookahead() return not line[:1].isspace() def match_secondary(self): line = self.lookahead() return line[:1].isspace() class HProfParser(LineParser): """Parser for java hprof output See also: - http://java.sun.com/developer/technicalArticles/Programming/HPROF.html """ trace_re = re.compile(r'\t(.*)\((.*):(.*)\)') trace_id_re = re.compile(r'^TRACE (\d+):$') def __init__(self, infile): LineParser.__init__(self, infile) self.traces = {} self.samples = {} def parse(self): # read lookahead self.readline() while not self.lookahead().startswith('------'): self.consume() while not self.lookahead().startswith('TRACE '): self.consume() self.parse_traces() while not self.lookahead().startswith('CPU'): self.consume() self.parse_samples() # populate the profile profile = Profile() profile[SAMPLES] = 0 functions = {} # build up callgraph for id, trace in compat_iteritems(self.traces): if not id in self.samples: continue mtime = self.samples[id][0] last = None for func, file, line in trace: if not func in functions: function = Function(func, func) function[SAMPLES] = 0 profile.add_function(function) functions[func] = function function = functions[func] # allocate time to the deepest method in the trace if not last: function[SAMPLES] += mtime profile[SAMPLES] += mtime else: c = function.get_call(last) c[SAMPLES2] += mtime last = func # compute derived data profile.validate() profile.find_cycles() profile.ratio(TIME_RATIO, SAMPLES) profile.call_ratios(SAMPLES2) profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) return profile def parse_traces(self): while self.lookahead().startswith('TRACE '): self.parse_trace() def parse_trace(self): l = self.consume() mo = self.trace_id_re.match(l) tid = mo.group(1) last = None trace = [] while self.lookahead().startswith('\t'): l = self.consume() match = self.trace_re.search(l) if not match: #sys.stderr.write('Invalid line: %s\n' % l) break else: function_name, file, line = match.groups() trace += [(function_name, file, line)] self.traces[int(tid)] = trace def parse_samples(self): self.consume() self.consume() while not self.lookahead().startswith('CPU'): rank, percent_self, percent_accum, count, traceid, method = self.lookahead().split() self.samples[int(traceid)] = (int(count), method) self.consume() class SysprofParser(XmlParser): def __init__(self, stream): XmlParser.__init__(self, stream) def parse(self): objects = {} nodes = {} self.element_start('profile') while self.token.type == XML_ELEMENT_START: if self.token.name_or_data == 'objects': assert not objects objects = self.parse_items('objects') elif self.token.name_or_data == 'nodes': assert not nodes nodes = self.parse_items('nodes') else: self.parse_value(self.token.name_or_data) self.element_end('profile') return self.build_profile(objects, nodes) def parse_items(self, name): assert name[-1] == 's' items = {} self.element_start(name) while self.token.type == XML_ELEMENT_START: id, values = self.parse_item(name[:-1]) assert id not in items items[id] = values self.element_end(name) return items def parse_item(self, name): attrs = self.element_start(name) id = int(attrs['id']) values = self.parse_values() self.element_end(name) return id, values def parse_values(self): values = {} while self.token.type == XML_ELEMENT_START: name = self.token.name_or_data value = self.parse_value(name) assert name not in values values[name] = value return values def parse_value(self, tag): self.element_start(tag) value = self.character_data() self.element_end(tag) if value.isdigit(): return int(value) if value.startswith('"') and value.endswith('"'): return value[1:-1] return value def build_profile(self, objects, nodes): profile = Profile() profile[SAMPLES] = 0 for id, object in compat_iteritems(objects): # Ignore fake objects (process names, modules, "Everything", "kernel", etc.) if object['self'] == 0: continue function = Function(id, object['name']) function[SAMPLES] = object['self'] profile.add_function(function) profile[SAMPLES] += function[SAMPLES] for id, node in compat_iteritems(nodes): # Ignore fake calls if node['self'] == 0: continue # Find a non-ignored parent parent_id = node['parent'] while parent_id != 0: parent = nodes[parent_id] caller_id = parent['object'] if objects[caller_id]['self'] != 0: break parent_id = parent['parent'] if parent_id == 0: continue callee_id = node['object'] assert objects[caller_id]['self'] assert objects[callee_id]['self'] function = profile.functions[caller_id] samples = node['self'] try: call = function.calls[callee_id] except KeyError: call = Call(callee_id) call[SAMPLES2] = samples function.add_call(call) else: call[SAMPLES2] += samples # Compute derived events profile.validate() profile.find_cycles() profile.ratio(TIME_RATIO, SAMPLES) profile.call_ratios(SAMPLES2) profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) return profile class XPerfParser(Parser): """Parser for CSVs generted by XPerf, from Microsoft Windows Performance Tools. """ def __init__(self, stream): Parser.__init__(self) self.stream = stream self.profile = Profile() self.profile[SAMPLES] = 0 self.column = {} def parse(self): import csv reader = csv.reader( self.stream, delimiter = ',', quotechar = None, escapechar = None, doublequote = False, skipinitialspace = True, lineterminator = '\r\n', quoting = csv.QUOTE_NONE) header = True for row in reader: if header: self.parse_header(row) header = False else: self.parse_row(row) # compute derived data self.profile.validate() self.profile.find_cycles() self.profile.ratio(TIME_RATIO, SAMPLES) self.profile.call_ratios(SAMPLES2) self.profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) return self.profile def parse_header(self, row): for column in range(len(row)): name = row[column] assert name not in self.column self.column[name] = column def parse_row(self, row): fields = {} for name, column in compat_iteritems(self.column): value = row[column] for factory in int, float: try: value = factory(value) except ValueError: pass else: break fields[name] = value process = fields['Process Name'] symbol = fields['Module'] + '!' + fields['Function'] weight = fields['Weight'] count = fields['Count'] if process == 'Idle': return function = self.get_function(process, symbol) function[SAMPLES] += weight * count self.profile[SAMPLES] += weight * count stack = fields['Stack'] if stack != '?': stack = stack.split('/') assert stack[0] == '[Root]' if stack[-1] != symbol: # XXX: some cases the sampled function does not appear in the stack stack.append(symbol) caller = None for symbol in stack[1:]: callee = self.get_function(process, symbol) if caller is not None: try: call = caller.calls[callee.id] except KeyError: call = Call(callee.id) call[SAMPLES2] = count caller.add_call(call) else: call[SAMPLES2] += count caller = callee def get_function(self, process, symbol): function_id = process + '!' + symbol try: function = self.profile.functions[function_id] except KeyError: module, name = symbol.split('!', 1) function = Function(function_id, name) function.process = process function.module = module function[SAMPLES] = 0 self.profile.add_function(function) return function class SleepyParser(Parser): """Parser for GNU gprof output. See also: - http://www.codersnotes.com/sleepy/ - http://sleepygraph.sourceforge.net/ """ stdinInput = False def __init__(self, filename): Parser.__init__(self) from zipfile import ZipFile self.database = ZipFile(filename) self.symbols = {} self.calls = {} self.profile = Profile() _symbol_re = re.compile( r'^(?P\w+)' + r'\s+"(?P[^"]*)"' + r'\s+"(?P[^"]*)"' + r'\s+"(?P[^"]*)"' + r'\s+(?P\d+)$' ) def openEntry(self, name): # Some versions of verysleepy use lowercase filenames for database_name in self.database.namelist(): if name.lower() == database_name.lower(): name = database_name break return self.database.open(name, 'r') def parse_symbols(self): for line in self.openEntry('Symbols.txt'): line = line.decode('UTF-8').rstrip('\r\n') mo = self._symbol_re.match(line) if mo: symbol_id, module, procname, sourcefile, sourceline = mo.groups() function_id = ':'.join([module, procname]) try: function = self.profile.functions[function_id] except KeyError: function = Function(function_id, procname) function.module = module function[SAMPLES] = 0 self.profile.add_function(function) self.symbols[symbol_id] = function def parse_callstacks(self): for line in self.openEntry('Callstacks.txt'): line = line.decode('UTF-8').rstrip('\r\n') fields = line.split() samples = float(fields[0]) callstack = fields[1:] callstack = [self.symbols[symbol_id] for symbol_id in callstack] callee = callstack[0] callee[SAMPLES] += samples self.profile[SAMPLES] += samples for caller in callstack[1:]: try: call = caller.calls[callee.id] except KeyError: call = Call(callee.id) call[SAMPLES2] = samples caller.add_call(call) else: call[SAMPLES2] += samples callee = caller def parse(self): profile = self.profile profile[SAMPLES] = 0 self.parse_symbols() self.parse_callstacks() # Compute derived events profile.validate() profile.find_cycles() profile.ratio(TIME_RATIO, SAMPLES) profile.call_ratios(SAMPLES2) profile.integrate(TOTAL_TIME_RATIO, TIME_RATIO) return profile class PstatsParser: """Parser python profiling statistics saved with te pstats module.""" stdinInput = False multipleInput = True def __init__(self, *filename): import pstats try: self.stats = pstats.Stats(*filename) except ValueError: if PYTHON_3: sys.stderr.write('error: failed to load %s\n' % ', '.join(filename)) sys.exit(1) import hotshot.stats self.stats = hotshot.stats.load(filename[0]) self.profile = Profile() self.function_ids = {} def get_function_name(self, key): filename, line, name = key module = os.path.splitext(filename)[0] module = os.path.basename(module) return "%s:%d:%s" % (module, line, name) def get_function(self, key): try: id = self.function_ids[key] except KeyError: id = len(self.function_ids) name = self.get_function_name(key) function = Function(id, name) function.filename = key[0] self.profile.functions[id] = function self.function_ids[key] = id else: function = self.profile.functions[id] return function def parse(self): self.profile[TIME] = 0.0 self.profile[TOTAL_TIME] = self.stats.total_tt for fn, (cc, nc, tt, ct, callers) in compat_iteritems(self.stats.stats): callee = self.get_function(fn) callee.called = nc callee[TOTAL_TIME] = ct callee[TIME] = tt self.profile[TIME] += tt self.profile[TOTAL_TIME] = max(self.profile[TOTAL_TIME], ct) for fn, value in compat_iteritems(callers): caller = self.get_function(fn) call = Call(callee.id) if isinstance(value, tuple): for i in xrange(0, len(value), 4): nc, cc, tt, ct = value[i:i+4] if CALLS in call: call[CALLS] += cc else: call[CALLS] = cc if TOTAL_TIME in call: call[TOTAL_TIME] += ct else: call[TOTAL_TIME] = ct else: call[CALLS] = value call[TOTAL_TIME] = ratio(value, nc)*ct caller.add_call(call) if False: self.stats.print_stats() self.stats.print_callees() # Compute derived events self.profile.validate() self.profile.ratio(TIME_RATIO, TIME) self.profile.ratio(TOTAL_TIME_RATIO, TOTAL_TIME) return self.profile formats = { "axe": AXEParser, "callgrind": CallgrindParser, "hprof": HProfParser, "json": JsonParser, "oprofile": OprofileParser, "perf": PerfParser, "prof": GprofParser, "pstats": PstatsParser, "sleepy": SleepyParser, "sysprof": SysprofParser, "xperf": XPerfParser, } ######################################################################## # Output class Theme: def __init__(self, bgcolor = (0.0, 0.0, 1.0), mincolor = (0.0, 0.0, 0.0), maxcolor = (0.0, 0.0, 1.0), fontname = "Arial", fontcolor = "white", nodestyle = "filled", minfontsize = 10.0, maxfontsize = 10.0, minpenwidth = 0.5, maxpenwidth = 4.0, gamma = 2.2, skew = 1.0): self.bgcolor = bgcolor self.mincolor = mincolor self.maxcolor = maxcolor self.fontname = fontname self.fontcolor = fontcolor self.nodestyle = nodestyle self.minfontsize = minfontsize self.maxfontsize = maxfontsize self.minpenwidth = minpenwidth self.maxpenwidth = maxpenwidth self.gamma = gamma self.skew = skew def graph_bgcolor(self): return self.hsl_to_rgb(*self.bgcolor) def graph_fontname(self): return self.fontname def graph_fontcolor(self): return self.fontcolor def graph_fontsize(self): return self.minfontsize def node_bgcolor(self, weight): return self.color(weight) def node_fgcolor(self, weight): if self.nodestyle == "filled": return self.graph_bgcolor() else: return self.color(weight) def node_fontsize(self, weight): return self.fontsize(weight) def node_style(self): return self.nodestyle def edge_color(self, weight): return self.color(weight) def edge_fontsize(self, weight): return self.fontsize(weight) def edge_penwidth(self, weight): return max(weight*self.maxpenwidth, self.minpenwidth) def edge_arrowsize(self, weight): return 0.5 * math.sqrt(self.edge_penwidth(weight)) def fontsize(self, weight): return max(weight**2 * self.maxfontsize, self.minfontsize) def color(self, weight): weight = min(max(weight, 0.0), 1.0) hmin, smin, lmin = self.mincolor hmax, smax, lmax = self.maxcolor if self.skew < 0: raise ValueError("Skew must be greater than 0") elif self.skew == 1.0: h = hmin + weight*(hmax - hmin) s = smin + weight*(smax - smin) l = lmin + weight*(lmax - lmin) else: base = self.skew h = hmin + ((hmax-hmin)*(-1.0 + (base ** weight)) / (base - 1.0)) s = smin + ((smax-smin)*(-1.0 + (base ** weight)) / (base - 1.0)) l = lmin + ((lmax-lmin)*(-1.0 + (base ** weight)) / (base - 1.0)) return self.hsl_to_rgb(h, s, l) def hsl_to_rgb(self, h, s, l): """Convert a color from HSL color-model to RGB. See also: - http://www.w3.org/TR/css3-color/#hsl-color """ h = h % 1.0 s = min(max(s, 0.0), 1.0) l = min(max(l, 0.0), 1.0) if l <= 0.5: m2 = l*(s + 1.0) else: m2 = l + s - l*s m1 = l*2.0 - m2 r = self._hue_to_rgb(m1, m2, h + 1.0/3.0) g = self._hue_to_rgb(m1, m2, h) b = self._hue_to_rgb(m1, m2, h - 1.0/3.0) # Apply gamma correction r **= self.gamma g **= self.gamma b **= self.gamma return (r, g, b) def _hue_to_rgb(self, m1, m2, h): if h < 0.0: h += 1.0 elif h > 1.0: h -= 1.0 if h*6 < 1.0: return m1 + (m2 - m1)*h*6.0 elif h*2 < 1.0: return m2 elif h*3 < 2.0: return m1 + (m2 - m1)*(2.0/3.0 - h)*6.0 else: return m1 TEMPERATURE_COLORMAP = Theme( mincolor = (2.0/3.0, 0.80, 0.25), # dark blue maxcolor = (0.0, 1.0, 0.5), # satured red gamma = 1.0 ) PINK_COLORMAP = Theme( mincolor = (0.0, 1.0, 0.90), # pink maxcolor = (0.0, 1.0, 0.5), # satured red ) GRAY_COLORMAP = Theme( mincolor = (0.0, 0.0, 0.85), # light gray maxcolor = (0.0, 0.0, 0.0), # black ) BW_COLORMAP = Theme( minfontsize = 8.0, maxfontsize = 24.0, mincolor = (0.0, 0.0, 0.0), # black maxcolor = (0.0, 0.0, 0.0), # black minpenwidth = 0.1, maxpenwidth = 8.0, ) PRINT_COLORMAP = Theme( minfontsize = 18.0, maxfontsize = 30.0, fontcolor = "black", nodestyle = "solid", mincolor = (0.0, 0.0, 0.0), # black maxcolor = (0.0, 0.0, 0.0), # black minpenwidth = 0.1, maxpenwidth = 8.0, ) themes = { "color": TEMPERATURE_COLORMAP, "pink": PINK_COLORMAP, "gray": GRAY_COLORMAP, "bw": BW_COLORMAP, "print": PRINT_COLORMAP, } def sorted_iteritems(d): # Used mostly for result reproducibility (while testing.) keys = compat_keys(d) keys.sort() for key in keys: value = d[key] yield key, value class DotWriter: """Writer for the DOT language. See also: - "The DOT Language" specification http://www.graphviz.org/doc/info/lang.html """ strip = False wrap = False def __init__(self, fp): self.fp = fp def wrap_function_name(self, name): """Split the function name on multiple lines.""" if len(name) > 32: ratio = 2.0/3.0 height = max(int(len(name)/(1.0 - ratio) + 0.5), 1) width = max(len(name)/height, 32) # TODO: break lines in symbols name = textwrap.fill(name, width, break_long_words=False) # Take away spaces name = name.replace(", ", ",") name = name.replace("> >", ">>") name = name.replace("> >", ">>") # catch consecutive return name show_function_events = [TOTAL_TIME_RATIO, TIME_RATIO] show_edge_events = [TOTAL_TIME_RATIO, CALLS] def graph(self, profile, theme): self.begin_graph() fontname = theme.graph_fontname() fontcolor = theme.graph_fontcolor() nodestyle = theme.node_style() self.attr('graph', fontname=fontname, ranksep=0.25, nodesep=0.125) self.attr('node', fontname=fontname, shape="box", style=nodestyle, fontcolor=fontcolor, width=0, height=0) self.attr('edge', fontname=fontname) for _, function in sorted_iteritems(profile.functions): labels = [] if function.process is not None: labels.append(function.process) if function.module is not None: labels.append(function.module) if self.strip: function_name = function.stripped_name() else: function_name = function.name # dot can't parse quoted strings longer than YY_BUF_SIZE, which # defaults to 16K. But some annotated C++ functions (e.g., boost, # https://github.com/jrfonseca/gprof2dot/issues/30) can exceed that MAX_FUNCTION_NAME = 4096 if len(function_name) >= MAX_FUNCTION_NAME: sys.stderr.write('warning: truncating function name with %u chars (%s)\n' % (len(function_name), function_name[:32] + '...')) function_name = function_name[:MAX_FUNCTION_NAME - 1] + unichr(0x2026) if self.wrap: function_name = self.wrap_function_name(function_name) labels.append(function_name) for event in self.show_function_events: if event in function.events: label = event.format(function[event]) labels.append(label) if function.called is not None: labels.append("%u%s" % (function.called, MULTIPLICATION_SIGN)) if function.weight is not None: weight = function.weight else: weight = 0.0 label = '\n'.join(labels) self.node(function.id, label = label, color = self.color(theme.node_bgcolor(weight)), fontcolor = self.color(theme.node_fgcolor(weight)), fontsize = "%.2f" % theme.node_fontsize(weight), tooltip = function.filename, ) for _, call in sorted_iteritems(function.calls): callee = profile.functions[call.callee_id] labels = [] for event in self.show_edge_events: if event in call.events: label = event.format(call[event]) labels.append(label) if call.weight is not None: weight = call.weight elif callee.weight is not None: weight = callee.weight else: weight = 0.0 label = '\n'.join(labels) self.edge(function.id, call.callee_id, label = label, color = self.color(theme.edge_color(weight)), fontcolor = self.color(theme.edge_color(weight)), fontsize = "%.2f" % theme.edge_fontsize(weight), penwidth = "%.2f" % theme.edge_penwidth(weight), labeldistance = "%.2f" % theme.edge_penwidth(weight), arrowsize = "%.2f" % theme.edge_arrowsize(weight), ) self.end_graph() def begin_graph(self): self.write('digraph {\n') def end_graph(self): self.write('}\n') def attr(self, what, **attrs): self.write("\t") self.write(what) self.attr_list(attrs) self.write(";\n") def node(self, node, **attrs): self.write("\t") self.id(node) self.attr_list(attrs) self.write(";\n") def edge(self, src, dst, **attrs): self.write("\t") self.id(src) self.write(" -> ") self.id(dst) self.attr_list(attrs) self.write(";\n") def attr_list(self, attrs): if not attrs: return self.write(' [') first = True for name, value in sorted_iteritems(attrs): if value is None: continue if first: first = False else: self.write(", ") self.id(name) self.write('=') self.id(value) self.write(']') def id(self, id): if isinstance(id, (int, float)): s = str(id) elif isinstance(id, basestring): if id.isalnum() and not id.startswith('0x'): s = id else: s = self.escape(id) else: raise TypeError self.write(s) def color(self, rgb): r, g, b = rgb def float2int(f): if f <= 0.0: return 0 if f >= 1.0: return 255 return int(255.0*f + 0.5) return "#" + "".join(["%02x" % float2int(c) for c in (r, g, b)]) def escape(self, s): if not PYTHON_3: s = s.encode('utf-8') s = s.replace('\\', r'\\') s = s.replace('\n', r'\n') s = s.replace('\t', r'\t') s = s.replace('"', r'\"') return '"' + s + '"' def write(self, s): self.fp.write(s) ######################################################################## # Main program def naturalJoin(values): if len(values) >= 2: return ', '.join(values[:-1]) + ' or ' + values[-1] else: return ''.join(values) def main(): """Main program.""" global totalMethod formatNames = list(formats.keys()) formatNames.sort() optparser = optparse.OptionParser( usage="\n\t%prog [options] [file] ...") optparser.add_option( '-o', '--output', metavar='FILE', type="string", dest="output", help="output filename [stdout]") optparser.add_option( '-n', '--node-thres', metavar='PERCENTAGE', type="float", dest="node_thres", default=0.5, help="eliminate nodes below this threshold [default: %default]") optparser.add_option( '-e', '--edge-thres', metavar='PERCENTAGE', type="float", dest="edge_thres", default=0.1, help="eliminate edges below this threshold [default: %default]") optparser.add_option( '-f', '--format', type="choice", choices=formatNames, dest="format", default="prof", help="profile format: %s [default: %%default]" % naturalJoin(formatNames)) optparser.add_option( '--total', type="choice", choices=('callratios', 'callstacks'), dest="totalMethod", default=totalMethod, help="preferred method of calculating total time: callratios or callstacks (currently affects only perf format) [default: %default]") optparser.add_option( '-c', '--colormap', type="choice", choices=('color', 'pink', 'gray', 'bw', 'print'), dest="theme", default="color", help="color map: color, pink, gray, bw, or print [default: %default]") optparser.add_option( '-s', '--strip', action="store_true", dest="strip", default=False, help="strip function parameters, template parameters, and const modifiers from demangled C++ function names") optparser.add_option( '--color-nodes-by-selftime', action="store_true", dest="color_nodes_by_selftime", default=False, help="color nodes by self time, rather than by total time (sum of self and descendants)") optparser.add_option( '--colour-nodes-by-selftime', action="store_true", dest="color_nodes_by_selftime", help=optparse.SUPPRESS_HELP) optparser.add_option( '-w', '--wrap', action="store_true", dest="wrap", default=False, help="wrap function names") optparser.add_option( '--show-samples', action="store_true", dest="show_samples", default=False, help="show function samples") # add option to create subtree or show paths optparser.add_option( '-z', '--root', type="string", dest="root", default="", help="prune call graph to show only descendants of specified root function") optparser.add_option( '-l', '--leaf', type="string", dest="leaf", default="", help="prune call graph to show only ancestors of specified leaf function") optparser.add_option( '--depth', type="int", dest="depth", default=-1, help="prune call graph to show only descendants or ancestors until specified depth") # add a new option to control skew of the colorization curve optparser.add_option( '--skew', type="float", dest="theme_skew", default=1.0, help="skew the colorization curve. Values < 1.0 give more variety to lower percentages. Values > 1.0 give less variety to lower percentages") # add option for filtering by file path optparser.add_option( '-p', '--path', action="append", type="string", dest="filter_paths", help="Filter all modules not in a specified path") (options, args) = optparser.parse_args(sys.argv[1:]) if len(args) > 1 and options.format != 'pstats': optparser.error('incorrect number of arguments') try: theme = themes[options.theme] except KeyError: optparser.error('invalid colormap \'%s\'' % options.theme) # set skew on the theme now that it has been picked. if options.theme_skew: theme.skew = options.theme_skew totalMethod = options.totalMethod try: Format = formats[options.format] except KeyError: optparser.error('invalid format \'%s\'' % options.format) if Format.stdinInput: if not args: fp = sys.stdin elif PYTHON_3: fp = open(args[0], 'rt', encoding='UTF-8') else: fp = open(args[0], 'rt') parser = Format(fp) elif Format.multipleInput: if not args: optparser.error('at least a file must be specified for %s input' % options.format) parser = Format(*args) else: if len(args) != 1: optparser.error('exactly one file must be specified for %s input' % options.format) parser = Format(args[0]) profile = parser.parse() if options.output is None: if PYTHON_3: output = open(sys.stdout.fileno(), mode='wt', encoding='UTF-8', closefd=False) else: output = sys.stdout else: if PYTHON_3: output = open(options.output, 'wt', encoding='UTF-8') else: output = open(options.output, 'wt') dot = DotWriter(output) dot.strip = options.strip dot.wrap = options.wrap if options.show_samples: dot.show_function_events.append(SAMPLES) profile = profile profile.prune(options.node_thres/100.0, options.edge_thres/100.0, options.filter_paths, options.color_nodes_by_selftime) if options.root: rootIds = profile.getFunctionIds(options.root) if not rootIds: sys.stderr.write('root node ' + options.root + ' not found (might already be pruned : try -e0 -n0 flags)\n') sys.exit(1) profile.prune_root(rootIds, options.depth) if options.leaf: leafIds = profile.getFunctionIds(options.leaf) if not leafIds: sys.stderr.write('leaf node ' + options.leaf + ' not found (maybe already pruned : try -e0 -n0 flags)\n') sys.exit(1) profile.prune_leaf(leafIds, options.depth) dot.graph(profile, theme) if __name__ == '__main__': main() ================================================ FILE: scripts/run.py ================================================ #!/usr/bin/env python3 import argparse import os import datetime from run_base import * # constants binary = 'iccad19gr' # argparse parser = argparse.ArgumentParser() parser.add_argument('benchmarks', choices=all_benchmarks.get_choices(), nargs='+', metavar='BENCHMARK', help='Choices are ' + ', '.join(all_benchmarks.get_choices())) parser.add_argument('-m', '--mode', choices=modes) parser.add_argument( '-s', '--steps', choices=['route', 'eval', 'view'], nargs='+', default=['route']) parser.add_argument('-p', '--benchmark_path') parser.add_argument('-t', '--threads', type=int, default=8) args = parser.parse_args() # seleted benchmarks bms = all_benchmarks.get_selected(args.benchmarks) bm_path = args.benchmark_path if bm_path is None: bm_path = os.environ.get('BENCHMARK_PATH') if bm_path is None: print('Benchmark path is not specified.') quit() # mode cmd_prefix cmd_prefix = mode_prefixes[args.mode] if args.mode == 'valgrind': print('Please make sure the binary is not compiled with static linking to avoid false alarm') # run if True: now = datetime.datetime.now() log_dir = 'run{:02d}{:02d}'.format(now.month, now.day) run('mkdir -p {}'.format(log_dir)) print('The following benchmarks will be ran: ', bms) def route(): guide_file = '{0}/{1}.solution.guide'.format(bm_log_dir, bm.full_name) log_file = '{0}/{1}.log'.format(bm_log_dir, bm.full_name) run('{cmd_prefix} ./{0} -lef {1}.input.lef -def {1}.input.def -threads {2} -output {3} |& tee {4}'.format( binary, file_name_prefix, args.threads, guide_file, log_file, cmd_prefix=cmd_prefix)) if args.mode == 'gprof': run('gprof {} > {}.gprof'.format(binary, bm.full_name)) run('./gprof2dot.py -s {0}.gprof | dot -Tpdf -o {0}.pdf'.format(bm.full_name)) run('mv *.solution.guide* *.log *.gprof *.pdf {} 2>/dev/null'.format(bm_log_dir)) def evaluate(): guide_file = '{0}/{1}.solution.guide'.format(bm_log_dir, bm.full_name) sol_file = '{0}/{1}.solution.def'.format(bm_log_dir, bm.full_name) dr_log_file = '{0}/{1}_dr_eval.log'.format(bm_log_dir, bm.full_name) log_file = '{0}/{1}_eval.log'.format(bm_log_dir, bm.full_name) dr_file = 'drcu' bm_yy = int(bm.full_name[4:6]) run('cp ispd{0}eval/ispd{0}eval* ./'.format(bm_yy)) def evaluate_once(): run('./{0} -lef {1}.input.lef -def {1}.input.def -guide {2} -threads {3} -tat 2000000000 -output {4} |& tee {5}'.format( dr_file, file_name_prefix, guide_file, args.threads, sol_file, dr_log_file)) if bm_yy == 18: run('./ispd{0}eval.sh -lef {1}.input.lef -guide {2} -def {3} -thread {4} |& tee {5}'.format( bm_yy, file_name_prefix, guide_file, sol_file, args.threads, log_file)) else: run('./ispd{0}eval.sh -lef {1}.input.lef -guide {2} -idef {1}.input.def -odef {3} -thread {4} |& tee {5}'.format( bm_yy, file_name_prefix, guide_file, sol_file, args.threads, log_file)) evaluate_once() run('rm ispd{0}eval_bin ispd{0}eval.sh ispd{0}eval.tcl ispd{0}eval.w *.def.v eval.def'.format(bm_yy)) run('mv *.log innovus.* *.solution.def* eval.*.rpt {} 2>/dev/null'.format(bm_log_dir)) def view(): file = open("tmp.tcl", "w") file.write("loadLefFile {}.input.lef\n".format(file_name_prefix)) file.write("loadDefFile {}/{}.solution.def\n".format(bm_log_dir, bm.full_name)) file.write("setMultiCpuUsage -localCpu {}\n".format(args.threads)) file.write("win\n") file.close() run('innovus -init tmp.tcl') run('rm innovus.* *.drc.rpt *.solution.def.v tmp.tcl') for bm in bms: bm_log_dir = '{}/{}'.format(log_dir, bm.abbr_name) file_name_prefix = '{0}/iccad2019c/{1}/{1}'.format(bm_path, bm.full_name) run('mkdir -p {}'.format(bm_log_dir)) if 'route' in args.steps: route() if 'eval' in args.steps: evaluate() if 'view' in args.steps: view() ================================================ FILE: scripts/run_base.py ================================================ import os # run command def run(command): print(command) os.system('/bin/bash -c \'{0}\''.format(command)) # run modes modes = ['gdb', 'valgrind', 'vgdb', 'gprof'] mode_prefixes = { None : '', 'gprof' : '', 'gdb' : 'gdb --args', 'valgrind' : 'valgrind', 'vgdb' : 'valgrind --vgdb-error=0' } # benchmarks class Benchmark: def __init__(self, full_name, abbr_name): self.full_name = full_name self.abbr_name = abbr_name def __repr__(self): return self.full_name class Benchmarks: def __init__(self): self.__bms = [] self.__bm_sets = dict() def add(self, full_name_pat, abbr_name_pat, ids): for id in ids: self.__bms.append(Benchmark(full_name_pat.format(id), abbr_name_pat.format(id))) def get_bm(self, name): # TODO: can be faster by using hash table for bm in self.__bms: if name == bm.abbr_name or name == bm.full_name: return bm print('Error: benchmark', name, 'cannot be found') quit() def add_set(self, set_name, bm_names): bms = [] for name in bm_names: bms.append(self.get_bm(name)) self.__bm_sets[set_name] = bms def get_choices(self): choices = [] for bm in self.__bms: choices.append(bm.full_name) choices.append(bm.abbr_name) for bm_set in self.__bm_sets: choices.append(bm_set) choices.append('all') return choices def get_selected(self, names): if 'all' in names: return self.__bms else: selected = [] for name in names: if name in self.__bm_sets: selected += self.__bm_sets[name] else: selected.append(self.get_bm(name)) return selected ###################################### # Below is project-dependant setting # ###################################### # all benchmarks all_benchmarks = Benchmarks() all_benchmarks.add('ispd18_test{}', '8t{}', ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']) all_benchmarks.add('ispd19_test{}', '9t{}', ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']) all_benchmarks.add('ispd18_test{}_metal5', '8t{}m', ['5', '8', '10']) all_benchmarks.add('ispd19_test{}_metal5', '9t{}m', ['7', '8', '9']) all_benchmarks.add_set('contest', ['8t5', '8t8', '8t10', '9t7', '9t8', '9t9', '8t5m', '8t8m', '8t10m', '9t7m', '9t8m', '9t9m']) all_benchmarks.add_set('all18', ['8t1', '8t2', '8t3', '8t4', '8t5', '8t6', '8t7', '8t8', '8t9', '8t10', '8t5m', '8t8m', '8t10m']) all_benchmarks.add_set('all19', ['9t1', '9t2', '9t3', '9t4', '9t5', '9t6', '9t7', '9t8', '9t9', '9t10', '9t7m', '9t8m', '9t9m']) ================================================ FILE: src/.clang-format ================================================ BasedOnStyle: Google IndentWidth: 4 AccessModifierOffset: -4 BinPackArguments: false BinPackParameters: false ColumnLimit: 120 SortIncludes: false ================================================ FILE: src/CMakeLists.txt ================================================ ######### # Setup # ######### # Specify the minimum version for CMake cmake_minimum_required(VERSION 2.8) # Message message(STATUS "ICCAD19 GR CUHK") message(STATUS ${CMAKE_CURRENT_SOURCE_DIR}) message(STATUS ${PROJECT_SOURCE_DIR}) # Find includes in the build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) # Project's name project(iccad19gr) # Set the output folder where your program will be created set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}) set(CMAKE_CXX_STANDARD 14) set(PATH_RSYN ${CMAKE_CURRENT_SOURCE_DIR}/../rsyn) set(PATH_ICCAD19 ${CMAKE_CURRENT_SOURCE_DIR}) ################### # Warnings/Errors # ################### set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-type") ###################### # Check Dependencies # ###################### # uncommment this line if you are using self-compiled boost lib set(Boost_USE_STATIC_LIBS ON) find_package(Boost COMPONENTS system filesystem program_options REQUIRED) # find_package(Threads) ############### # Source Code # ############### file(GLOB_RECURSE SRC_FILES_RSYN ${PATH_RSYN}/src/*.cpp ${PATH_RSYN}/src/*.cc ${PATH_RSYN}/src/*.c) file(GLOB_RECURSE SRC_FILES_ICCAD19 ${PATH_ICCAD19}/*.cpp ${PATH_ICCAD19}/*.c) set(SRC_FILES ${SRC_FILES_RSYN} ${SRC_FILES_ICCAD19}) ################# # Library Paths # ################# # Need to come before target is created. if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") link_directories(${PATH_RSYN}/lib/linux) endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") link_directories(${PATH_RSYN}/lib/macosx) endif() ########### # Targets # ########### add_executable(iccad19gr ${SRC_FILES}) ####################### # Include Directories # ####################### include_directories(${PATH_RSYN}/src) include_directories(${PATH_RSYN}/src/rsyn/export) include_directories(${PATH_RSYN}/include) include_directories(${PATH_ICCAD19}) ################# # Linker Flags # ################# # TODO: set static under release mode only set_target_properties(iccad19gr PROPERTIES LINK_FLAGS "-static -Wl,--whole-archive -rdynamic -lpthread -Wl,--no-whole-archive") # LEF/DEF target_link_libraries(iccad19gr lef) target_link_libraries(iccad19gr def) # Boost target_include_directories(iccad19gr PUBLIC ${Boost_INCLUDE_DIR}) target_link_libraries(iccad19gr ${Boost_LIBRARIES}) ================================================ FILE: src/db/CutLayer.cpp ================================================ #include "CutLayer.h" #include "Setting.h" namespace db { ViaType::ViaType(Rsyn::PhysicalVia rsynVia) { if (rsynVia.allCutGeometries().size() > 1) hasMultiCut = true; bot = getBoxFromRsynGeometries(rsynVia.allBottomGeometries()); cut = getBoxFromRsynGeometries(rsynVia.allCutGeometries()); top = getBoxFromRsynGeometries(rsynVia.allTopGeometries()); name = rsynVia.getName(); if (rsynVia.hasRowCol()) { const DBU xBotEnc = rsynVia.getEnclosure(Rsyn::BOTTOM_VIA_LEVEL, X); const DBU yBotEnc = rsynVia.getEnclosure(Rsyn::BOTTOM_VIA_LEVEL, Y); const DBU xTopEnc = rsynVia.getEnclosure(Rsyn::TOP_VIA_LEVEL, X); const DBU yTopEnc = rsynVia.getEnclosure(Rsyn::TOP_VIA_LEVEL, Y); const int numRows = rsynVia.getNumRows(); const int numCols = rsynVia.getNumCols(); const DBU xCut = (rsynVia.getCutSize(X) * numCols + rsynVia.getSpacing(X) * (numCols - 1) + 1) / 2; const DBU yCut = (rsynVia.getCutSize(Y) * numRows + rsynVia.getSpacing(Y) * (numRows - 1) + 1) / 2; bot = {-xCut - xBotEnc, -yCut - yBotEnc, xCut + xBotEnc, yCut + yBotEnc}; cut = {-xCut, -yCut, xCut, yCut}; top = {-xCut - xTopEnc, -yCut - yTopEnc, xCut + xTopEnc, yCut + yTopEnc}; } if (!bot.IsStrictValid() || !cut.IsStrictValid() || !top.IsStrictValid()) { log() << "Warning in " << __func__ << ": For " << rsynVia.getName() << " , has non strict valid via layer bound... " << std::endl; } } std::tuple ViaType::getDefaultScore(const Dimension botDim, const Dimension topDim) const { return std::tuple(bot[botDim].range(), // belowWidth top[topDim].range(), // aboveWidth bot[1 - botDim].range(), // belowWidth top[1 - topDim].range()); // aboveLength } utils::BoxT ViaType::getShiftedBotMetal(const utils::PointT& viaPos) const { utils::BoxT metal = bot; metal.ShiftBy(viaPos); return metal; } utils::BoxT ViaType::getShiftedTopMetal(const utils::PointT& viaPos) const { utils::BoxT metal = top; metal.ShiftBy(viaPos); return metal; } CutLayer::CutLayer(const Rsyn::PhysicalLayer& rsynLayer, const vector& rsynVias, const Dimension botDim, const Dimension topDim, const DBU libDBU) : name(rsynLayer.getName()), idx(rsynLayer.getRelativeIndex()), width(rsynLayer.getWidth()) { // Rsyn::PhysicalLayer (LEF) const lefiLayer* layer = rsynLayer.getLayer(); if (!layer->hasSpacingNumber() || !layer->numSpacing()) { log() << "Error in " << __func__ << ": For " << rsynLayer.getName() << " CutLayer::init, rsynSpacingRule is empty, init all rules with default 0... " << std::endl; } else { spacing = static_cast(std::round(layer->spacing(0) * libDBU)); } delete rsynLayer.getLayer(); // Rsyn::PhysicalVia (LEF) if (rsynVias.empty()) { log() << "Error in " << __func__ << ": For " << name << " rsynVias is empty... " << std::endl; } int defaultViaTypeIdx = -1; const DBU dbuMax = std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : std::numeric_limits::max(); std::tuple bestScore(dbuMax, dbuMax, dbuMax, dbuMax); for (const Rsyn::PhysicalVia& rsynVia : rsynVias) { if (rsynVia.isViaDesign()) continue; if ((rsynVia.allBottomGeometries().size() != 1 || rsynVia.allCutGeometries().size() != 1 || rsynVia.allTopGeometries().size() != 1)) { if (setting.dbVerbose >= +VerboseLevelT::MIDDLE) { log() << "Warning in " << __func__ << ": For " << rsynVia.getName() << " , has not exactly one metal layer bound or more than one cut layer bound... " << std::endl; } continue; } allViaTypes.emplace_back(rsynVia); const std::tuple& score = allViaTypes.back().getDefaultScore(botDim, topDim); if (score < bestScore) { bestScore = score; defaultViaTypeIdx = allViaTypes.size() - 1; } } if (defaultViaTypeIdx == -1) { log() << "Error in " << __func__ << ": For " << name << " all rsyn vias have not exactly one via bound... " << std::endl; } // make default via the first one if (defaultViaTypeIdx > 0) { std::swap(allViaTypes[0], allViaTypes[defaultViaTypeIdx]); } // init ViaType::idx for (unsigned i = 0; i != allViaTypes.size(); ++i) { allViaTypes[i].idx = i; } } ostream& CutLayer::printBasics(ostream& os) const { os << name << ": idx=" << idx << ", viaTypes=" << defaultViaType().name << " ("; for (auto via : allViaTypes) { if (via.name != defaultViaType().name) { os << via.name << " "; } } os << ")"; return os; } ostream& CutLayer::printDesignRules(ostream& os) const { os << name << ": width=" << width << ", space=" << spacing; return os; } ostream& CutLayer::printViaOccupancyLUT(ostream& os) const { os << name << ": viaCut(" << viaCut().size() / 2 + 1 << ',' << viaCut()[0].size() / 2 + 1 << ")"; os << ", viaMetal(" << viaMetal().size() / 2 + 1 << ',' << viaMetal()[0].size() / 2 + 1 << ")"; // TODO: make xSize member variables, since they will be the same in a LUT over all cps auto getMaxSize = [](const vector>>& LUT, size_t& xSize, size_t& ySize) { xSize = 0; ySize = 0; for (const vector>& cpLUT : LUT) { if (cpLUT.size()) { xSize = max(xSize, cpLUT.size()); ySize = max(ySize, cpLUT[0].size()); } } }; size_t xSize, ySize; os << ", viaBotVia("; if (defaultViaType().allViaBotVia.size()) { getMaxSize(viaBotVia(), xSize, ySize); os << viaBotVia().size() << ',' << xSize << ',' << ySize << ")"; } else os << "-,-,-)"; os << ", viaTopVia("; if (defaultViaType().allViaTopVia.size()) { getMaxSize(viaTopVia(), xSize, ySize); os << viaTopVia().size() << ',' << xSize << ',' << ySize << ")"; } else os << "-,-,-)"; getMaxSize(viaBotWire(), xSize, ySize); os << ", viaBotWire(" << viaBotWire().size() << ',' << xSize << ',' << ySize << ")"; getMaxSize(viaTopWire(), xSize, ySize); os << ", viaTopWire(" << viaTopWire().size() << ',' << xSize << ',' << ySize << ")"; return os; } ostream& operator<<(ostream& os, const CutLayer& layer) { return layer.printBasics(os); } } // namespace db ================================================ FILE: src/db/CutLayer.h ================================================ #pragma once #include "GeoPrimitive.h" namespace db { class ViaType { public: bool hasMultiCut = false; utils::BoxT bot; // box on bottom metal layer utils::BoxT top; // box on top metal layer utils::BoxT cut; // box on cut layer std::string name; int idx; vector> botForbidRegions; vector> topForbidRegions; // via-wire conflict (crossPointIdx, trackIdx, crossPointIdx) vector>> viaBotWire; vector>> viaTopWire; // same-layer via-via conflict (viaTypeIdx, lowerTrackIdx, upperTrackIdx) // TODO: remove allViaMetal, rename allViaMetalNum to allViaMetal vector>> allViaCut; // due to cut spacing vector>> allViaMetal; // due to metal spacing vector>> allViaMetalNum; // due to metal spacing, integer version // cross-layer via-via conflict (viaTypeIdx, crossPointIdx, trackIdx, crossPointIdx) vector>>> allViaBotVia; vector>>> allViaTopVia; // merged LUTs vector> mergedAllViaMetal; vector>> mergedAllViaBotVia; vector>> mergedAllViaTopVia; ViaType() {} ViaType(Rsyn::PhysicalVia rsynVia); // alphabetical score tuple (belowWidth, aboveWidth, belowLength, aboveLength) std::tuple getDefaultScore(const Dimension botDim, const Dimension topDim) const; // shifted bot/top metal utils::BoxT getShiftedBotMetal(const utils::PointT& viaPos) const; utils::BoxT getShiftedTopMetal(const utils::PointT& viaPos) const; }; class CutLayer { public: CutLayer(const Rsyn::PhysicalLayer& rsynLayer, const vector& rsynVias, const Dimension botDim, const Dimension topDim, const DBU libDBU); // Basic infomation std::string name; int idx; // layerIdx (consistent with Rsyn::xxx::getRelativeIndex()) // Design rules DBU width = 0; DBU spacing = 0; // Via types vector allViaTypes; const ViaType& defaultViaType() const { return allViaTypes[0]; } bool isDefaultViaType(const ViaType& viaType) const { return viaType.idx == defaultViaType().idx; } utils::BoxT topMaxForbidRegion; utils::BoxT botMaxForbidRegion; // Via conflict lookup table (true means "not available" / with conflict) // 1. same-layer via-via conflict (lowerTrackIdx, upperTrackIdx) // due to cut spacing const vector>& viaCut() const { return defaultViaType().allViaCut[0]; } // due to metal spacing const vector>& viaMetal() const { return defaultViaType().allViaMetal[0]; } const vector>& viaMetalNum() const { return defaultViaType().allViaMetalNum[0]; } // 2. via-via conflict (crossPointIdx, trackIdx, crossPointIdx) const vector>>& viaBotVia() const { return defaultViaType().allViaBotVia[0]; } const vector>>& viaTopVia() const { return defaultViaType().allViaTopVia[0]; } // 3. via-wire conflict (crossPointIdx, trackIdx, crossPointIdx) const vector>>& viaBotWire() const { return defaultViaType().viaBotWire; } const vector>>& viaTopWire() const { return defaultViaType().viaTopWire; } ostream& printBasics(ostream& os) const; ostream& printDesignRules(ostream& os) const; ostream& printViaOccupancyLUT(ostream& os) const; friend ostream& operator<<(ostream& os, const CutLayer& layer); }; } // namespace db ================================================ FILE: src/db/Database.cpp ================================================ #include "Database.h" #include "rsyn/io/parser/lef_def/DEFControlParser.h" db::Database database; namespace db { void Database::init() { log() << std::endl; log() << "################################################################" << std::endl; log() << "Start initializing database" << std::endl; log() << std::endl; rsynService.init(); auto dieBound = rsynService.physicalDesign.getPhysicalDie().getBounds(); dieRegion = getBoxFromRsynBounds(dieBound); if (setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { log() << "Die region (in DBU): " << dieRegion << std::endl; log() << std::endl; } RouteGrid::init(); NetList::init(rsynService); markPinAndObsOccupancy(); initMTSafeMargin(); log() << "Finish initializing database" << std::endl; log() << "MEM: cur=" << utils::mem_use::get_current() << "MB, peak=" << utils::mem_use::get_peak() << "MB" << std::endl; log() << std::endl; } void Database::markPinAndObsOccupancy() { if (db::setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { log() << "Mark pin & obs occupancy on RouteGrid ..." << std::endl; } vector> fixedMetalVec; // STEP 1: get fixed objects // Mark pins associated with nets for (const auto& net : nets) { for (const auto& accessBoxes : net.pinAccessBoxes) { for (const auto& box : accessBoxes) { fixedMetalVec.emplace_back(box, net.idx); } } } // Mark dangling pins // minor TODO: port? const Rsyn::Session session; const Rsyn::PhysicalDesign& physicalDesign = static_cast(session.getService("rsyn.physical"))->getPhysicalDesign(); const DBU libDBU = physicalDesign.getDatabaseUnits(Rsyn::LIBRARY_DBU); unsigned numUnusedPins = 0; unsigned numObs = 0; unsigned numSNetObs = 0; for (Rsyn::Instance instance : rsynService.module.allInstances()) { if (instance.getType() != Rsyn::CELL) continue; // phCell Rsyn::Cell cell = instance.asCell(); Rsyn::PhysicalCell phCell = rsynService.physicalDesign.getPhysicalCell(cell); Rsyn::PhysicalLibraryCell phLibCell = rsynService.physicalDesign.getPhysicalLibraryCell(cell); const DBUxy origin(static_cast(std::round(phLibCell.getMacro()->originX() * libDBU)), static_cast(std::round(phLibCell.getMacro()->originY() * libDBU))); // libPin for (Rsyn::Pin pin : instance.allPins(false)) { if (!pin.getNet()) { // no associated net Rsyn::PhysicalLibraryPin phLibPin = rsynService.physicalDesign.getPhysicalLibraryPin(pin); vector accessBoxes; Net::getPinAccessBoxes(phLibPin, phCell, accessBoxes, origin); for (const auto& box : accessBoxes) { fixedMetalVec.emplace_back(box, OBS_NET_IDX); } ++numUnusedPins; } } // libObs DBUxy displacement = phCell.getPosition() + origin; auto transform = phCell.getTransform(); for (const Rsyn::PhysicalObstacle& phObs : phLibCell.allObstacles()) { if (phObs.getLayer().getType() != Rsyn::PhysicalLayerType::ROUTING) continue; const int layerIdx = phObs.getLayer().getRelativeIndex(); for (auto bounds : phObs.allBounds()) { bounds.translate(displacement); bounds = transform.apply(bounds); const BoxOnLayer box(layerIdx, getBoxFromRsynBounds(bounds)); fixedMetalVec.emplace_back(box, OBS_NET_IDX); ++numObs; } } } // Mark special nets for (Rsyn::PhysicalSpecialNet specialNet : rsynService.physicalDesign.allPhysicalSpecialNets()) { for (const DefWireDscp& wire : specialNet.getNet().clsWires) { for (const DefWireSegmentDscp& segment : wire.clsWireSegments) { int layerIdx = rsynService.physicalDesign.getPhysicalLayerByName(segment.clsLayerName).getRelativeIndex(); const DBU width = segment.clsRoutedWidth; DBUxy pos; DBU ext = 0; for (unsigned i = 0; i != segment.clsRoutingPoints.size(); ++i) { const DefRoutingPointDscp& pt = segment.clsRoutingPoints[i]; const DBUxy& nextPos = pt.clsPos; const DBU nextExt = pt.clsHasExtension ? pt.clsExtension : 0; if (i >= 1) { for (unsigned dim = 0; dim != 2; ++dim) { if (pos[dim] == nextPos[dim]) continue; const DBU l = pos[dim] < nextPos[dim] ? pos[dim] - ext : nextPos[dim] - nextExt; const DBU h = pos[dim] < nextPos[dim] ? nextPos[dim] + nextExt : pos[dim] + ext; BoxOnLayer box(layerIdx); box[dim].Set(l, h); box[1 - dim].Set(pos[1 - dim] - width / 2, pos[1 - dim] + width / 2); fixedMetalVec.emplace_back(box, OBS_NET_IDX); ++numSNetObs; break; } } pos = nextPos; ext = nextExt; if (!pt.clsHasVia) continue; const Rsyn::PhysicalVia& via = rsynService.physicalDesign.getPhysicalViaByName(pt.clsViaName); const int botLayerIdx = via.getBottomLayer().getRelativeIndex(); for (const Rsyn::PhysicalViaGeometry& geo : via.allBottomGeometries()) { Bounds bounds = geo.getBounds(); bounds.translate(pos); const BoxOnLayer box(botLayerIdx, getBoxFromRsynBounds(bounds)); fixedMetalVec.emplace_back(box, OBS_NET_IDX); ++numSNetObs; } const int topLayerIdx = via.getTopLayer().getRelativeIndex(); for (const Rsyn::PhysicalViaGeometry& geo : via.allTopGeometries()) { Bounds bounds = geo.getBounds(); bounds.translate(pos); const BoxOnLayer box(topLayerIdx, getBoxFromRsynBounds(bounds)); fixedMetalVec.emplace_back(box, OBS_NET_IDX); ++numSNetObs; } if (via.hasViaRule()) { const utils::PointT numRowCol = via.hasRowCol() ? utils::PointT(via.getNumCols(), via.getNumRows()) : utils::PointT(1, 1); BoxOnLayer botBox(botLayerIdx); BoxOnLayer topBox(topLayerIdx); for (unsigned dimIdx = 0; dimIdx != 2; ++dimIdx) { const Dimension dim = static_cast(dimIdx); const DBU origin = via.hasOrigin() ? pos[dim] + via.getOrigin(dim) : pos[dim]; const DBU botOff = via.hasOffset() ? origin + via.getOffset(Rsyn::BOTTOM_VIA_LEVEL, dim) : origin; const DBU topOff = via.hasOffset() ? origin + via.getOffset(Rsyn::TOP_VIA_LEVEL, dim) : origin; const DBU length = (via.getCutSize(dim) * numRowCol[dim] + via.getSpacing(dim) * (numRowCol[dim] - 1)) / 2; const DBU botEnc = length + via.getEnclosure(Rsyn::BOTTOM_VIA_LEVEL, dim); const DBU topEnc = length + via.getEnclosure(Rsyn::TOP_VIA_LEVEL, dim); botBox[dim].Set(botOff - botEnc, botOff + botEnc); topBox[dim].Set(topOff - topEnc, topOff + topEnc); } fixedMetalVec.emplace_back(botBox, OBS_NET_IDX); fixedMetalVec.emplace_back(topBox, OBS_NET_IDX); numSNetObs += 2; } if (layerIdx == botLayerIdx) layerIdx = topLayerIdx; else if (layerIdx == topLayerIdx) layerIdx = botLayerIdx; else { log() << "Error: Special net " << specialNet.getNet().clsName << " via " << pt.clsViaName << " on wrong layer " << layerIdx << std::endl; break; } } } } } // Stat vector layerNumFixedObjects(getLayerNum(), 0); for (const auto& fixedMetal : fixedMetalVec) { layerNumFixedObjects[fixedMetal.first.layerIdx]++; } // Print if (setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { log() << "The number of unused pins is " << numUnusedPins << std::endl; log() << "The number of OBS is " << numObs << std::endl; log() << "The number of special net OBS is " << numSNetObs << std::endl; log() << "The number of fixed objects on each layers:" << std::endl; for (unsigned i = 0; i < getLayerNum(); i++) { if (layerNumFixedObjects[i] > 0) log() << getLayer(i).name << ": " << layerNumFixedObjects[i] << std::endl; } } log() << std::endl; // STEP 2: mark if (setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { printlog("mark fixed metal rtrees..."); } markFixedMetalBatch(fixedMetalVec, 0, fixedMetalVec.size()); } void Database::initMTSafeMargin() { for (auto& layer : layers) { layer.mtSafeMargin = max({layer.minAreaMargin, layer.confLutMargin, layer.fixedMetalQueryMargin}); if (db::setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { printlog(layer.name, "mtSafeMargin = max {", layer.minAreaMargin, layer.confLutMargin, layer.fixedMetalQueryMargin, "} =", layer.mtSafeMargin); } } } void Database::getGridPinAccessBoxes(const Net& net, vector>& gridPinAccessBoxes) const { gridPinAccessBoxes.resize(net.numOfPins()); for (unsigned pinIdx = 0; pinIdx != net.numOfPins(); ++pinIdx) { vector> pins(getLayerNum()); for (const db::BoxOnLayer& pinAccessBox : net.pinAccessBoxes[pinIdx]) { int dir = getLayerDir(pinAccessBox.layerIdx); DBU pitch = getLayer(pinAccessBox.layerIdx).pitch; // pinForbidRegion auto pinForbidRegion = getMetalRectForbidRegion(pinAccessBox, AggrParaRunSpace::DEFAULT); const db::GridBoxOnLayer& gridPinForbidRegion = rangeSearch(pinForbidRegion); if (isValid(gridPinForbidRegion)) { pins[pinAccessBox.layerIdx].push_back(gridPinForbidRegion); } // One-pitch extension auto pinExtension = pinAccessBox; for (int d = 0; d < 2; ++d) { pinExtension[d].low -= pitch; pinExtension[d].high += pitch; } const db::GridBoxOnLayer& gridPinExtension = rangeSearch(pinExtension); for (int trackIdx = gridPinExtension.trackRange.low; trackIdx <= gridPinExtension.trackRange.high; ++trackIdx) { for (int cpIdx = gridPinExtension.crossPointRange.low; cpIdx <= gridPinExtension.crossPointRange.high; ++cpIdx) { db::GridPoint pt(pinAccessBox.layerIdx, trackIdx, cpIdx); if (!gridPinForbidRegion.includePoint(pt) && Dist(pinAccessBox, getLoc(pt)) <= pitch) { pins[pinAccessBox.layerIdx].emplace_back(pinAccessBox.layerIdx, utils::IntervalT{trackIdx, trackIdx}, utils::IntervalT{cpIdx, cpIdx}); } } } } // assign a relatively far grid access box if none (rarely happen) unsigned numBoxes = 0; for (const vector& pin : pins) { numBoxes += pin.size(); } if (!numBoxes) { for (const db::BoxOnLayer& pinAccessBox : net.pinAccessBoxes[pinIdx]) { db::GridBoxOnLayer gridBox = rangeSearch(pinAccessBox); if (gridBox.trackRange.low > gridBox.trackRange.high) { if (gridBox.trackRange.low == 0) { gridBox.trackRange.high = 0; } else { gridBox.trackRange.low = gridBox.trackRange.high; } } if (gridBox.crossPointRange.low > gridBox.crossPointRange.high) { if (gridBox.crossPointRange.low == 0) { gridBox.crossPointRange.high = 0; } else { gridBox.crossPointRange.low = gridBox.crossPointRange.high; } } pins[pinAccessBox.layerIdx].push_back(gridBox); } } // slice gridPinAccessBoxes[pinIdx].clear(); for (vector& pin : pins) { if (!pin.empty()) { db::GridBoxOnLayer::sliceGridPolygons(pin); for (const db::GridBoxOnLayer& box : pin) { if (isValid(box)) { gridPinAccessBoxes[pinIdx].push_back(box); } } } } if (gridPinAccessBoxes[pinIdx].empty()) { log() << "Error: Net " << net.getName() << " Pin " << pinIdx << " has empty grid pin access boxes\n"; } } } } // namespace db MTStat runJobsMT(int numJobs, const std::function& handle) { int numThreads = min(numJobs, db::setting.numThreads); MTStat mtStat(max(1, db::setting.numThreads)); if (numThreads <= 1) { utils::timer threadTimer; for (int i = 0; i < numJobs; ++i) { handle(i); } mtStat.durations[0] = threadTimer.elapsed(); } else { int globalJobIdx = 0; std::mutex mtx; utils::timer threadTimer; auto thread_func = [&](int threadIdx) { int jobIdx; while (true) { mtx.lock(); jobIdx = globalJobIdx++; mtx.unlock(); if (jobIdx >= numJobs) { mtStat.durations[threadIdx] = threadTimer.elapsed(); break; } handle(jobIdx); } }; std::thread threads[numThreads]; for (int i = 0; i < numThreads; i++) { threads[i] = std::thread(thread_func, i); } for (int i = 0; i < numThreads; i++) { threads[i].join(); } } return mtStat; } ================================================ FILE: src/db/Database.h ================================================ #pragma once #include "RsynService.h" #include "RouteGrid.h" #include "Net.h" #include "Setting.h" #include "Stat.h" class MTStat { public: vector durations; MTStat(int numOfThreads = 0) : durations(numOfThreads, 0.0) {} const MTStat& operator+=(const MTStat& rhs); friend ostream& operator<<(ostream& os, const MTStat mtStat); }; namespace db { class Database : public RouteGrid, public NetList { public: utils::BoxT dieRegion; void init(); void clear() { RouteGrid::clear(); } // get girdPinAccessBoxes // TODO: better way to differetiate same-layer and diff-layer girdPinAccessBoxes void getGridPinAccessBoxes(const Net& net, vector>& gridPinAccessBoxes) const; private: RsynService rsynService; // mark pin and obstacle occupancy on RouteGrid void markPinAndObsOccupancy(); // init safe margin for multi-thread void initMTSafeMargin(); }; } // namespace db extern db::Database database; namespace std { // hash function for Dimension template <> struct hash { std::size_t operator()(const Dimension d) const { return (hash()(d)); } }; // hash function for std::tuple template struct hash> { std::size_t operator()(const std::tuple& t) const { return (hash()(std::get<0>(t)) ^ hash()(std::get<1>(t)) ^ hash()(std::get<2>(t))); } }; } // namespace std MTStat runJobsMT(int numJobs, const std::function& handle); ================================================ FILE: src/db/GeoPrimitive.cpp ================================================ #include "GeoPrimitive.h" #include "Database.h" namespace db { // BoxOnLayer bool BoxOnLayer::isConnected(const BoxOnLayer& rhs) const { return abs(rhs.layerIdx - layerIdx) < 2 && HasIntersectWith(rhs); } ostream& operator<<(ostream& os, const BoxOnLayer& box) { os << "box(l=" << box.layerIdx << ", x=" << box[0] << ", y=" << box[1] << ")"; return os; } utils::BoxT getBoxFromRsynBounds(const Bounds& bounds) { return {bounds.getLower().x, bounds.getLower().y, bounds.getUpper().x, bounds.getUpper().y}; } utils::BoxT getBoxFromRsynGeometries(const vector& geos) { utils::BoxT box; for (const Rsyn::PhysicalViaGeometry& geo : geos) { box = box.UnionWith(getBoxFromRsynBounds(geo.getBounds())); } return box; } // GridPoint bool GridPoint::operator==(const GridPoint& rhs) const { return layerIdx == rhs.layerIdx && crossPointIdx == rhs.crossPointIdx && trackIdx == rhs.trackIdx; } bool GridPoint::operator!=(const GridPoint& rhs) const { return layerIdx != rhs.layerIdx || crossPointIdx != rhs.crossPointIdx || trackIdx != rhs.trackIdx; } ostream& operator<<(ostream& os, const GridPoint& gp) { os << "gPt(l=" << gp.layerIdx << ", t=" << gp.trackIdx << ", c=" << gp.crossPointIdx << ")"; return os; } // GridEdge ostream& operator<<(ostream& os, const GridEdge& edge) { os << "gEdge(" << edge.u << " " << edge.v << ")"; return os; } bool GridEdge::isVia() const { const auto& lower = (u.layerIdx <= v.layerIdx) ? u : v; const auto& upper = (u.layerIdx > v.layerIdx) ? u : v; if ((lower.layerIdx + 1) == database.getLayerNum()) { return false; } return database.getUpper(lower) == upper; } bool GridEdge::isTrackSegment() const { return u.layerIdx == v.layerIdx && u.trackIdx == v.trackIdx; } bool GridEdge::isWrongWaySegment() const { return u.layerIdx == v.layerIdx && u.crossPointIdx == v.crossPointIdx; } bool GridEdge::operator==(const GridEdge& rhs) const { return u == rhs.u && v == rhs.v; } // GridBoxOnLayer bool GridBoxOnLayer::operator==(const GridBoxOnLayer& rhs) const { return layerIdx == rhs.layerIdx && trackRange == rhs.trackRange && crossPointRange == rhs.crossPointRange; } ostream& operator<<(ostream& os, const GridBoxOnLayer& gb) { os << "gBox(l=" << gb.layerIdx << ", t=" << gb.trackRange << ", c=" << gb.crossPointRange << ")"; return os; } // slice polygons along sliceDir // sliceDir: 0 for x/vertical, 1 for y/horizontal void GridBoxOnLayer::sliceGridPolygons(vector& boxes) { if (boxes.size() <= 1) return; vector locs; for (const auto& box : boxes) { locs.push_back(box.trackRange.low); locs.push_back(box.trackRange.high); } sort(locs.begin(), locs.end()); locs.erase(unique(locs.begin(), locs.end()), locs.end()); // slice each box vector slicedBoxes; for (const auto& box : boxes) { GridBoxOnLayer slicedBox = box; auto itLoc = lower_bound(locs.begin(), locs.end(), box.trackRange.low); auto itEnd = upper_bound(itLoc, locs.end(), box.trackRange.high); slicedBox.trackRange.Set(*itLoc); slicedBoxes.push_back(slicedBox); // front boundary while ((itLoc + 1) != itEnd) { int left = *itLoc, right = *(itLoc + 1); if ((right - left) > 1) { slicedBox.trackRange.Set(left + 1, right - 1); slicedBoxes.push_back(slicedBox); // middle } slicedBox.trackRange.Set(right); slicedBoxes.push_back(slicedBox); // back boundary ++itLoc; } } boxes = move(slicedBoxes); // merge overlaped boxes over crossPoints utils::MergeRects(boxes, 1); // stitch boxes over tracks utils::MergeRects(boxes, 0); } // TrackSegment ostream& operator<<(ostream& os, const TrackSegment& ts) { os << "tSeg(l=" << ts.layerIdx << ", t" << ts.trackIdx << ", c=" << ts.crossPointRange << ")"; return os; } // ViaBox ostream& operator<<(ostream& os, const ViaBox& vb) { os << "viaBox(lower=" << vb.lower << ", upper=" << vb.upper << ")"; return os; } } // namespace db ================================================ FILE: src/db/GeoPrimitive.h ================================================ #pragma once #include "global.h" namespace db { // BoxOnLayer // A box on a certain layer: primitive for route guide and pin acesss box class BoxOnLayer : public utils::BoxT { public: int layerIdx; // constructors template BoxOnLayer(int layerIndex = -1, Args... params) : layerIdx(layerIndex), utils::BoxT(params...) {} // inherit setters from utils::BoxT in batch template void Set(int layerIndex = -1, Args... params) { layerIdx = layerIndex; utils::BoxT::Set(params...); } bool isConnected(const BoxOnLayer& rhs) const; friend ostream& operator<<(ostream& os, const BoxOnLayer& box); }; // helper utils::BoxT getBoxFromRsynBounds(const Bounds& bounds); utils::BoxT getBoxFromRsynGeometries(const vector& geos); // GridPoint class GridPoint { public: int layerIdx; int trackIdx; int crossPointIdx; GridPoint(int layerIndex = -1, int trackIndex = -1, int crossPointIndex = -1) : layerIdx(layerIndex), trackIdx(trackIndex), crossPointIdx(crossPointIndex) {} bool operator==(const GridPoint& rhs) const; bool operator!=(const GridPoint& rhs) const; friend ostream& operator<<(ostream& os, const GridPoint& gp); }; } // namespace db namespace std { // hash function for GridPoint template <> struct hash { std::size_t operator()(const db::GridPoint& gp) const { return (std::hash()(gp.layerIdx) ^ std::hash()(gp.trackIdx) ^ std::hash()(gp.crossPointIdx)); } }; } // namespace std namespace db { // GridEdge class GridEdge { public: GridPoint u, v; GridEdge(const GridPoint& nodeU, const GridPoint& nodeV) : u(nodeU), v(nodeV) {} // two types of GridEdge: 1. via, 2. track segment bool isVia() const; const GridPoint& lowerGridPoint() const { return u.layerIdx <= v.layerIdx ? u : v; } bool isTrackSegment() const; bool isWrongWaySegment() const; bool operator==(const GridEdge& rhs) const; friend ostream& operator<<(ostream& os, const GridEdge& edge); }; class TrackSegment { public: int layerIdx; int trackIdx; utils::IntervalT crossPointRange; // assume edge.isTrackSegment() TrackSegment(const GridEdge edge) : layerIdx(edge.u.layerIdx), trackIdx(edge.u.trackIdx), crossPointRange(edge.u.crossPointIdx, edge.v.crossPointIdx) { if (!crossPointRange.IsValid()) std::swap(crossPointRange.low, crossPointRange.high); } TrackSegment(int layerIndex, int trackIndex, const utils::IntervalT& crossPointIndexRange) : layerIdx(layerIndex), trackIdx(trackIndex), crossPointRange(crossPointIndexRange) {} friend ostream& operator<<(ostream& os, const TrackSegment& ts); }; // GridBoxOnLayer class GridBoxOnLayer { public: int layerIdx; utils::IntervalT trackRange; utils::IntervalT crossPointRange; GridBoxOnLayer() : layerIdx(-1) {} // default to be invalid GridBoxOnLayer(int layerIndex, const utils::IntervalT& trackIdxRange, const utils::IntervalT& crossPointIdxRange) : layerIdx(layerIndex), trackRange(trackIdxRange), crossPointRange(crossPointIdxRange) {} bool includePoint(const GridPoint& point) const { return layerIdx == point.layerIdx && trackRange.Contain(point.trackIdx) && crossPointRange.Contain(point.crossPointIdx); } // slice polygons along sliceDir // sliceDir: 0 for x/vertical, 1 for y/horizontal // assume boxes are on the same layer static void sliceGridPolygons(vector& boxes); const utils::IntervalT& operator[](unsigned i) const { assert(i == 0 || i == 1); return (i == 0) ? trackRange : crossPointRange; } utils::IntervalT& operator[](unsigned i) { assert(i == 0 || i == 1); return (i == 0) ? trackRange : crossPointRange; } bool operator==(const GridBoxOnLayer& rhs) const; friend ostream& operator<<(ostream& os, const GridBoxOnLayer& gb); }; // ViaBox class ViaBox { public: GridBoxOnLayer lower, upper; ViaBox() {} // default to be invalid ViaBox(const GridBoxOnLayer& lowerGridBox, const GridBoxOnLayer& upperGridBox) : lower(lowerGridBox), upper(upperGridBox) {} friend ostream& operator<<(ostream& os, const ViaBox& vb); }; } // namespace db ================================================ FILE: src/db/LayerList.cpp ================================================ #include #include "LayerList.h" namespace db { void LayerList::init() { const Rsyn::Session session; Rsyn::PhysicalDesign physicalDesign = static_cast(session.getService("rsyn.physical"))->getPhysicalDesign(); const DBU libDBU = physicalDesign.getDatabaseUnits(Rsyn::LIBRARY_DBU); // Rsyn::PhysicalLayer (LEF) vector rsynLayers; vector rsynCutLayers; for (const Rsyn::PhysicalLayer& rsynLayer : physicalDesign.allPhysicalLayers()) { switch (rsynLayer.getType()) { case Rsyn::ROUTING: rsynLayers.push_back(rsynLayer); break; case Rsyn::CUT: rsynCutLayers.push_back(rsynLayer); break; default: break; } } if (rsynCutLayers.size() + 1 != rsynLayers.size()) { log() << "Error in " << __func__ << ": rsynCutLayers.size() is " << rsynCutLayers.size() << " , rsynLayers.size() is " << rsynLayers.size() << " , not matched... " << std::endl; } // Rsyn::PhysicalVia (LEF) vector> rsynVias(rsynCutLayers.size()); for (const Rsyn::PhysicalVia& rsynVia : physicalDesign.allPhysicalVias()) { rsynVias[rsynVia.getCutLayer().getRelativeIndex()].push_back(rsynVia); } // Rsyn::PhysicalTracks (DEF) vector rsynTracks(rsynLayers.size()); for (const Rsyn::PhysicalTracks& rsynTrack : physicalDesign.allPhysicalTracks()) { int idx = rsynTrack.allLayers().front().getRelativeIndex(); if ((rsynTrack.getDirection() == Rsyn::TRACK_HORIZONTAL) == !strcmp(rsynLayers[idx].getLayer()->direction(), "HORIZONTAL")) { assert(rsynLayers[idx].getRelativeIndex() == idx); rsynTracks[idx] = (rsynTrack); } } // init each MetalLayer layers.clear(); for (unsigned i = 0; i != rsynLayers.size(); ++i) { layers.emplace_back(rsynLayers[i], rsynTracks[i], libDBU); } // init MetalLayer::CrossPointSet initCrossPoints(); cutLayers.clear(); for (unsigned i = 0; i != rsynCutLayers.size(); ++i) { cutLayers.emplace_back(rsynCutLayers[i], rsynVias[i], layers[i].direction, layers[i + 1].direction, libDBU); } /* DR Lagacy Not Used // via area equivalent length (conservative) for (int i = 0, sz = rsynLayers.size(); i < sz; i++) { MetalLayer& layer = layers[i]; auto dir = layer.direction; auto width = layer.width; auto getEqLen = [&](const utils::BoxT& rect, DBU& viaLenEqLen, DBU& viaWidthEqLen) { DBU minViaLen = min(abs(rect[1 - dir].low), abs(rect[1 - dir].high)); // conservative DBU viaWidth = rect[dir].range(); DBU viaLen = rect[1 - dir].range(); viaWidthEqLen = viaLen * max((DBU)0, viaWidth - width) / width; viaLenEqLen = max((DBU)0, minViaLen - width / 2); }; DBU topViaLenEqLen = INT_MAX; DBU botViaLenEqLen = INT_MAX; DBU topViaWidthEqLen = INT_MAX; DBU botViaWidthEqLen = INT_MAX; if (i != 0) getEqLen(cutLayers[i - 1].defaultViaType().top, botViaLenEqLen, botViaWidthEqLen); if (i != sz - 1) getEqLen(cutLayers[i].defaultViaType().bot, topViaLenEqLen, topViaWidthEqLen); layer.viaLenEqLen = min(topViaLenEqLen, botViaLenEqLen); layer.viaWidthEqLen = min(topViaWidthEqLen, botViaWidthEqLen); layer.minLenRaw = layer.minLenRaw - layer.viaWidthEqLen; layer.minLenOneVia = layer.minLenRaw - 2 * layer.viaLenEqLen; layer.minLenTwoVia = layer.minLenOneVia - layer.viaWidthEqLen; if (i == 0) { layer.viaOvlpDist = 0; } else if (i == sz - 1) { layer.viaOvlpDist = 0; } else { auto intvl1 = cutLayers[i - 1].defaultViaType().top[1 - dir]; auto intvl2 = cutLayers[i].defaultViaType().bot[1 - dir]; layer.viaOvlpDist = max(abs(intvl1.high) + abs(intvl2.low), abs(intvl1.low) + abs(intvl2.high)); layer.viaOvlpDist = min(layer.viaOvlpDist, intvl1.range()); layer.viaOvlpDist = min(layer.viaOvlpDist, intvl2.range()); } layer.minLenOneVia = max((DBU)0, layer.minLenOneVia); layer.minLenTwoVia = max((DBU)0, layer.minLenTwoVia); layer.minLenRaw = max((DBU)0, layer.minLenRaw); } // init CutLayer::viaAccess initViaForbidRegions(); initViaConfLUT(); */ } bool LayerList::isValid(const GridPoint& gridPt) const { return gridPt.layerIdx >= 0 && gridPt.layerIdx < layers.size() && layers[gridPt.layerIdx].isValid(gridPt); } bool LayerList::isValid(const GridBoxOnLayer& gridBox) const { return gridBox.layerIdx >= 0 && gridBox.layerIdx < layers.size() && layers[gridBox.layerIdx].isValid(gridBox); } bool LayerList::isValid(const ViaBox& viaBox) const { return isValid(viaBox.lower) && isValid(viaBox.upper) && // seperately getUpper(viaBox.lower) == viaBox.upper && getLower(viaBox.upper) == viaBox.lower; // consistent } BoxOnLayer LayerList::getMetalRectForbidRegion(const BoxOnLayer& metalRect, AggrParaRunSpace aggr) const { const MetalLayer& layer = layers[metalRect.layerIdx]; DBU margin[2]; // x, y for (int dir = 0; dir < 2; ++dir) { margin[dir] = layer.getSpace(metalRect, dir, aggr); margin[dir] += layer.width / 2; } return {metalRect.layerIdx, metalRect.lx() - margin[0], metalRect.ly() - margin[1], metalRect.hx() + margin[0], metalRect.hy() + margin[1]}; } vector> LayerList::getAccurateMetalRectForbidRegions(const BoxOnLayer& metalRect) const { const MetalLayer& layer = layers[metalRect.layerIdx]; vector> results; for (int dir = 0; dir < 2; ++dir) { const DBU range = metalRect[1 - dir].range(); if (range < layer.maxEolWidth) { utils::BoxT region = metalRect; region[1 - dir].low -= layer.maxEolWithin; region[1 - dir].high += layer.maxEolWithin; region[dir].low -= layer.maxEolSpace; region[dir].high += layer.maxEolSpace; results.push_back(region); } else { DBU space = layer.getParaRunSpace(metalRect); utils::BoxT region = metalRect; region[dir].low -= space; region[dir].high += space; results.push_back(region); } } return results; } void LayerList::expandBox(BoxOnLayer& box, int numPitchToExtend) const { DBU margin = layers[box.layerIdx].pitch * numPitchToExtend; box.lx() -= margin; box.ly() -= margin; box.hx() += margin; box.hy() += margin; } void LayerList::expandBox(BoxOnLayer& box, int numPitchToExtend, int dir) const { DBU margin = layers[box.layerIdx].pitch * numPitchToExtend; box[dir].low -= margin; box[dir].high += margin; } utils::IntervalT LayerList::getSurroundingTrack(int layerIdx, DBU loc) const { assert(layerIdx >= 0 && layerIdx < layers.size()); return layers[layerIdx].getSurroundingTrack(loc); } utils::IntervalT LayerList::getSurroundingCrossPoint(int layerIdx, DBU loc) const { if (layerIdx == 0) { return layers[1].getSurroundingTrack(loc); } else if (layerIdx == layers.size() - 1) { return layers[layerIdx - 1].getSurroundingTrack(loc); } else { const utils::IntervalT& upperTrack = layers[layerIdx + 1].getSurroundingTrack(loc); const utils::IntervalT& lowerTrack = layers[layerIdx - 1].getSurroundingTrack(loc); const utils::IntervalT& fromUpperTrack = layers[layerIdx + 1].getLowerCrossPointRange(upperTrack); const utils::IntervalT& fromLowerTrack = layers[layerIdx - 1].getUpperCrossPointRange(lowerTrack); return fromUpperTrack.IntersectWith(fromLowerTrack); } } GridBoxOnLayer LayerList::getSurroundingGrid(int layerIdx, utils::PointT loc) const { auto dir = layers[layerIdx].direction; return {layerIdx, getSurroundingTrack(layerIdx, loc[dir]), getSurroundingCrossPoint(layerIdx, loc[1 - dir])}; } utils::IntervalT LayerList::rangeSearchTrack(int layerIdx, const utils::IntervalT& locRange, bool includeBound) const { assert(layerIdx >= 0 && layerIdx < layers.size()); return layers[layerIdx].rangeSearchTrack(locRange, includeBound); } utils::IntervalT LayerList::rangeSearchCrossPoint(int layerIdx, const utils::IntervalT& locRange, bool includeBound) const { assert(layerIdx >= 0 && layerIdx < layers.size()); if (layerIdx == 0) { return layers[1].rangeSearchTrack(locRange, includeBound); } else if (layerIdx == layers.size() - 1) { return layers[layerIdx - 1].rangeSearchTrack(locRange, includeBound); } else { const utils::IntervalT& upperTrack = layers[layerIdx + 1].rangeSearchTrack(locRange, includeBound); const utils::IntervalT& lowerTrack = layers[layerIdx - 1].rangeSearchTrack(locRange, includeBound); bool upperValid = layers[layerIdx + 1].isTrackRangeValid(upperTrack); bool lowerValid = layers[layerIdx - 1].isTrackRangeValid(lowerTrack); if (upperValid && lowerValid) { // the most typical case const utils::IntervalT& fromUpperTrack = layers[layerIdx + 1].getLowerCrossPointRange(upperTrack); const utils::IntervalT& fromLowerTrack = layers[layerIdx - 1].getUpperCrossPointRange(lowerTrack); return fromUpperTrack.UnionWith(fromLowerTrack); } else if (upperValid || (!lowerValid && layers[layerIdx + 1].isTrackRangeWeaklyValid(upperTrack))) { return layers[layerIdx + 1].getLowerCrossPointRange(upperTrack); } else if (layers[layerIdx - 1].isTrackRangeWeaklyValid(lowerTrack)) { return layers[layerIdx - 1].getUpperCrossPointRange(lowerTrack); } else { return {0, -1}; // a little bit safer than default {inf, -inf} } } } GridBoxOnLayer LayerList::rangeSearch(const BoxOnLayer& box, bool includeBound) const { auto dir = layers[box.layerIdx].direction; return {box.layerIdx, rangeSearchTrack(box.layerIdx, box[dir], includeBound), rangeSearchCrossPoint(box.layerIdx, box[1 - dir], includeBound)}; } utils::PointT LayerList::getLoc(const GridPoint& gridPt) const { assert(isValid(gridPt)); return layers[gridPt.layerIdx].getLoc(gridPt); } BoxOnLayer LayerList::getLoc(const GridBoxOnLayer& gridBox) const { assert(isValid(gridBox)); return layers[gridBox.layerIdx].getLoc(gridBox); } std::pair, utils::PointT> LayerList::getLoc(const GridEdge& edge) const { assert(edge.isTrackSegment() || edge.isWrongWaySegment()); return layers[edge.u.layerIdx].getLoc(edge); } GridPoint LayerList::getUpper(const GridPoint& cur) const { assert(isValid(cur) && cur.layerIdx < (int)layers.size() - 1); return layers[cur.layerIdx].getUpper(cur); } GridPoint LayerList::getLower(const GridPoint& cur) const { assert(isValid(cur) && cur.layerIdx > 0); return layers[cur.layerIdx].getLower(cur); } GridBoxOnLayer LayerList::getUpper(const GridBoxOnLayer& cur) const { assert(isValid(cur) && cur.layerIdx < (int)layers.size() - 1); return GridBoxOnLayer( // layer cur.layerIdx + 1, // track layers[cur.layerIdx + 1].rangeSearchTrack( {layers[cur.layerIdx].crossPoints[cur.crossPointRange.low].location, layers[cur.layerIdx].crossPoints[cur.crossPointRange.high].location}), // cross point layers[cur.layerIdx].getUpperCrossPointRange(cur.trackRange)); } GridBoxOnLayer LayerList::getLower(const GridBoxOnLayer& cur) const { assert(isValid(cur) && cur.layerIdx > 0); return GridBoxOnLayer( // layer cur.layerIdx - 1, // track layers[cur.layerIdx - 1].rangeSearchTrack( {layers[cur.layerIdx].crossPoints[cur.crossPointRange.low].location, layers[cur.layerIdx].crossPoints[cur.crossPointRange.high].location}), // cross point layers[cur.layerIdx].getLowerCrossPointRange(cur.trackRange)); } ViaBox LayerList::getViaBoxBetween(const BoxOnLayer& lower, const BoxOnLayer& upper) { assert((lower.layerIdx + 1) == upper.layerIdx); auto box2d = lower.IntersectWith(upper); auto lowerGridBoxTmp = rangeSearch({lower.layerIdx, box2d}); if (!isValid(lowerGridBoxTmp)) return ViaBox(); // invalid auto upperGridBox = getUpper(lowerGridBoxTmp); if (!isValid(upperGridBox)) return ViaBox(); // invalid auto lowerGridBox = getLower(upperGridBox); if (!isValid(lowerGridBox)) return ViaBox(); // invalid return ViaBox(lowerGridBox, upperGridBox); } bool LayerList::isConnected(const GridBoxOnLayer& lhs, const GridBoxOnLayer& rhs) { if (!isValid(lhs) || !isValid(rhs)) { return false; } else if ((lhs.layerIdx + 1) == rhs.layerIdx) { return isValid(getViaBoxBetween(lhs, rhs)); } else if (lhs.layerIdx == (rhs.layerIdx + 1)) { return isValid(getViaBoxBetween(rhs, lhs)); } else if (lhs.layerIdx == rhs.layerIdx) { return lhs.trackRange.HasIntersectWith(rhs.trackRange) && lhs.crossPointRange.HasIntersectWith(rhs.crossPointRange); } else { return false; } } bool LayerList::isAdjacent(const GridBoxOnLayer& lhs, const GridBoxOnLayer& rhs) { if (!isValid(lhs) || !isValid(rhs)) { return false; } else if (lhs.layerIdx == rhs.layerIdx) { return (abs(lhs.trackRange.low - rhs.trackRange.high) == 1 || abs(rhs.trackRange.low - lhs.trackRange.high) == 1) && lhs.crossPointRange.HasIntersectWith(rhs.crossPointRange); } else { return false; } } void LayerList::initCrossPoints() { for (unsigned i = 0; i != layers.size(); ++i) { vector& crossPoints = layers[i].crossPoints; vector emptyTrackSet; vector& lowerTrackSet = (i > 0) ? layers[i - 1].tracks : emptyTrackSet; vector& upperTrackSet = (i < (layers.size() - 1)) ? layers[i + 1].tracks : emptyTrackSet; // merge cross points to lower and upper layers int iLo = 0, iUp = 0; // track indexes DBU lastBoth = 0; while (iLo < lowerTrackSet.size() || iUp < upperTrackSet.size()) { if (iUp >= upperTrackSet.size()) { crossPoints.emplace_back(lowerTrackSet[iLo].location, iLo, -1); lowerTrackSet[iLo].upperCPIdx = crossPoints.size() - 1; ++iLo; } else if (iLo >= lowerTrackSet.size()) { crossPoints.emplace_back(upperTrackSet[iUp].location, -1, iUp); upperTrackSet[iUp].lowerCPIdx = crossPoints.size() - 1; ++iUp; } // boundaries should be checked first else if (lowerTrackSet[iLo].location < upperTrackSet[iUp].location) { crossPoints.emplace_back(lowerTrackSet[iLo].location, iLo, -1); lowerTrackSet[iLo].upperCPIdx = crossPoints.size() - 1; ++iLo; } else if (lowerTrackSet[iLo].location > upperTrackSet[iUp].location) { crossPoints.emplace_back(upperTrackSet[iUp].location, -1, iUp); upperTrackSet[iUp].lowerCPIdx = crossPoints.size() - 1; ++iUp; } else { // iLo < lowerTrackSet.size() && iUp < lowerTrackSet.size() && lowerTrackSet[iLo].location == // lowerTrackSet[iUp].location crossPoints.emplace_back(lowerTrackSet[iLo].location, iLo, iUp); lowerTrackSet[iLo].upperCPIdx = crossPoints.size() - 1; upperTrackSet[iUp].lowerCPIdx = crossPoints.size() - 1; ++iLo; ++iUp; } } layers[i].initAccCrossPointDistCost(); } } void LayerList::initOppLUT(const vector>>& ori, vector>>& opp) { const size_t nCPs = ori.size(); size_t xSize = 0; for (const vector>& orig : ori) { xSize = orig.size(); if (xSize) { break; } } auto travelCPs = [&](std::function handle) { for (unsigned i = 0; i != nCPs; ++i) { if (ori[i].empty()) { continue; } for (unsigned j = 0; j != xSize; ++j) { const int ySize = ((int)ori[i][0].size() - 1) / 2; for (unsigned k = max(0, ySize - (int)i); k < min(ySize * 2 + 1, int(nCPs + ySize - i)); ++k) { if (ori[i][j][k]) { handle(i, j, ySize, k); } } } } }; vector ySizes(nCPs, -1); auto updateSize = [&](const unsigned i, const unsigned j, const unsigned ySize, const unsigned k) { ySizes[i + k - ySize] = max(ySizes[i + k - ySize], abs((int)ySize - (int)k)); }; auto fillTable = [&](const unsigned i, const unsigned j, const unsigned ySize, const unsigned k) { vector& tmpOpp = opp[i + k - ySize][xSize - j - 1]; const int tmpYSize = ((int)tmpOpp.size() - 1) / 2; tmpOpp[tmpYSize + ySize - k] = true; }; travelCPs(updateSize); opp.clear(); opp.resize(nCPs); for (unsigned i = 0; i != nCPs; ++i) { if (ySizes[i] >= 0) { opp[i].resize(xSize, vector(ySizes[i] * 2 + 1, false)); } else if (ori[i].empty()) { opp[i].resize(xSize, vector(1, false)); } assert(ori[i].size() + opp[i].size()); } travelCPs(fillTable); } void LayerList::initViaWire(const int layerIdx, const utils::BoxT& viaMetal, vector>>& viaWireLUT) { const MetalLayer& layer = layers[layerIdx]; const DBU halfWidth = ceil(layer.width / 2.0); const DBU viaMetalWidth = viaMetal[layer.direction].range(); const DBU viaMetalHeight = viaMetal[1 - layer.direction].range(); const DBU pSpace = layer.getParaRunSpace(viaMetal); const DBU space = max({pSpace, layer.maxEolSpace, layer.maxEolWithin}); const size_t xSize = max(ceil((space + halfWidth + viaMetal[layer.direction].high) / (double)layer.pitch), ceil((space + halfWidth - viaMetal[layer.direction].low) / (double)layer.pitch)) - 1; const utils::IntervalT locRange(-space - halfWidth + viaMetal[1 - layer.direction].low + 1, +space + halfWidth + viaMetal[1 - layer.direction].high - 1); viaWireLUT.resize(layer.numCrossPoints()); vector viaTrack(xSize + 1, false); for (unsigned i = 0; i != layer.numCrossPoints(); ++i) { const CrossPoint& cp = layer.crossPoints[i]; utils::IntervalT tmpLocRange(locRange); tmpLocRange.ShiftBy(layer.crossPoints[i].location); const utils::IntervalT& cpRange = rangeSearchCrossPoint(layerIdx, tmpLocRange); const size_t ySize = max((int)i - cpRange.low, cpRange.high - (int)i); viaWireLUT[i].resize(xSize * 2 + 1, vector(ySize * 2 + 1, false)); for (unsigned j = 0; j != xSize * 2 + 1; ++j) { DBU xDist = 0; if (j < xSize) { xDist = max(0L, int(xSize - j) * layer.pitch - halfWidth + viaMetal[layer.direction].low); } else if (j > xSize) { xDist = max(0L, int(j - xSize) * layer.pitch - halfWidth - viaMetal[layer.direction].high); } for (unsigned k = max(0, (int)ySize - (int)i); k < min(ySize * 2 + 1, layer.numCrossPoints() + ySize - i); ++k) { const CrossPoint& tmpCP = layer.crossPoints[i + k - ySize]; DBU yDist = 0; if (k < ySize) { yDist = max(0L, cp.location - tmpCP.location - halfWidth + viaMetal[1 - layer.direction].low); } else if (k > ySize) { yDist = max(0L, tmpCP.location - cp.location - halfWidth - viaMetal[1 - layer.direction].high); } if (pow(xDist, 2) + pow(yDist, 2) < pow(pSpace, 2) || layer.isEolViolation(xDist, viaMetalHeight, yDist) || layer.isEolViolation(yDist, viaMetalWidth, xDist)) { viaTrack[abs((int)j - (int)xSize)] = true; viaWireLUT[i][j][k] = true; } } } } size_t minXSize = xSize; for (; minXSize && !viaTrack[minXSize]; --minXSize) { } unsigned d = xSize - minXSize; if (!d) { return; } for (vector>& vvb : viaWireLUT) { for (unsigned i = 0; i != minXSize * 2 + 1; ++i) { vvb[i] = vvb[i + d]; } vvb.resize(minXSize * 2 + 1); } } void LayerList::initViaConfLUT() { for (unsigned i = 0; i != cutLayers.size(); ++i) { CutLayer& cutLayer = cutLayers[i]; // Loops for init all-all via-via LUTs for (unsigned j = 0; j != cutLayer.allViaTypes.size(); ++j) { ViaType& viaType1 = cutLayer.allViaTypes[j]; viaType1.allViaCut.resize(cutLayer.allViaTypes.size()); viaType1.allViaMetal.resize(cutLayer.allViaTypes.size()); viaType1.allViaMetalNum.resize(cutLayer.allViaTypes.size()); for (unsigned k = 0; k != cutLayer.allViaTypes.size(); ++k) { ViaType& viaType2 = cutLayer.allViaTypes[k]; auto& viaCut = viaType1.allViaCut[k]; auto& viaMetal = viaType1.allViaMetal[k]; auto& viaMetalNum = viaType1.allViaMetalNum[k]; initSameLayerViaConfLUT(i, viaType1, viaType2, viaCut, viaMetal, viaMetalNum); } } // 2. init viaTopVia & viaBotVia if (i > 0) { // Loops for init all-all via-via LUTs for (unsigned j = 0; j != cutLayer.allViaTypes.size(); ++j) { ViaType& viaType1 = cutLayer.allViaTypes[j]; viaType1.allViaBotVia.resize(cutLayers[i - 1].allViaTypes.size()); for (unsigned k = 0; k != cutLayers[i - 1].allViaTypes.size(); ++k) { ViaType& viaType2 = cutLayers[i - 1].allViaTypes[k]; viaType2.allViaTopVia.resize(cutLayer.allViaTypes.size()); auto& viaBotVia = viaType1.allViaBotVia[k]; auto& viaTopVia = viaType2.allViaTopVia[j]; initDiffLayerViaConfLUT(i, viaType1, viaType2, viaBotVia, viaTopVia); } } } // 3. init viaBotWire & viaTopWire layers[i].wireTopVia.resize(cutLayer.allViaTypes.size()); layers[i + 1].wireBotVia.resize(cutLayer.allViaTypes.size()); for (auto& viaType : cutLayer.allViaTypes) { initViaWire(i, viaType.bot, viaType.viaBotWire); initViaWire(i + 1, viaType.top, viaType.viaTopWire); LayerList::initOppLUT(viaType.viaBotWire, layers[i].wireTopVia[viaType.idx]); LayerList::initOppLUT(viaType.viaTopWire, layers[i + 1].wireBotVia[viaType.idx]); } } // 4. init wireRange for (MetalLayer& layer : layers) { layer.initWireRange(); } // Merge LUTs for (unsigned i = 0; i != cutLayers.size(); ++i) { CutLayer& cutLayer = cutLayers[i]; for (unsigned j = 0; j != cutLayer.allViaTypes.size(); ++j) { ViaType& viaType = cutLayer.allViaTypes[j]; viaType.mergedAllViaMetal = mergeLUTs(viaType.allViaMetal); if (i > 0) { for (int k = 0; k != viaType.allViaBotVia.size(); ++k) { viaType.mergedAllViaBotVia = mergeLUTsCP(viaType.allViaBotVia); } } if (i < cutLayers.size()) { for (int k = 0; k != viaType.allViaTopVia.size(); ++k) { viaType.mergedAllViaTopVia = mergeLUTsCP(viaType.allViaTopVia); } } } } for (int i = 0; i < layers.size(); ++i) { MetalLayer& layer = layers[i]; if (i > 0) { layer.mergedWireBotVia = mergeLUTsCP(layer.wireBotVia); } if ((i + 1) < layers.size()) { layer.mergedWireTopVia = mergeLUTsCP(layer.wireTopVia); } } // Set isWireViaMultiTrack for (int i = 0; i < layers.size(); ++i) { if (i > 0 && layers[i].wireBotVia[0][0].size() > 1 || (i + 1) < layers.size() && layers[i].wireTopVia[0][0].size() > 1) layers[i].isWireViaMultiTrack = true; } // writeDefConflictLUTs("debugConflictLUTa.log"); // exit(0); } void LayerList::initSameLayerViaConfLUT(const int layerIdx, ViaType& viaT1, ViaType& viaT2, vector>& viaCut, vector>& viaMetal, vector>& viaMetalNum) { CutLayer& cutLayer = cutLayers[layerIdx]; MetalLayer& botLayer = layers[layerIdx]; MetalLayer& topLayer = layers[layerIdx + 1]; const Dimension botDim = botLayer.direction; const Dimension topDim = topLayer.direction; const DBU cutSpacing = cutLayer.spacing; const utils::BoxT& botT1 = viaT1.bot; const utils::BoxT& cutT1 = viaT1.cut; const utils::BoxT& topT1 = viaT1.top; const utils::BoxT& botT2 = viaT2.bot; const utils::BoxT& cutT2 = viaT2.cut; const utils::BoxT& topT2 = viaT2.top; const DBU botPSpace = max(botLayer.getParaRunSpace(botT1), botLayer.getParaRunSpace(botT2)); const DBU topPSpace = max(topLayer.getParaRunSpace(topT1), topLayer.getParaRunSpace(topT2)); const DBU botCSpace = 0; // max(botLayer.getCornerSpace(botT1), botLayer.getCornerSpace(botT2)); const DBU topCSpace = 0; // max(topLayer.getCornerSpace(topT1), topLayer.getCornerSpace(topT2)); const DBU botSpace = max({botPSpace, botCSpace, botLayer.maxEolSpace, botLayer.maxEolWithin}); const DBU topSpace = max({topPSpace, topCSpace, topLayer.maxEolSpace, topLayer.maxEolWithin}); const DBU botPitch = botLayer.pitch; const DBU topPitch = topLayer.pitch; // init viaCut & viaMetal const size_t cutXSize = max(ceil((cutSpacing + cutT1[botDim].high - cutT2[botDim].low) / (double)botPitch), ceil((cutSpacing + cutT2[botDim].high - cutT1[botDim].low) / (double)botPitch)) - 1; const size_t cutYSize = max(ceil((cutSpacing + cutT1[topDim].high - cutT2[topDim].low) / (double)topPitch), ceil((cutSpacing + cutT2[topDim].high - cutT1[topDim].low) / (double)topPitch)) - 1; const DBU metalXLength = max({botSpace + botT2[botDim].high - botT1[botDim].low, botSpace + botT1[botDim].high - botT2[botDim].low, topSpace + topT2[botDim].high - topT1[botDim].low, topSpace + topT1[botDim].high - topT2[botDim].low}); const DBU metalYLength = max({botSpace + botT2[topDim].high - botT1[topDim].low, botSpace + botT1[topDim].high - botT2[topDim].low, topSpace + topT2[topDim].high - topT1[topDim].low, topSpace + topT1[topDim].high - topT2[topDim].low}); const size_t metalXSize = max(cutXSize, (size_t)ceil((metalXLength) / (double)botPitch) - 1); const size_t metalYSize = max(cutYSize, (size_t)ceil((metalYLength) / (double)topPitch) - 1); const DBU maxLength = max(metalXLength, metalYLength); botLayer.confLutMargin = max(botLayer.confLutMargin, maxLength); topLayer.confLutMargin = max(topLayer.confLutMargin, maxLength); viaCut.resize(2 * cutXSize + 1, vector(2 * cutYSize + 1, false)); viaMetal.resize(2 * metalXSize + 1, vector(2 * metalYSize + 1, false)); viaMetalNum.resize(2 * metalXSize + 1, vector(2 * metalYSize + 1, 0)); vector viaMetalTrack(2 * metalXSize + 1, false); utils::PointT delta; for (unsigned j = 0; j != 2 * cutXSize + 1; ++j) { delta[botDim] = botPitch * (static_cast(j) - static_cast(cutXSize)); for (unsigned k = 0; k != 2 * cutYSize + 1; ++k) { delta[topDim] = topPitch * (static_cast(k) - static_cast(cutYSize)); utils::BoxT tmpT2(cutT2); tmpT2.ShiftBy(delta); if (utils::L2Dist(tmpT2, cutT1) < cutSpacing) viaCut[j][k] = true; } } const size_t offsetX{metalXSize - cutXSize}; const size_t offsetY{metalYSize - cutYSize}; for (unsigned j = 0; j != 2 * metalXSize + 1; ++j) { delta[botDim] = botPitch * (static_cast(j) - static_cast(metalXSize)); for (unsigned k = 0; k != 2 * metalYSize + 1; ++k) { delta[topDim] = topPitch * (static_cast(k) - static_cast(metalYSize)); utils::BoxT tmpBotT2(botT2); utils::BoxT tmpTopT2(topT2); tmpBotT2.ShiftBy(delta); tmpTopT2.ShiftBy(delta); viaMetalNum[j][k] += static_cast(j <= 2 * cutXSize + offsetX && k <= 2 * cutYSize + offsetY && j >= offsetX && k >= offsetY && viaCut[j - offsetX][k - offsetY]) + static_cast( L2Dist(tmpBotT2, botT1) < botPSpace || L2Dist(tmpTopT2, topT1) < topPSpace || botLayer.isEolViolation(tmpBotT2, botT1) || topLayer.isEolViolation(tmpTopT2, topT1)); // || // utils::ParaRunLength(tmpBotT2, botT1) <= 0 && utils::LInfDist(tmpBotT2, botT1) < botCSpace || // utils::ParaRunLength(tmpTopT2, topT1) <= 0 && utils::LInfDist(tmpTopT2, topT1) < topCSpace); if (viaMetalNum[j][k]) { viaMetalTrack[j] = true; viaMetal[j][k] = true; } } } size_t minMetalXSize = 2 * metalXSize + 1; for (; minMetalXSize && !viaMetalTrack[minMetalXSize]; --minMetalXSize) { } if (minMetalXSize < metalXSize) viaMetal.resize(minMetalXSize + 1); } void LayerList::initDiffLayerViaConfLUT(const int layerIdx, ViaType& viaT1, ViaType& viaT2, vector>>& viaBotVia, vector>>& viaTopVia) { MetalLayer& botLayer = layers[layerIdx]; const Dimension botDim = botLayer.direction; const utils::BoxT& botT1 = viaT1.bot; const utils::BoxT& topT2 = viaT2.top; const DBU botPSpace = max(botLayer.getParaRunSpace(botT1), botLayer.getParaRunSpace(topT2)); const DBU botCSpace = 0; // max(botLayer.getCornerSpace(botT1), botLayer.getCornerSpace(topT2)); const DBU botSpace = max({botPSpace, botCSpace, botLayer.maxEolSpace, botLayer.maxEolWithin}); const DBU botPitch = botLayer.pitch; const unsigned nBotCPs = botLayer.numCrossPoints(); const DBU xLength = botSpace + max(botT1[botDim].high - topT2[botDim].low, topT2[botDim].high - botT1[botDim].low); const size_t xSize = ceil(xLength / (double)botPitch) - 1; const utils::IntervalT botLocRange(-topT2[1 - botDim].high + botT1[1 - botDim].low - botSpace + 1, +botT1[1 - botDim].high - topT2[1 - botDim].low + botSpace - 1); const DBU maxLength = max({xLength, -botLocRange.low, botLocRange.high}); botLayer.confLutMargin = max(botLayer.confLutMargin, maxLength); viaBotVia.resize(nBotCPs); for (unsigned j = 0; j != nBotCPs; ++j) { utils::IntervalT tmpLocRange(botLocRange); tmpLocRange.ShiftBy(botLayer.crossPoints[j].location); const utils::IntervalT& cpRange = rangeSearchCrossPoint(layerIdx, tmpLocRange); const size_t ySize = max((int)j - cpRange.low, cpRange.high - (int)j); if (botLayer.crossPoints[j].upperTrackIdx >= 0) { viaBotVia[j].resize(xSize * 2 + 1, vector(ySize * 2 + 1, false)); } else { viaBotVia[j].resize(xSize * 2 + 1, vector(ySize * 2 + 1, true)); } } utils::PointT delta; for (unsigned j = 0; j != nBotCPs; ++j) { const CrossPoint& cp = botLayer.crossPoints[j]; if (cp.upperTrackIdx == -1) { continue; } const unsigned ySize = (viaBotVia[j][0].size() - 1) / 2; for (unsigned k = 0; k != xSize * 2 + 1; ++k) { delta[botDim] = botPitch * (static_cast(k) - static_cast(xSize)); for (unsigned l = max(0, (int)ySize - (int)j); l < min(ySize * 2 + 1, nBotCPs + ySize - j); ++l) { const CrossPoint& tmpCP = botLayer.crossPoints[j + l - ySize]; if (tmpCP.lowerTrackIdx == -1) { viaBotVia[j][k][l] = true; continue; } delta[1 - botDim] = tmpCP.location - cp.location; utils::BoxT tmpTopT2(topT2); tmpTopT2.ShiftBy(delta); if (L2Dist(tmpTopT2, botT1) < botPSpace || botLayer.isEolViolation(tmpTopT2, botT1)) { // || // utils::ParaRunLength(tmpTopT2, botT1) <= 0 && utils::LInfDist(tmpTopT2, botT1) < botCSpace) { viaBotVia[j][k][l] = true; } } } } LayerList::initOppLUT(viaBotVia, viaTopVia); } void LayerList::initViaForbidRegions() { for (int i = 0; i < cutLayers.size(); ++i) { auto& cutLayer = cutLayers[i]; cutLayer.botMaxForbidRegion = cutLayer.defaultViaType().bot; cutLayer.topMaxForbidRegion = cutLayer.defaultViaType().top; for (auto& viaType : cutLayer.allViaTypes) { viaType.botForbidRegions = getAccurateMetalRectForbidRegions({i, viaType.bot}); for (const auto& region : viaType.botForbidRegions) { cutLayer.botMaxForbidRegion = cutLayer.botMaxForbidRegion.UnionWith(region); } viaType.topForbidRegions = getAccurateMetalRectForbidRegions({i + 1, viaType.top}); for (const auto& region : viaType.topForbidRegions) { cutLayer.topMaxForbidRegion = cutLayer.topMaxForbidRegion.UnionWith(region); } } } } void LayerList::mergeLUT(vector>& lhs, const vector>& rhs) { const unsigned lhsXSize = lhs.size() / 2; const unsigned lhsYSize = lhs[0].size() / 2; const unsigned rhsXSize = rhs.size() / 2; const unsigned rhsYSize = rhs[0].size() / 2; const unsigned offsetX = lhsXSize - rhsXSize; const unsigned offsetY = lhsYSize - rhsYSize; for (unsigned j = 0; j != rhs.size(); ++j) { for (unsigned k = 0; k != rhs[0].size(); ++k) { if (rhs[j][k]) lhs[j + offsetX][k + offsetY] = true; } } } vector> LayerList::mergeLUTs(const vector>>& LUTs) { int XSize = 0, YSize = 0; vector> mergedLUT; for (auto& LUT : LUTs) { XSize = max(XSize, int(LUT.size())); YSize = max(YSize, int(LUT[0].size())); } mergedLUT.resize(XSize, vector(YSize, false)); for (auto& LUT : LUTs) { mergeLUT(mergedLUT, LUT); } return mergedLUT; } vector>> LayerList::mergeLUTsCP(const vector>>>& LUTs) { vector XSizes(LUTs[0].size(), 0); vector YSizes(LUTs[0].size(), 0); // crossPointIdx, trackIdx, crossPointIdx vector>> mergedLUTs(LUTs[0].size()); for (unsigned cpIdx = 0; cpIdx != LUTs[0].size(); ++cpIdx) { for (unsigned typeIdx = 0; typeIdx != LUTs.size(); ++typeIdx) { XSizes[cpIdx] = max(XSizes[cpIdx], int(LUTs[typeIdx][cpIdx].size())); YSizes[cpIdx] = max(YSizes[cpIdx], int(LUTs[typeIdx][cpIdx][0].size())); } mergedLUTs[cpIdx].resize(XSizes[cpIdx], vector(YSizes[cpIdx], false)); } for (unsigned cpIdx = 0; cpIdx != LUTs[0].size(); ++cpIdx) { for (unsigned typeIdx = 0; typeIdx != LUTs.size(); ++typeIdx) { mergeLUT(mergedLUTs[cpIdx], LUTs[typeIdx][cpIdx]); } } return mergedLUTs; } void LayerList::print() { log() << "METAL LAYERS" << std::endl; numGridPoints = 0; totalTrackLength = 0; for (const MetalLayer& layer : layers) { log() << layer << std::endl; numGridPoints += layer.numGridPoints(); totalTrackLength += layer.numTracks() * layer.getCrossPointRangeDistCost({0, layer.numCrossPoints() - 1}); } log() << "The total number of grid points is " << numGridPoints << std::endl; log() << "The total length of tracks is " << totalTrackLength << " DBU " << std::endl; log() << "(Note: dir=Y means that each track is horizontal and has differnt Y)" << std::endl; log() << "Metal layer design rules: " << std::endl; for (const MetalLayer& layer : layers) { layer.printDesignRules(log()) << std::endl; } log() << "Wire conflict LUT: " << std::endl; for (const MetalLayer& layer : layers) { layer.printViaOccupancyLUT(log()) << std::endl; } log() << "CUT LAYERS" << std::endl; numVias = 0; for (int i = 0; i < getLayerNum() - 1; ++i) { int num = layers[i].numTracks() * layers[i + 1].numTracks(); const auto& cutLayer = cutLayers[i]; log() << cutLayer << ", #vias=" << num << std::endl; numVias += num; } log() << "Cut layer design rules: " << std::endl; for (const CutLayer& layer : cutLayers) { layer.printDesignRules(log()) << std::endl; } log() << "Via conflict LUT: " << std::endl; for (const CutLayer& layer : cutLayers) { layer.printViaOccupancyLUT(log()) << std::endl; } log() << "The total number of via candidates is " << numVias << std::endl; } void LayerList::writeDefConflictLUTs(const std::string& debugFileName) const { std::ofstream ofs(debugFileName); int cpIdx = 0; for (const auto& cutLayer : cutLayers) { cutLayer.printBasics(ofs); cutLayer.printDesignRules(ofs); cutLayer.printViaOccupancyLUT(ofs); ofs << "viaCut" << std::endl; int xSize = ((int)cutLayer.allViaTypes[0].allViaCut[0].size() - 1) / 2; int ySize = ((int)cutLayer.allViaTypes[0].allViaCut[0][0].size() - 1) / 2; for (int j = xSize; j != cutLayer.allViaTypes[0].allViaCut[0].size(); ++j) { for (int k = ySize; k != cutLayer.allViaTypes[0].allViaCut[0][0].size(); ++k) { ofs << (int)(cutLayer.allViaTypes[0].allViaCut[0][j][k]) << " "; } ofs << std::endl; } ofs << std::endl; ofs << "viaMetal" << std::endl; xSize = ((int)cutLayer.allViaTypes[0].allViaMetal[0].size() - 1) / 2; ySize = ((int)cutLayer.allViaTypes[0].allViaMetal[0][0].size() - 1) / 2; for (int j = xSize; j != cutLayer.allViaTypes[0].allViaMetal[0].size(); ++j) { for (int k = ySize; k != cutLayer.allViaTypes[0].allViaMetal[0][0].size(); ++k) { ofs << (int)(cutLayer.allViaTypes[0].allViaMetal[0][j][k]) << " "; } ofs << std::endl; } ofs << std::endl; ofs << "viaBotVia" << std::endl; cpIdx = 0; if (cutLayer.idx > 0) { for (const auto& cp : cutLayer.allViaTypes[0].allViaBotVia[0]) { ofs << "cpidx is: " << cpIdx++ << std::endl; for (auto a : cp) { for (auto b : a) { ofs << (int)(b) << " "; } ofs << std::endl; } } } ofs << "viaTopVia" << std::endl; cpIdx = 0; if (cutLayer.idx < cutLayers.size() - 1) { for (const auto& cp : cutLayer.allViaTypes[0].allViaTopVia[0]) { ofs << "cpidx is: " << cpIdx++ << std::endl; for (auto a : cp) { for (auto b : a) { ofs << (int)(b) << " "; } ofs << std::endl; } } } ofs << std::endl; } } } // namespace db ================================================ FILE: src/db/LayerList.h ================================================ #pragma once #include "CutLayer.h" #include "MetalLayer.h" #include "RsynService.h" namespace db { class LayerList { public: void init(); // Check whether a geo primitive is valid bool isValid(const GridPoint& gridPt) const; bool isValid(const GridBoxOnLayer& gridBox) const; bool isValid(const ViaBox& viaBox) const; // Get metal rectangle (diff-net) forbidding region // 1. for pin taps BoxOnLayer getMetalRectForbidRegion(const BoxOnLayer& metalRect, AggrParaRunSpace aggr) const; // 2. for via forbid regions vector> getAccurateMetalRectForbidRegions(const BoxOnLayer& metalRect) const; // Expand box by several pitches void expandBox(BoxOnLayer& box, int numPitchToExtend) const; void expandBox(BoxOnLayer& box, int numPitchToExtend, int dir) const; // NOTE: the functions below assume valid input geo primitive(s) // Search by location utils::IntervalT getSurroundingTrack(int layerIdx, DBU loc) const; utils::IntervalT getSurroundingCrossPoint(int layerIdx, DBU loc) const; GridBoxOnLayer getSurroundingGrid(int layerIdx, utils::PointT loc) const; // Search by location range // input: layer (a valid one is assumed), location range [min, max] (inclusive) // output: index range of Track/CrossPoint // note: if out of range, assign the nearest endpoint utils::IntervalT rangeSearchTrack(int layerIdx, const utils::IntervalT& locRange, bool includeBound = true) const; utils::IntervalT rangeSearchCrossPoint(int layerIdx, const utils::IntervalT& locRange, bool includeBound = true) const; GridBoxOnLayer rangeSearch(const BoxOnLayer& box, bool includeBound = true) const; // Get (x, y) location of GridPoint/GridBoxOnLayer utils::PointT getLoc(const GridPoint& gridPt) const; BoxOnLayer getLoc(const GridBoxOnLayer& gridBox) const; std::pair, utils::PointT> getLoc(const GridEdge& edge) const; // Find the upper/lower GridPoint/GridBoxOnLayer of the current GridPoint/GridBoxOnLayer // note: 1. valid layer is assumed, 2. upper/lower GridPoint/GridBoxOnLayer may not exist. GridPoint getUpper(const GridPoint& cur) const; GridPoint getLower(const GridPoint& cur) const; GridBoxOnLayer getUpper(const GridBoxOnLayer& cur) const; GridBoxOnLayer getLower(const GridBoxOnLayer& cur) const; // Get ViaBox from the intersection of two BoxOnLayer (in neighboring layers) // note: 1. should be on neighboring layers, 2. ViaBox may be empty. ViaBox getViaBoxBetween(const BoxOnLayer& lower, const BoxOnLayer& upper); ViaBox getViaBoxBetween(const GridBoxOnLayer& lower, const GridBoxOnLayer& upper) { return getViaBoxBetween(getLoc(lower), getLoc(upper)); } bool isConnected(const GridBoxOnLayer& lhs, const GridBoxOnLayer& rhs); bool isAdjacent(const GridBoxOnLayer& lhs, const GridBoxOnLayer& rhs); Dimension getLayerDir(int layerIdx) const { return layers[layerIdx].direction; } const MetalLayer& getLayer(int layerIdx) const { return layers[layerIdx]; } const CutLayer& getCutLayer(int cutLayerIdx) const { return cutLayers[cutLayerIdx]; } unsigned getLayerNum() const noexcept { return layers.size(); } // Merge LUTs void mergeLUT(vector>& lhs, const vector>& rhs); vector> mergeLUTs(const vector>>& LUTs); vector>> mergeLUTsCP(const vector>>>& LUTs); protected: vector layers; vector cutLayers; int numGridPoints; DBU totalTrackLength; int numVias; void initCrossPoints(); static void initOppLUT(const vector>>& ori, vector>>& opp); void initViaWire(const int layerIdx, const utils::BoxT& viaMetal, vector>>& viaWireLUT); void initSameLayerViaConfLUT(const int layerIdx, ViaType& viaT1, ViaType& viaT2, vector>& viaCut, vector>& viaMetal, vector>& viaMetalNum); void initDiffLayerViaConfLUT(const int layerIdx, ViaType& viaT1, ViaType& viaT2, vector>>& viaBotVia, vector>>& viaTopVia); void initViaConfLUT(); void initViaForbidRegions(); void print(); void writeDefConflictLUTs(const std::string& debugFileName) const; }; } // namespace db ================================================ FILE: src/db/MetalLayer.cpp ================================================ #include "MetalLayer.h" namespace db { ostream& operator<<(ostream& os, const Track& track) { os << "track(lo=" << track.lowerCPIdx << ", up=" << track.upperCPIdx << ", loc=" << track.location << ")"; return os; } ostream& operator<<(ostream& os, const CrossPoint& cp) { os << "crossPt(lo=" << cp.lowerTrackIdx << ", up=" << cp.upperTrackIdx << ", loc=" << cp.location << ")"; return os; } MetalLayer::MetalLayer(Rsyn::PhysicalLayer rsynLayer, Rsyn::PhysicalTracks rsynTrack, const DBU libDBU) { // Rsyn::PhysicalLayer (LEF) lefiLayer* layer = rsynLayer.getLayer(); name = layer->name(); direction = strcmp(layer->direction(), "HORIZONTAL") ? X : Y; assert((rsynTrack.getDirection() == Rsyn::TRACK_HORIZONTAL) == (direction == Y)); idx = rsynLayer.getRelativeIndex(); width = static_cast(std::round(layer->width() * libDBU)); minWidth = static_cast(std::round(layer->minwidth() * libDBU)); widthForSuffOvlp = std::ceil(minWidth * 0.7071); shrinkForSuffOvlp = std::max(0, std::ceil(widthForSuffOvlp - width * 0.5)); minArea = static_cast(std::round(layer->area() * libDBU * libDBU)); minLenRaw = minArea / width - width; // default spacing const int numSpaceTable = layer->numSpacingTable(); if (!numSpaceTable) { log() << "Warning in " << __func__ << ": For " << name << ", no run spacing table..." << std::endl; } else { for (int iSpaceTable = 0; iSpaceTable < numSpaceTable; ++iSpaceTable) { if (!layer->spacingTable(iSpaceTable)->isParallel()) { continue; } const lefiParallel* parallel = layer->spacingTable(iSpaceTable)->parallel(); const int numLength = parallel->numLength(); if (numLength > 0) { parallelLength.resize(numLength); for (unsigned iLength = 0; iLength != (unsigned)numLength; ++iLength) { parallelLength[iLength] = static_cast(std::round(parallel->length(iLength) * libDBU)); } } const int numWidth = parallel->numWidth(); if (numWidth > 0) { parallelWidth.resize(numWidth); parallelWidthSpace.resize(numWidth); for (unsigned iWidth = 0; iWidth != (unsigned)numWidth; ++iWidth) { parallelWidth[iWidth] = static_cast(std::round(parallel->width(iWidth) * libDBU)); parallelWidthSpace[iWidth].resize(std::max(1, numLength), 0); for (int iLength = 0; iLength < numLength; ++iLength) { parallelWidthSpace[iWidth][iLength] = static_cast(std::round(parallel->widthSpacing(iWidth, iLength) * libDBU)); } } defaultSpace = getParaRunSpace(width); paraRunSpaceForLargerWidth = (parallelWidthSpace.size() > 1) ? parallelWidthSpace[1][0] : defaultSpace; } } } // eol spacing if (!layer->hasSpacingNumber()) { log() << "Warning in " << __func__ << ": For " << name << ", no spacing rules..." << std::endl; } else { const int numSpace = layer->numSpacing(); spaceRules.reserve(numSpace); for (int iSpace = 0; iSpace < numSpace; ++iSpace) { const DBU space = static_cast(std::round(layer->spacing(iSpace) * libDBU)); const DBU eolWidth = static_cast(std::round(layer->spacingEolWidth(iSpace) * libDBU)); const DBU eolWithin = static_cast(std::round(layer->spacingEolWithin(iSpace) * libDBU)); const DBU parSpace = static_cast(std::round(layer->spacingParSpace(iSpace) * libDBU)); const DBU parWithin = static_cast(std::round(layer->spacingParWithin(iSpace) * libDBU)); if (layer->hasSpacingParellelEdge(iSpace)) { spaceRules.emplace_back(space, eolWidth, eolWithin, parSpace, parWithin); maxEolSpace = std::max(maxEolSpace, space); maxEolWidth = std::max(maxEolWidth, eolWidth); maxEolWithin = std::max(maxEolWithin, eolWithin); } else if (layer->hasSpacingEndOfLine(iSpace)) { spaceRules.emplace_back(space, eolWidth, eolWithin); maxEolSpace = std::max(maxEolSpace, space); maxEolWidth = std::max(maxEolWidth, eolWidth); maxEolWithin = std::max(maxEolWithin, eolWithin); } else if (space != defaultSpace) { log() << "Warning in " << __func__ << ": For " << rsynLayer.getName() << ", mismatched defaultSpace & spacingTable... " << std::endl; } } if (spaceRules.empty()) { log() << "Warning in " << __func__ << ": For " << name << ", no eol spacing rules..." << std::endl; } } fixedMetalQueryMargin = std::max(maxEolSpace, maxEolWithin); // corner spacing const int numProps = layer->numProps(); for (unsigned iProp = 0; static_cast(iProp) < numProps; ++iProp) { if (strcmp(layer->propName(iProp), "LEF58_CORNERSPACING")) continue; if (hasCornerSpace()) { log() << "Warning in " << __func__ << ": For " << name << ", multiple corner spacing rules: " << layer->propValue(iProp) << "...\n"; continue; } std::istringstream iss(layer->propValue(iProp)); std::string sBuf(""); double fBuf1{0}; double fBuf2{0}; while (iss) { iss >> sBuf; if (sBuf == "CORNERSPACING" || sBuf == "CONVEXCORNER" || sBuf == ";") continue; if (sBuf == "EXCEPTEOL") { cornerExceptEol = true; iss >> fBuf1; cornerEolWidth = static_cast(std::round(fBuf1 * libDBU)); } else if (sBuf == "WIDTH") { iss >> fBuf1 >> sBuf >> fBuf2; if (fBuf1) { cornerWidth.push_back(static_cast(std::round(fBuf1 * libDBU))); cornerWidthSpace.push_back(static_cast(std::round(fBuf2 * libDBU))); } else { cornerWidthSpace[0] = static_cast(std::round(fBuf2 * libDBU)); } } else { log() << "Warning in " << __func__ << ": For " << name << ", corner spacing not identified: " << sBuf << "...\n"; } } } delete rsynLayer.getLayer(); // Rsyn::PhysicalTracks (DEF) // note: crossPoints will be initialized in LayerList pitch = rsynTrack.getSpace(); DBU location = rsynTrack.getLocation(); for (int i = 0; i < rsynTrack.getNumberOfTracks(); ++i) { tracks.emplace_back(location); location += pitch; } // safe margin minAreaMargin = ceil(((minArea / width) + width) * 1.0 / pitch) * pitch * 2; // Check consistency between LEF and DEF check(); } bool MetalLayer::isTrackRangeValid(const utils::IntervalT& trackRange) const { return trackRange.low >= 0 && trackRange.high < tracks.size() && trackRange.IsValid(); } bool MetalLayer::isTrackRangeWeaklyValid(const utils::IntervalT& trackRange) const { return trackRange.low >= 0 && trackRange.low < tracks.size() && trackRange.high >= 0 && trackRange.high < tracks.size(); } utils::IntervalT MetalLayer::getUpperCrossPointRange(const utils::IntervalT& trackRange) const { return {tracks[trackRange.low].upperCPIdx, tracks[trackRange.high].upperCPIdx}; } utils::IntervalT MetalLayer::getLowerCrossPointRange(const utils::IntervalT& trackRange) const { return {tracks[trackRange.low].lowerCPIdx, tracks[trackRange.high].lowerCPIdx}; } utils::IntervalT MetalLayer::getSurroundingTrack(DBU loc) const { // offset by firstTrackLoc(), make it within track range, and round const double floatingTrackIdx = (std::min(std::max(firstTrackLoc(), loc), lastTrackLoc()) - firstTrackLoc()) / static_cast(pitch); return {floor(floatingTrackIdx), ceil(floatingTrackIdx)}; } utils::IntervalT MetalLayer::rangeSearchTrack(const utils::IntervalT& locRange, bool includeBound) const { auto locRangeCopy = locRange; // invalid range (low >= high) will still be invalid if (locRangeCopy.low < firstTrackLoc()) { locRangeCopy.low = firstTrackLoc(); } if (locRangeCopy.high > lastTrackLoc()) { locRangeCopy.high = lastTrackLoc(); } utils::IntervalT res{ceil(double(locRangeCopy.low - firstTrackLoc()) / double(pitch)), floor(double(locRangeCopy.high - firstTrackLoc()) / double(pitch))}; if (!includeBound) { if (res.high >= 0 && res.high < numTracks() && tracks[res.high].location == locRange.high) --res.high; if (res.low >= 0 && res.low < numTracks() && tracks[res.low].location == locRange.low) ++res.low; } return res; } bool MetalLayer::isCrossPointRangeValid(const utils::IntervalT& crossPointRange) const { return crossPointRange.low >= 0 && crossPointRange.high < crossPoints.size() && crossPointRange.IsValid(); } void MetalLayer::initAccCrossPointDistCost() { accCrossPointDistCost.resize(numCrossPoints() + 1); accCrossPointDistCost[0] = 0; // For four uniform-distributed crossPoints with dist 1: // accCrossPointCost = {0, 0.5, 1.5, 2.5, 3} for (int cpIdx = 0; cpIdx < numCrossPoints(); ++cpIdx) { DBU delta = 0; if ((cpIdx + 1) < numCrossPoints()) { delta = (crossPoints[cpIdx + 1].location - crossPoints[cpIdx].location) / 2; } accCrossPointDistCost[cpIdx + 1] = crossPoints[cpIdx].location - crossPoints[0].location + delta; } } DBU MetalLayer::getCrossPointRangeDistCost(const utils::IntervalT& crossPointRange) const { assert(crossPointRange.IsValid()); return accCrossPointDistCost[crossPointRange.high + 1] - accCrossPointDistCost[crossPointRange.low]; } DBU MetalLayer::getCrossPointRangeDist(const utils::IntervalT& crossPointRange) const { return crossPoints[crossPointRange.high].location - crossPoints[crossPointRange.low].location; } utils::PointT MetalLayer::getLoc(const GridPoint& grid) const { utils::PointT loc; loc[direction] = tracks[grid.trackIdx].location; loc[1 - direction] = crossPoints[grid.crossPointIdx].location; return loc; } std::pair, utils::PointT> MetalLayer::getLoc(const GridEdge& edge) const { utils::PointT loc1 = getLoc(edge.u); utils::PointT loc2 = getLoc(edge.v); if (loc1.x == loc2.x) { if (loc1.y < loc2.y) return {loc1, loc2}; else return {loc2, loc1}; } else { if (loc1.x < loc2.x) return {loc1, loc2}; else return {loc2, loc1}; } } BoxOnLayer MetalLayer::getLoc(const GridBoxOnLayer& gridBox) const { BoxOnLayer box; box.layerIdx = gridBox.layerIdx; box[direction].Set(tracks[gridBox.trackRange.low].location, tracks[gridBox.trackRange.high].location); box[1 - direction].Set(crossPoints[gridBox.crossPointRange.low].location, crossPoints[gridBox.crossPointRange.high].location); return box; } GridPoint MetalLayer::getUpper(const GridPoint& cur) const { return {cur.layerIdx + 1, crossPoints[cur.crossPointIdx].upperTrackIdx, tracks[cur.trackIdx].upperCPIdx}; } GridPoint MetalLayer::getLower(const GridPoint& cur) const { return {cur.layerIdx - 1, crossPoints[cur.crossPointIdx].lowerTrackIdx, tracks[cur.trackIdx].lowerCPIdx}; } bool MetalLayer::isValid(const GridPoint& gridPt) const { return gridPt.trackIdx >= 0 && gridPt.trackIdx < tracks.size() && // track gridPt.crossPointIdx >= 0 && gridPt.crossPointIdx < crossPoints.size(); // cross point } bool MetalLayer::isValid(const GridBoxOnLayer& gridBox) const { return isTrackRangeValid(gridBox.trackRange) && isCrossPointRangeValid(gridBox.crossPointRange); } DBU MetalLayer::getParaRunSpace(const DBU width, const DBU length) const { int iWidth = parallelWidth.size() - 1; // first smaller than or equal to while (iWidth > 0 && parallelWidth[iWidth] >= width) { --iWidth; } if (length == 0) return parallelWidthSpace[iWidth][0]; // fast return int iLength = parallelLength.size() - 1; // first smaller than or equal to while (iLength > 0 && parallelLength[iLength] >= length) { --iLength; } return parallelWidthSpace[iWidth][iLength]; } DBU MetalLayer::getParaRunSpace(const utils::BoxT& targetMetal, const DBU length) const { return getParaRunSpace(min(targetMetal.width(), targetMetal.height()), length); } DBU MetalLayer::getSpace(const utils::BoxT& targetMetal, int dir, AggrParaRunSpace aggr) const { const DBU range = targetMetal[1 - dir].range(); DBU space = getEolSpace(range); if (!space) { // parallel run spacing DBU length = 0; if (aggr == AggrParaRunSpace::LARGER_LENGTH && targetMetal[1 - dir].range() > 100 * pitch) { // hack: assume at least two-pitch parallel run length length = (pitch * 2 + width); } space = getParaRunSpace(targetMetal, length); } // do not know the width of neighbor, so paraRunSpaceForLargerWidth if (aggr == AggrParaRunSpace::LARGER_WIDTH && paraRunSpaceForLargerWidth > space) { space = paraRunSpaceForLargerWidth; } return space; } DBU MetalLayer::getEolSpace(const DBU width) const { return (width < maxEolWidth) ? maxEolSpace : 0; } bool MetalLayer::isEolViolation(const DBU space, const DBU width, const DBU within) const { return (space < maxEolSpace && width < maxEolWidth && within < maxEolWithin); } bool MetalLayer::isEolViolation(const utils::BoxT& lhs, const utils::BoxT& rhs) const { for (unsigned dim = 0; dim != 2; ++dim) { const DBU space = utils::Dist(lhs[1 - dim], rhs[1 - dim]); const DBU width = min(lhs[dim].range(), rhs[dim].range()); const DBU within = utils::Dist(lhs[dim], rhs[dim]); if (isEolViolation(space, width, within)) return true; } return false; } DBU MetalLayer::getCornerSpace(const DBU width) const { if (cornerExceptEol && width < cornerEolWidth) return 0; int iWidth = cornerWidth.size() - 1; // first smaller than or equal to while (iWidth > 0 && cornerWidth[iWidth] >= width) { --iWidth; } return cornerWidthSpace[iWidth]; } DBU MetalLayer::getCornerSpace(const utils::BoxT& targetMetal) const { return getCornerSpace(min(targetMetal.width(), targetMetal.height())); } void MetalLayer::initWireRange() { const DBU eolSpace = getEolSpace(width); const DBU wireEndPointSpace = eolSpace ? eolSpace + width : defaultSpace + width; // consider two half width wireRange.resize(numCrossPoints(), {0, 0}); int i, j; for (int cpIdx = 0; cpIdx < numCrossPoints(); ++cpIdx) { i = 0; while (cpIdx + i >= 0 && crossPoints[cpIdx].location - crossPoints[cpIdx + i].location < wireEndPointSpace) { --i; } j = 0; while (cpIdx + j < numCrossPoints() && crossPoints[cpIdx + j].location - crossPoints[cpIdx].location < wireEndPointSpace) { ++j; } wireRange[cpIdx] = {i + 1, j - 1}; } } ostream& MetalLayer::printBasics(ostream& os) const { os << name << ": dir=" << getDimension(direction) << ", idx=" << idx; os << ", tracks=(locs=" << firstTrackLoc() << "-" << lastTrackLoc() << ",pitch=" << pitch << ",#=" << numTracks() << ")"; os << ", crossPts=(locs=" << firstCrossPointLoc() << "-" << lastCrossPointLoc() << ",#=" << numCrossPoints() << ")"; os << ", #grids=" << numGridPoints() << ")"; return os; } ostream& MetalLayer::printDesignRules(ostream& os) const { os << name << ": width=" << width << ", paraSpace=(default=" << defaultSpace; for (int i = 0; i < parallelWidth.size(); ++i) { os << ", " << parallelWidth[i] << ":" << parallelWidthSpace[i]; } os << "), eolSpace=("; for (const SpaceRule& spaceRule : spaceRules) { if (spaceRule.hasEol /* && !spaceRule.hasPar */) { os << spaceRule.eolWidth << ':' << spaceRule.space << ", "; } } os << "), minArea=" << minArea; return os; } ostream& MetalLayer::printViaOccupancyLUT(ostream& os) const { auto getMaxSize2d = [](const vector>>& LUT, size_t& xSize, size_t& ySize) { xSize = 0; ySize = 0; for (const vector>& cpLUT : LUT) { if (cpLUT.size()) { xSize = max(xSize, cpLUT.size()); ySize = max(ySize, cpLUT[0].size()); } } }; auto getMaxSize1d = [](const vector>& ranges, utils::IntervalT& yRange) { yRange = {0, 0}; for (const auto& rangeCP : ranges) { yRange = yRange.UnionWith(rangeCP); } }; size_t xSize, ySize; utils::IntervalT yRange; getMaxSize1d(wireRange, yRange); os << name << ": wire(" << wireRange.size() << ',' << yRange << ')'; if (wireBotVia.size()) { getMaxSize2d(wireBotVia[0], xSize, ySize); // TODO: print default os << ", wireBotVia(" << wireBotVia.size() << ',' << xSize << ',' << ySize << ')'; } if (wireTopVia.size()) { getMaxSize2d(wireTopVia[0], xSize, ySize); os << ", wireTopVia(" << wireTopVia.size() << ',' << xSize << ',' << ySize << ')'; } return os; } ostream& operator<<(ostream& os, const MetalLayer& layer) { return layer.printBasics(os); } void MetalLayer::check() const { if (width < minWidth) { log() << "Warning: In layer " << name << ", width = " << width << " < minWidth = " << minWidth << std::endl; } if (width > maxEolWidth) { log() << "Warning: In layer " << name << ", width = " << width << " > maxEolWidth = " << maxEolWidth << std::endl; } if (width + defaultSpace > pitch) { log() << "Warning: In layer " << name << ", width + defaultSpace =" << width + defaultSpace << " > picth = " << pitch << std::endl; } } } // namespace db ================================================ FILE: src/db/MetalLayer.h ================================================ #pragma once #include "GeoPrimitive.h" namespace db { class Track { public: Track(DBU loc, int lowerIdx = -1, int upperIdx = -1) : location(loc), lowerCPIdx(lowerIdx), upperCPIdx(upperIdx) {} DBU location; int lowerCPIdx; int upperCPIdx; friend ostream& operator<<(ostream& os, const Track& track); }; // Cross points are projection of tracks from upper and lower layers class CrossPoint { public: CrossPoint(DBU loc, int lowerIdx = -1, int upperIdx = -1) : location(loc), lowerTrackIdx(lowerIdx), upperTrackIdx(upperIdx) {} DBU location; int lowerTrackIdx; int upperTrackIdx; friend ostream& operator<<(ostream& os, const CrossPoint& cp); }; class SpaceRule { public: SpaceRule(const DBU space, const DBU eolWidth, const DBU eolWithin) : space(space), hasEol(true), eolWidth(eolWidth), eolWithin(eolWithin) {} SpaceRule(const DBU space, const DBU eolWidth, const DBU eolWithin, const DBU parSpace, const DBU parWithin) : space(space), hasEol(true), eolWidth(eolWidth), eolWithin(eolWithin), hasPar(true), parSpace(parSpace), parWithin(parWithin) {} DBU space = 0; bool hasEol = false; DBU eolWidth = 0; DBU eolWithin = 0; bool hasPar = false; DBU parSpace = 0; DBU parWithin = 0; }; enum class AggrParaRunSpace { DEFAULT, LARGER_WIDTH, LARGER_LENGTH }; // note: for operations on GeoPrimitives, all checking is down in LayerList for low level efficiency class MetalLayer { public: MetalLayer(Rsyn::PhysicalLayer rsynLayer, Rsyn::PhysicalTracks rsynTrack, const DBU libDBU); // Basic infomation std::string name; Dimension direction; // direction of track dimension int idx; // layerIdx (consistent with Rsyn::xxx::getRelativeIndex()) // Track (1D) DBU pitch = 0; vector tracks; int numTracks() const { return tracks.size(); } DBU firstTrackLoc() const { return tracks.front().location; } DBU lastTrackLoc() const { return tracks.back().location; } bool isTrackRangeValid(const utils::IntervalT& trackRange) const; bool isTrackRangeWeaklyValid(const utils::IntervalT& trackRange) const; utils::IntervalT getUpperCrossPointRange(const utils::IntervalT& trackRange) const; utils::IntervalT getLowerCrossPointRange(const utils::IntervalT& trackRange) const; // search by location (range) (result may be invalid/empty) utils::IntervalT getSurroundingTrack(DBU loc) const; utils::IntervalT rangeSearchTrack(const utils::IntervalT& locRange, bool includeBound = true) const; // CrossPoint (1D) vector crossPoints; int numCrossPoints() const { return crossPoints.size(); } DBU firstCrossPointLoc() const { return crossPoints.front().location; } DBU lastCrossPointLoc() const { return crossPoints.back().location; } bool isCrossPointRangeValid(const utils::IntervalT& crossPointRange) const; // base grid cost without congestion penalty // edge cost = accCrossPointCost[crossPointRange.high + 1] - accCrossPointCost[crossPointRange.low] // cost is directly posed on grids instead of edges (easier to cross layers & handle corners) vector accCrossPointDistCost; void initAccCrossPointDistCost(); DBU getCrossPointRangeDistCost(const utils::IntervalT& crossPointRange) const; DBU getCrossPointRangeDist(const utils::IntervalT& crossPointRange) const; // GridPoint (2D) = Track (1D) x CrossPoint (1D) int numGridPoints() const { return tracks.size() * crossPoints.size(); } bool isValid(const GridPoint& gridPt) const; bool isValid(const GridBoxOnLayer& gridBox) const; utils::PointT getLoc(const GridPoint& grid) const; BoxOnLayer getLoc(const GridBoxOnLayer& gridBox) const; std::pair, utils::PointT> getLoc(const GridEdge& edge) const; GridPoint getUpper(const GridPoint& cur) const; GridPoint getLower(const GridPoint& cur) const; // Design rules // width DBU width = 0; DBU minWidth = 0; DBU widthForSuffOvlp = 0; DBU shrinkForSuffOvlp = 0; // minArea DBU minArea = 0; DBU minLenRaw = 0; DBU minLenOneVia = 0; DBU minLenTwoVia = 0; DBU viaOvlpDist = 0; DBU viaLenEqLen = 0; DBU viaWidthEqLen = 0; bool hasMinLenVio(DBU len) const { return len < getMinLen(); } bool hasMinLenVioAcc(DBU len) const { return len < getMinLenAcc(len); } DBU getMinLen() const { return minLenRaw; } DBU getMinLenAcc(DBU len) const { return len < viaOvlpDist ? minLenOneVia : minLenTwoVia; } // parallel spacing vector parallelWidth{0}; vector parallelLength{0}; vector> parallelWidthSpace{{0}}; DBU defaultSpace = 0; DBU paraRunSpaceForLargerWidth = 0; DBU getParaRunSpace(const DBU width, const DBU length = 0) const; DBU getParaRunSpace(const utils::BoxT& targetMetal, const DBU length = 0) const; // eol spacing // TODO: handle multiple spaceRules vector spaceRules; DBU maxEolSpace = 0; DBU maxEolWidth = 0; DBU maxEolWithin = 0; DBU getEolSpace(const DBU width) const; bool isEolViolation(const DBU space, const DBU width, const DBU within) const; bool isEolViolation(const utils::BoxT& lhs, const utils::BoxT& rhs) const; // corner spacing bool cornerExceptEol = false; DBU cornerEolWidth = 0; vector cornerWidth{0}; vector cornerWidthSpace{0}; bool hasCornerSpace() const { return cornerWidthSpace.size() > 1 || cornerWidthSpace[0]; } DBU getCornerSpace(const DBU width) const; DBU getCornerSpace(const utils::BoxT& targetMetal) const; // Translate design rule // either both parallel-run spacing or eol spacing DBU getSpace(const utils::BoxT& targetMetal, int dir, AggrParaRunSpace aggr) const; // there is parallel-run spacing with negative length if the targetMetal is not eol dominated bool isEolDominated(const utils::BoxT& targetMetal) const { return max(targetMetal.x.range(), targetMetal.y.range()) < maxEolWidth; } // margin for multi-thread safe and others DBU minAreaMargin = 0; DBU confLutMargin = 0; DBU fixedMetalQueryMargin = 0; DBU mtSafeMargin = 0; // Via conflict lookup table (true means "available" / no conflict) // 1. wire-via conflict (viaTypeIdx, crossPointIdx, trackIdx, crossPointIdx) vector>>> wireBotVia; vector>>> wireTopVia; vector>> mergedWireBotVia; vector>> mergedWireTopVia; bool isWireViaMultiTrack = false; // 2. wire-wire conflict (crossPointIdx, crossPointIdx) vector> wireRange; void initWireRange(); ostream& printBasics(ostream& os) const; ostream& printDesignRules(ostream& os) const; ostream& printViaOccupancyLUT(ostream& os) const; friend ostream& operator<<(ostream& os, const MetalLayer& layer); private: void check() const; }; } // namespace db ================================================ FILE: src/db/Net.cpp ================================================ #include "Net.h" #include #include "Setting.h" namespace db { NetBase::~NetBase() {} BoxOnLayer NetBase::getMaxAccessBox(int pinIdx) const { DBU maxArea = std::numeric_limits::min(); db::BoxOnLayer bestBox; for (const auto& box : pinAccessBoxes[pinIdx]) { if (maxArea < box.area()) { maxArea = box.area(); bestBox = box; } } return bestBox; } void NetBase::print(ostream& os) const { os << "Net " << getName() << " (idx = " << idx << ") with " << numOfPins() << " pins " << std::endl; for (int i = 0; i < numOfPins(); ++i) { os << "pin " << i << " " << rsynPins[i].getInstanceName() << std::endl; for (auto& accessBox : pinAccessBoxes[i]) { os << accessBox << std::endl; } } os << routeGuides.size() << " route guides" << std::endl; if (routeGuides.size() == gridRouteGuides.size()) { for (int i = 0; i < routeGuides.size(); ++i) { os << routeGuides[i] << " " << gridRouteGuides[i] << std::endl; } } else { for (auto& routeGuide : routeGuides) { os << routeGuide << std::endl; } } os << std::endl; } Net::Net(int i, Rsyn::Net net, RsynService& rsynService) { idx = i; rsynNet = net; // pins pinAccessBoxes.reserve(net.getNumPins()); const Rsyn::Session session; const Rsyn::PhysicalDesign& physicalDesign = static_cast(session.getService("rsyn.physical"))->getPhysicalDesign(); const DBU libDBU = physicalDesign.getDatabaseUnits(Rsyn::LIBRARY_DBU); for (auto RsynPin : net.allPins()) { rsynPins.push_back(RsynPin); pinAccessBoxes.emplace_back(); initPinAccessBoxes(RsynPin, rsynService, pinAccessBoxes.back(), libDBU); } } void Net::initPinAccessBoxes(Rsyn::Pin rsynPin, RsynService& rsynService, vector& accessBoxes, const DBU libDBU) { // PhysicalPort if (rsynPin.isPort()) { Rsyn::PhysicalPort phPort = rsynService.physicalDesign.getPhysicalPort(rsynPin.getPort()); getPinAccessBoxes(phPort, accessBoxes); return; } // PhysicalLibraryPin Rsyn::PhysicalLibraryPin phLibPin = rsynService.physicalDesign.getPhysicalLibraryPin(rsynPin); // PhysicalCell Rsyn::Instance instance = rsynPin.getInstance(); if (instance.getType() != Rsyn::CELL) { log() << "Warning: pin is not on a cell " << rsynPin.getNetName() << " " << rsynPin.getInstanceName() << std::endl; return; } Rsyn::Cell cell = instance.asCell(); Rsyn::PhysicalCell phCell = rsynService.physicalDesign.getPhysicalCell(cell); Rsyn::PhysicalLibraryCell phLibCell = rsynService.physicalDesign.getPhysicalLibraryCell(cell); const DBUxy origin(static_cast(std::round(phLibCell.getMacro()->originX() * libDBU)), static_cast(std::round(phLibCell.getMacro()->originY() * libDBU))); // fill accessBoxes getPinAccessBoxes(phLibPin, phCell, accessBoxes, origin); }; void Net::getPinAccessBoxes(Rsyn::PhysicalPort phPort, vector& accessBoxes) { auto displacement = phPort.getPosition(); auto bounds = phPort.getBounds(); Bounds dummyCellBounds(displacement, displacement); Rsyn::PhysicalTransform transform(dummyCellBounds, phPort.getOrientation()); bounds.translate(displacement); bounds = transform.apply(bounds); accessBoxes.emplace_back(phPort.getLayer().getRelativeIndex(), getBoxFromRsynBounds(bounds)); } void Net::getPinAccessBoxes(Rsyn::PhysicalLibraryPin phLibPin, Rsyn::PhysicalCell phCell, vector& accessBoxes, const DBUxy& origin) { if (!phLibPin.hasPinGeometries()) { log() << "Warning: pin of " << phCell.getName() << " has no pinGeometries" << std::endl; return; } const DBUxy displacement = phCell.getPosition() + origin; auto transform = phCell.getTransform(); // for (Rsyn::PhysicalPinGeometry phPinGeo : phLibPin.allPinGeometries()) { // TODO: check why multiple PinGeometry on 8t4 inst60849 auto phPinGeo = phLibPin.allPinGeometries()[0]; for (Rsyn::PhysicalPinLayer phPinLayer : phPinGeo.allPinLayers()) { if (!phPinLayer.hasRectangleBounds()) { log() << "Warning: pin has no RectangleBounds" << std::endl; continue; } int layerIdx = phPinLayer.getLayer().getRelativeIndex(); for (auto bounds : phPinLayer.allBounds()) { bounds.translate(displacement); bounds = transform.apply(bounds); accessBoxes.emplace_back(layerIdx, getBoxFromRsynBounds(bounds)); } } } void NetList::init(RsynService& rsynService) { if (db::setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { log() << "Init NetList ..." << std::endl; } nets.reserve(rsynService.design.getNumNets()); int numPins = 0; for (Rsyn::Net net : rsynService.module.allNets()) { switch (net.getUse()) { case Rsyn::POWER: continue; case Rsyn::GROUND: continue; default: break; } nets.emplace_back(nets.size(), net, rsynService); numPins += nets.back().pinAccessBoxes.size(); } if (setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { log() << "The number of nets is " << nets.size() << std::endl; log() << "The number of pins is " << numPins << std::endl; log() << std::endl; } } } // namespace db ================================================ FILE: src/db/Net.h ================================================ #pragma once #include "RsynService.h" #include "GeoPrimitive.h" namespace db { class NetBase { public: ~NetBase(); int idx; Rsyn::Net rsynNet; const std::string& getName() const { return rsynNet.getName(); } // pins vector rsynPins; vector> pinAccessBoxes; // (pinIdx, accessBoxIdx) -> BoxOnLayer unsigned numOfPins() const noexcept { return pinAccessBoxes.size(); } BoxOnLayer getMaxAccessBox(int pinIdx) const; // route guides vector routeGuides; vector gridRouteGuides; void print(ostream& os = std::cout) const; }; class Net : public NetBase { public: Net(int i, Rsyn::Net net, RsynService& rsynService); // more route guide information vector routeGuideVios; RTrees routeGuideRTrees; // for initialization void initPinAccessBoxes(Rsyn::Pin rsynPin, RsynService& rsynService, vector& accessBoxes, const DBU libDBU); static void getPinAccessBoxes(Rsyn::PhysicalPort phPort, vector& accessBoxes); static void getPinAccessBoxes(Rsyn::PhysicalLibraryPin phLibPin, Rsyn::PhysicalCell phCell, vector& accessBoxes, const DBUxy& origin); void clearPostRouteResult(); void clearResult(); }; class NetList { public: vector nets; void init(RsynService& rsynService); }; } // namespace db ================================================ FILE: src/db/RouteGrid.cpp ================================================ #include "RouteGrid.h" namespace db { void RouteGrid::init() { if (db::setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { log() << "Init RouteGrid ..." << std::endl; } LayerList::init(); // Fixed metal fixedMetals.resize(layers.size()); DBU m2Pitch = layers[1].pitch; unitWireCostRaw = db::Setting::weightWirelength / m2Pitch; unitViaCostRaw = db::Setting::weightViaNum; unitViaCost = unitViaCostRaw / unitWireCostRaw; unitShortVioCostRaw = db::Setting::weightShortArea; // note: a short of M2 track segments will be charged by // (shortLength * unitWireCostRaw) * unitShortVioCost // which should be unitShortVioCostRaw * (shortLength / m2Pitch) * (layers[i].width / m2Pitch) // Therefore, unitShortVioCost = unitShortVioCostRaw * layers[i].width / m2Pitch / m2Pitch / unitWireCostRaw unitShortVioCost.resize(layers.size()); for (int i = 0; i < layers.size(); ++i) { unitShortVioCost[i] = unitShortVioCostRaw * layers[i].width / m2Pitch / m2Pitch / unitWireCostRaw; } unitShortVioCostDiscounted.resize(unitShortVioCost.size()); setUnitVioCost(); if (setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { // LayerList::print(); log() << "ROUTE GRID COST" << std::endl; log() << "unitWireCostRaw (score / DBU) = " << unitWireCostRaw << std::endl; log() << "unitViaCostRaw (score for each via) = " << unitViaCostRaw << std::endl; log() << "unitShortVioCostRaw (score for each area of m2Pitch * m2Pitch) = " << unitShortVioCostRaw << std::endl; log() << "After normalization by unitWireCostRaw: " << std::endl; log() << "unitWireCost (in DBU) = 1" << std::endl; log() << "unitViaCost (in DBU) = " << unitViaCost << std::endl; log() << "unitShortVioCost (coeff for \"normal\" short) = " << unitShortVioCost << std::endl; log() << std::endl; } } void RouteGrid::clear() { // Fixed metal fixedMetals.clear(); } void RouteGrid::setUnitVioCost(double discount) { if (setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { printlog("Set unit vio cost with discount of", discount); } for (int i = 0; i < unitShortVioCost.size(); ++i) { unitShortVioCostDiscounted[i] = unitShortVioCost[i] * discount; } } int RouteGrid::getFixedMetalVio(const BoxOnLayer& box, int netIdx) const { auto regions = getAccurateMetalRectForbidRegions(box); utils::BoxT queryBox = box; queryBox.x.low -= layers[box.layerIdx].fixedMetalQueryMargin; queryBox.x.high += layers[box.layerIdx].fixedMetalQueryMargin; queryBox.y.low -= layers[box.layerIdx].fixedMetalQueryMargin; queryBox.y.high += layers[box.layerIdx].fixedMetalQueryMargin; for (const auto& region : regions) { queryBox = queryBox.UnionWith(region); } boostBox rtreeQueryBox(boostPoint(queryBox.x.low, queryBox.y.low), boostPoint(queryBox.x.high, queryBox.y.high)); vector> queryResults; fixedMetals[box.layerIdx].query(bgi::intersects(rtreeQueryBox), std::back_inserter(queryResults)); vector, int>> neighMetals; for (const auto& queryResult : queryResults) { if (queryResult.second != netIdx) { const auto& b = queryResult.first; neighMetals.emplace_back(utils::BoxT(bg::get(b), bg::get(b), bg::get(b), bg::get(b)), queryResult.second); } } int numOvlp = 0; for (const auto& neighMetal : neighMetals) { // getOvlpFixedMetals for (auto forbidRegion : regions) { auto ovlp = forbidRegion.IntersectWith(neighMetal.first); if (ovlp.IsValid()) { numOvlp += (ovlp.area() > 0); } } // getOvlpFixedMetalForbidRegions auto forbidRegions = getAccurateMetalRectForbidRegions({box.layerIdx, neighMetal.first}); for (auto forbidRegion : forbidRegions) { auto ovlp = forbidRegion.IntersectWith(box); if (ovlp.IsValid()) { numOvlp += (ovlp.area() > 0); } } // getOvlpC2CMetals if (!layers[box.layerIdx].isEolDominated(neighMetal.first)) { DBU space = layers[box.layerIdx].getParaRunSpace(neighMetal.first); numOvlp += (utils::L2Dist(box, neighMetal.first) < space); } } return numOvlp; } DBU RouteGrid::getOvlpFixedMetalArea(const BoxOnLayer& box, int netIdx) const { utils::BoxT queryBox = box; boostBox rtreeQueryBox(boostPoint(queryBox.x.low, queryBox.y.low), boostPoint(queryBox.x.high, queryBox.y.high)); vector> queryResults; fixedMetals[box.layerIdx].query(bgi::intersects(rtreeQueryBox), std::back_inserter(queryResults)); vector, int>> neighMetals; for (const auto& queryResult : queryResults) { if (queryResult.second != netIdx) { const auto& b = queryResult.first; neighMetals.emplace_back(utils::BoxT(bg::get(b), bg::get(b), bg::get(b), bg::get(b)), queryResult.second); } } DBU area = 0; for (const auto& neighMetal : neighMetals) { auto ovlp = queryBox.IntersectWith(neighMetal.first); if (ovlp.IsValid()) area += ovlp.area(); } return area; } vector, int>> RouteGrid::getOvlpBoxes(const BoxOnLayer& box, int idx, const RTrees& rtrees) const { boostBox queryBox(boostPoint(box.x.low, box.y.low), boostPoint(box.x.high, box.y.high)); vector> queryResults; rtrees[box.layerIdx].query(bgi::intersects(queryBox), std::back_inserter(queryResults)); vector, int>> results; for (const auto& queryResult : queryResults) { if (queryResult.second != idx) { const auto& b = queryResult.first; results.emplace_back(utils::BoxT(bg::get(b), bg::get(b), bg::get(b), bg::get(b)), queryResult.second); } } return results; } vector, int>> RouteGrid::getOvlpFixedMetals(const BoxOnLayer& box, int netIdx) const { return getOvlpBoxes(box, netIdx, fixedMetals); } void RouteGrid::markFixedMetalBatch(vector>& fixedMetalVec, int beginIdx, int endIdx) { vector>> fixedMetalsRtreeItems; fixedMetalsRtreeItems.resize(layers.size()); if (setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { log() << "mark fixed metal batch ..." << std::endl; } const int initMem = utils::mem_use::get_current(); vector> layerToObjIdx(getLayerNum()); for (unsigned i = beginIdx; i < endIdx; i++) layerToObjIdx[fixedMetalVec[i].first.layerIdx].push_back(i); int curLayer = 0; std::mutex layer_mutex; auto thread_func = [&]() { while (true) { layer_mutex.lock(); int l = curLayer++; layer_mutex.unlock(); if (l >= getLayerNum()) return; for (auto idx : layerToObjIdx[l]) { // fixedMetals const BoxOnLayer& box = fixedMetalVec[idx].first; int netIdx = fixedMetalVec[idx].second; boostBox markBox(boostPoint(box.x.low, box.y.low), boostPoint(box.x.high, box.y.high)); fixedMetalsRtreeItems[box.layerIdx].push_back({markBox, netIdx}); DBU space = layers[box.layerIdx].getParaRunSpace(box); if (space > layers[box.layerIdx].fixedMetalQueryMargin) { layers[box.layerIdx].fixedMetalQueryMargin = space; } } } }; const int numThreads = max(1, db::setting.numThreads); std::thread threads[numThreads]; for (int i = 0; i < numThreads; i++) threads[i] = std::thread(thread_func); for (int i = 0; i < numThreads; i++) threads[i].join(); const int curMem = utils::mem_use::get_current(); if (setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { printflog("MEM(MB): init/cur=%d/%d, incr=%d\n", initMem, curMem, curMem - initMem); log() << std::endl; } if (!beginIdx) { for (int layerIdx = 0; layerIdx < layers.size(); layerIdx++) { RTree tRtree(fixedMetalsRtreeItems[layerIdx]); fixedMetals[layerIdx] = boost::move(tRtree); } } else { for (int layerIdx = 0; layerIdx < layers.size(); layerIdx++) { for (auto& item : fixedMetalsRtreeItems[layerIdx]) fixedMetals[layerIdx].insert(item); } } } } // namespace db ================================================ FILE: src/db/RouteGrid.h ================================================ #pragma once #include "LayerList.h" #include "Net.h" #include "Setting.h" namespace db { class ViaData; using CostT = double; struct mutex_wrapper : std::mutex { mutex_wrapper() = default; mutex_wrapper(mutex_wrapper const&) noexcept : std::mutex() {} bool operator==(mutex_wrapper const& other) noexcept { return this == &other; } }; // net index // a valid net idx >= 0 const int OBS_NET_IDX = -1; // for obstacles const int NULL_NET_IDX = -2; // for neither net nor obstacle class RouteGrid : public LayerList { public: using ViaMapT = vector>>; using NDViaMapT = std::unordered_map; void init(); void clear(); void setUnitVioCost(double discount = 1.0); // Query fixed metals vector, int>> getOvlpBoxes(const BoxOnLayer& box, int idx, const RTrees& rtree) const; vector, int>> getOvlpFixedMetals(const BoxOnLayer& box, int netIdx) const; int getFixedMetalVio(const BoxOnLayer& box, int netIdx) const; DBU getOvlpFixedMetalArea(const BoxOnLayer& box, int netIdx) const; void markFixedMetalBatch(vector>& fixedMetalVec, int beginIdx, int endIdx); const RTree& getFixedMetals(int layerIdx) const { return fixedMetals[layerIdx]; } DBU getUnitViaCost() const { return unitViaCost; } DBU getUnitShortCost(int layerIdx) const { return unitShortVioCostDiscounted[layerIdx]; } protected: // Unit cost // in contest metric CostT unitWireCostRaw; // for each DBU CostT unitViaCostRaw; // for each occurrence CostT unitShortVioCostRaw; // for each area of m2Pitch * m2Pitch vector unitShortVioCost, unitShortVioCostDiscounted; // ceoff (no unit), a M2 short will charged by // (shortLength * unitWireCostRaw) * unitShortVioCost // in DBU CostT unitViaCost; // for each occurrence // Fixed metals (e.g., cell pins, blockage) RTrees fixedMetals; // box -> netIdx }; } // namespace db ================================================ FILE: src/db/RsynService.h ================================================ #pragma once #include "global.h" namespace db { class RsynService { public: Rsyn::PhysicalService* physicalService; // Rsyn::RoutingGuide* routeGuideService; Rsyn::PhysicalDesign physicalDesign; Rsyn::Design design; Rsyn::Module module; void init() { Rsyn::Session session; physicalService = session.getService("rsyn.physical"); // routeGuideService = session.getService("rsyn.routingGuide"); physicalDesign = physicalService->getPhysicalDesign(); design = session.getDesign(); module = design.getTopModule(); } }; } ================================================ FILE: src/db/Setting.cpp ================================================ #include "Setting.h" #include "Database.h" namespace db { void Setting::makeItSilent() { multiNetVerbose = VerboseLevelT::LOW; dbVerbose = VerboseLevelT::LOW; } void Setting::adapt() { if (database.nets.size() > 800000) { --rrrIterLimit; } } Setting setting; } // namespace db ================================================ FILE: src/db/Setting.h ================================================ #pragma once #include "global.h" namespace db { BETTER_ENUM(VerboseLevelT, int, LOW = 0, MIDDLE = 1, HIGH = 2); // global setting class Setting { public: // basic std::string outputFile; std::string name; int numThreads = 1; // 0 for simple scheduling int tat = std::numeric_limits::max(); // multi_net VerboseLevelT multiNetVerbose = VerboseLevelT::MIDDLE; bool multiNetScheduleSortAll = true; bool multiNetScheduleSort = true; bool multiNetScheduleReverse = true; int multiNetSelectViaTypesIter = 3; int rrrIterLimit = 4; bool rrrWriteEachIter = false; double rrrInitVioCostDiscount = 0.1; double rrrFadeCoeff = 0.01; // should be <= 0.5 to make sure fade/(1-fade) <= 1 int edgeShiftingIter = 2; // single_net VerboseLevelT singleNetVerbose = VerboseLevelT::MIDDLE; bool fixOpenBySST = true; double unitSqrtViaUsage = 1.5; // # of tracks that unit sqrt(via) uses double initLogisticSlope = 1.0; // the slope of the logistic func in cost func // db VerboseLevelT dbVerbose = VerboseLevelT::MIDDLE; int maxNumWarnForEachRouteStatus = 5; bool dbWriteDebugFile = false; double dbInitHistUsageForPinAccess = 0.1; // Metric weights of ISPD 2018 Contest // Wirelength unit is M2 pitch // 1. basic objective static constexpr double weightWirelength = 0.5; static constexpr int weightViaNum = 4; // 2. routing preference static constexpr int weightOutOfGuideWirelength = 1; static constexpr int weightOutOfGuideViaNum = 1; static constexpr double weightOffTrackWirelength = 0.5; static constexpr int weightOffTrackViaNum = 1; static constexpr int weightWrongWayWirelength = 1; static constexpr int wirelenCostWeight = 4; // 3. violation // normalized by square of M2 pitch static constexpr int weightShortArea = 500; // including wire spacing, eol spacing, cut spacing static constexpr int weightSpaceVioNum = 500; static constexpr int weightMinAreaVioNum = 500; void makeItSilent(); void adapt(); }; extern Setting setting; } // namespace db ================================================ FILE: src/db/Stat.cpp ================================================ #include "Stat.h" #include "Setting.h" namespace db { RouteStat routeStat; RouteStatus operator&(const RouteStatus& lhs, const RouteStatus& rhs) { for (auto status : {lhs, rhs}) { if (!isSucc(status)) { return status; } } for (auto status : {lhs, rhs}) { if (status != +RouteStatus::SUCC_NORMAL) { return status; } } return RouteStatus::SUCC_NORMAL; } RouteStatus& operator&=(RouteStatus& lhs, const RouteStatus& rhs) { lhs = lhs & rhs; return lhs; } std::unordered_map descriptions = { {(+db::RouteStatus::FAIL_PIN_OUT_OF_GRID)._to_integral(), "has pin not on grid, skip"}, {(+db::RouteStatus::FAIL_DETACHED_GUIDE)._to_integral(), "has route guide detached from others, skip"}, {(+db::RouteStatus::FAIL_DETACHED_PIN)._to_integral(), "has pin detached from route guides, cannot fix by expanding route guides"}, {(+db::RouteStatus::FAIL_CONN_EXT_PIN)._to_integral(), "has unconnected pin due to access box inflation, cannot fix by add linking wire"}, {(+db::RouteStatus::FAIL_DISCONNECTED_GRID_GRAPH)._to_integral(), "has disconnected grid graph, skip"}}; std::mutex printWarnMsgMutex; void printWarnMsg(RouteStatus status, const Net& net) { if (setting.dbVerbose < +db::VerboseLevelT::MIDDLE || isSucc(status)) { return; } printWarnMsgMutex.lock(); static std::unordered_map counts; int& count = counts[status._to_integral()]; if (count >= db::setting.maxNumWarnForEachRouteStatus) { printWarnMsgMutex.unlock(); return; } std::string desc; auto it = descriptions.find(status._to_integral()); if (it != descriptions.end()) { desc = " (" + it->second + ")"; } log() << "Warning: Net " << net.getName() << " gets " << status._to_string() << desc << std::endl; ++count; if (count == db::setting.maxNumWarnForEachRouteStatus) { log() << "More warnings on " << status._to_string() << " will be suppressed" << std::endl; log() << std::endl; } printWarnMsgMutex.unlock(); } void StageRouteStat::clear() { allNetStatusCounters.clear(); miscEventCounters.clear(); } std::mutex stageRouteStatusMutex; std::mutex miscEventMutex; void StageRouteStat::increment(RouteStatus status) { stageRouteStatusMutex.lock(); ++allNetStatusCounters[status._to_integral()]; stageRouteStatusMutex.unlock(); } void StageRouteStat::increment(MiscRouteEvent misc, int count) { miscEventMutex.lock(); miscEventCounters[misc._to_integral()] += count; miscEventMutex.unlock(); } void StageRouteStat::print(const std::string& stageStr) const { // allNetStatusCounters int numTotal = 0, numSucc = 0; iterateEnumCountersInOrder(allNetStatusCounters, [&](RouteStatus status, int count) { numTotal += count; if (isSucc(status)) { numSucc += count; } }); int numFail = numTotal - numSucc; log() << stageStr << ": #nets = " << numTotal << std::endl; log() << "\t#succ = " << numSucc << " ("; int i = 0; iterateEnumCountersInOrder(allNetStatusCounters, [&](RouteStatus status, int count) { if (isSucc(status)) { std::cout << "#" << status << " = " << count << " "; } ++i; }); std::cout << ")" << std::endl; if (numFail > 0) { log() << "\t#fail = " << numFail << " ("; i = 0; iterateEnumCountersInOrder(allNetStatusCounters, [&](RouteStatus status, int count) { if (!isSucc(status)) { std::cout << "#" << status << " = " << count << " "; } ++i; }); std::cout << ")" << std::endl; } // miscEventCounters if (!miscEventCounters.empty()) { log() << "\tmisc ("; iterateEnumCountersInOrder(miscEventCounters, [&](MiscRouteEvent event, int count) { std::cout << "#" << event << " = " << count << " "; }); std::cout << ")" << std::endl; } } void RouteStat::clear() { stages.clear(); } void RouteStat::print() const { iterateEnumCountersInOrder(stages, [](RouteStage stage, StageRouteStat stageStat) { stageStat.print("Stage " + std::string(stage._to_string())); }); } } // namespace db ================================================ FILE: src/db/Stat.h ================================================ #pragma once #include "Net.h" #include "global.h" namespace db { BETTER_ENUM(RouteStatus, int, // 1. Succ SUCC_NORMAL, // 1.1 pre-route SUCC_ONE_PIN, // 1.2 post-route SUCC_CONN_EXT_PIN, // 2. Fail // 2.0 FAIL_UNPROCESSED, // 2.1 pre route FAIL_PIN_OUT_OF_GRID, FAIL_DETACHED_GUIDE, FAIL_DETACHED_PIN, // 2.2 maze route FAIL_DISCONNECTED_GRID_GRAPH, // 2.3 post route FAIL_CONN_EXT_PIN); BETTER_ENUM(MiscRouteEvent, int, // pre route ADD_DIFF_LAYER_GUIDE_1, ADD_DIFF_LAYER_GUIDE_2, FIX_DETACHED_PIN, // post maze route MIN_AREA_VIO, MIN_AREA_SHADOWED_VIO, REMOVE_TRACK_SWITCH_PIN, REMOVE_TRACK_SWITCH_NORMAL, REMOVE_TRACK_SWITCH_HORSESHOE, // post route LINK_PIN_VIO, FILL_SAME_NET_SPACE, REMOVE_CORNER); BETTER_ENUM(RouteStage, int, INIT, MAZE, ALL); template void iterateEnumCountersInOrder(const std::unordered_map& counters, const std::function& handle) { for (EnumT enumType : EnumT::_values()) { auto it = counters.find(enumType._to_integral()); if (it != counters.end()) { handle(EnumT::_from_integral(it->first), it->second); } } } // switch syntax is not supported by gcc 5 ... constexpr bool isSucc(RouteStatus status) { return status == +RouteStatus::SUCC_NORMAL || status == +RouteStatus::SUCC_ONE_PIN || status == +RouteStatus::SUCC_CONN_EXT_PIN; } // constexpr auto succ = better_enums::make_map(isSucc); // more efficient if many RouteStatus operator&(const RouteStatus& lhs, const RouteStatus& rhs); RouteStatus& operator&=(RouteStatus& lhs, const RouteStatus& rhs); void printWarnMsg(RouteStatus status, const Net& net); class StageRouteStat { public: void clear(); void increment(RouteStatus status); void increment(MiscRouteEvent misc, int count); void print(const std::string& stageStr) const; private: std::unordered_map allNetStatusCounters; std::unordered_map miscEventCounters; }; class RouteStat { public: template void increment(RouteStage stage, Args... params) { routeStatusMutex.lock(); stages[stage._to_integral()].increment(params...); routeStatusMutex.unlock(); } void clear(); void print() const; private: std::unordered_map stages; std::mutex routeStatusMutex; }; extern RouteStat routeStat; } // namespace db ================================================ FILE: src/flute/ChangeLog.txt ================================================ Version 1.0 [Apr. 2004] * Wirelength estimation based on the idea of ICCAD 04 paper. Version 2.0 [Feb. 16, 2005] * RSMT construction and Wirelength estimation based on the idea of ISPD 05 paper. Version 2.1 [Mar. 18, 2005] * The program flute-ckt and associated files are added to compute the FLUTE wirelength for a circuit in bookshelf format. Version 2.2 [Oct. 16, 2005] * The net breaking technique is improved by incorporating the HPWL based estimation in ICCAD 04 paper. * The option to remove duplicated pins is added. * The code is reorganized. Version 2.3 [Sep. 23, 2006] * PORT is renamed to POST (Potentially Optimal Steiner Tree) * The function readLUT() is rewritten to significantly cut the POWV and POST reading time. Version 2.4 [Jan. 16, 2007] * Internal parameters of flutes_wl_MD() and flutes_MD() are tuned to improve runtime-quality tradeoff. * The file size of POST9.dat is reduced by improved encoding. * The function readLUT() is improved to speed up the reading of POST9.dat. * Bookshelf files for ibm01 is included to demonstrate program flute-ckt. Version 2.5 [Jun. 20, 2007] * Local refinement technique is added to improve runtime-accuracy tradeoff for high accuracy. Version 3.0 [Apr. 10, 2008] * Implemented the net breaking and merging ideas of VLSIDAT 08 paper to achieve much better scalability and accuracy for high-degree nets. Version 3.1 [Feb. 28, 2011] * Functions in bookshelf_IO.c and memAlloc.c used by flute-ckt are improved to speed up the reading of GSRC Bookshelf format circuits. ================================================ FILE: src/flute/Readme ================================================ -------------- FLUTE - Version 3.1 ----------------- by Chris C.-N. Chu Dept. of ECpE, Iowa State University Copyright (c) - 2005 Iowa State University Research Foundation, Inc. ---------------------------------------------------- This package contains the following files: flute.c -- The rectilinear Steiner minimal tree and wirelength estimation algorithm described in the ICCAD 04 and ISPD 05 papers with some improvements described in TCAD 07 paper. flute.h -- The interface to use flute. flute_mst.c -- The net breaking and merging techniques described in the VLSIDAT 08 paper. dist.[ch], dl.[ch], err.[ch], heap.[ch], mst2.[ch], neighbors.[ch], global.h -- Utility functions used by flute_mst.c POWV9.dat -- The lookup-table of optimal POWVs up to degree 9. POST9.dat -- The lookup-table for optimal Steiner trees up to degree 9. flute-net.c -- A program to evaluate the wirelength of a net. It takes input from stdin as a list of points. rand-pts.c -- A program to generate a list of random points. flute-ckt.c -- A program to find FLUTE and half-perimeter wirelength of a circuit in bookshelf format. bookshelf_IO.[ch] -- Functions for flute-ckt.c to read bookshelf files. memAlloc.[ch] -- Functions for flute-ckt.c to allocate memory. ibm01/ibm01.* -- ibm01 bookshelf files that can be read by flute-ckt.c license.txt -- License agreement. ChangeLog.txt Makefile Readme To run the programs, first do a 'make'. POWV9.dat and POST9.dat is assume to be in the current directory. Some example commands: rand-pts | flute-net rand-pts 20 | flute-net // 20-pin nets rand-pts -r 20 | flute-net // randomized flute-ckt ibm01 ibm01.aux ibm01/ibm01.pl ================================================ FILE: src/flute/dist.c ================================================ #include "global.h" /*********************************************************************/ /* Return the Manhattan distance between two points */ long dist( Point p, Point q ) { long dx, dy; dx = (p.x) - (q.x); if( dx < 0 ) dx = -dx; dy = (p.y) - (q.y); if( dy < 0 ) dy = -dy; return dx + dy; } /*********************************************************************/ /* Return the Manhattan distance between two points */ long dist2( Point* p, Point* q ) { long dx, dy; dx = (p->x) - (q->x); if( dx < 0 ) dx = -dx; dy = (p->y) - (q->y); if( dy < 0 ) dy = -dy; return dx + dy; } /*********************************************************************/ /*********************************************************************/ ================================================ FILE: src/flute/dist.h ================================================ #ifndef _DIST_H_ #define _DIST_H_ #include "global.h" long dist( Point p, Point q ); long dist2( Point* p, Point* q ); #endif ================================================ FILE: src/flute/dl.c ================================================ #include "dl.h" #include #include dl_t dl_alloc() { dl_t dl = (dl_t)malloc(sizeof(dl_s)); if (!dl) { printf("Out of memory!!\n"); } else { dl->first = dl->last = 0; dl->count = 0; } return dl; } void dl_delete(dl_t dl, dl_el *el) { if (dl->first == el) { dl->first = el->next; } if (dl->last == el) { dl->last = el->prev; } if (el->next) { el->next->prev = el->prev; } if (el->prev) { el->prev->next = el->next; } free(el); dl->count--; } void dl_clear(dl_t dl) { dl_el *el, *next; if (dl->count > 0) { for (el=dl->first; el; el=next) { next = el->next; free(el); } } dl->first = dl->last = 0; dl->count = 0; } void dl_concat(dl_t first_list, dl_t second_list) { if (first_list->count <= 0) { *first_list = *second_list; } else if (second_list->count > 0) { first_list->last->next = second_list->first; second_list->first->prev = first_list->last; first_list->last = second_list->last; first_list->count += second_list->count; } free(second_list); } static void dl_insertion_sort(dl_t dl, size_t el_size, int(*compar)(void *, void *)) { char *buf; void *curr_d, *srch_d; dl_el *curr, *srch; if (dl_length(dl) <= 1) { return; } buf = (char*)malloc(el_size); for (curr=dl->first; curr!=dl->last; curr=curr->next) { curr_d = (void*)(((dl_el*)curr)+1); for (srch=dl->last; srch!=curr; srch=srch->prev) { srch_d = (void*)(((dl_el*)srch)+1); if (compar(curr_d, srch_d) > 0) { memcpy((void*)buf, curr_d, el_size); memcpy(curr_d, srch_d, el_size); memcpy(srch_d, (void*)buf, el_size); } } } free(buf); } void dl_sort(dl_t dl, size_t el_size, int(*compar)(void *, void *)) { dl_el *el, *first_head, *second_head; dl_s first_list, second_list; void *first_item, *second_item; int i, len; if (dl_length(dl) <= 25) { dl_insertion_sort(dl, el_size, compar); return; } len = dl_length(dl)/2; for (i=0, el=dl->first; inext; } first_list.first = dl->first; first_list.last = el->prev; first_list.count = len; first_list.last->next = 0; second_list.first = el; second_list.last = dl->last; second_list.count = dl_length(dl)-len; second_list.first->prev = 0; dl_sort(&first_list, el_size, compar); dl_sort(&second_list, el_size, compar); /* in-place merging */ first_head = first_list.first; second_head = second_list.first; first_item = (void*)(((dl_el*)first_head)+1); second_item = (void*)(((dl_el*)second_head)+1); if (compar(first_item, second_item) <= 0) { dl->first = el = first_head; first_head = first_head->next; } else { dl->first = el = second_head; second_head = second_head->next; } while (1) { first_item = (void*)(((dl_el*)first_head)+1); second_item = (void*)(((dl_el*)second_head)+1); if (compar(first_item, second_item) <= 0) { el->next = first_head; first_head->prev = el; el = first_head; first_head = first_head->next; if (!first_head) { el->next = second_head; second_head->prev = el; dl->last = second_list.last; break; } } else { el->next = second_head; second_head->prev = el; el = second_head; second_head = second_head->next; if (!second_head) { el->next = first_head; first_head->prev = el; dl->last = first_list.last; break; } } } } ================================================ FILE: src/flute/dl.h ================================================ #ifndef DL_H #define DL_H #include #include typedef struct dl_el_s { struct dl_el_s *prev, *next; } dl_el; typedef struct { dl_el *first, *last; unsigned int count; } dl_s, *dl_t; dl_t dl_alloc(void); void dl_delete(dl_t dl, dl_el *el); void dl_clear(dl_t dl); void dl_concat(dl_t list1, dl_t list2); void dl_sort(dl_t dl, size_t el_size, int(*compar)(void *, void *)); #define dl_length(dl) (dl)->count #define dl_empty(dl) ((dl)->count <= 0) #define dl_data(type, el) \ *(type*)(((dl_el*)(el))+1) #define dl_data_p(type, el) \ ((type*)(((dl_el*)(el))+1)) #define dl_forall(type, dl, data) \ { \ dl_el *_el, *_next; \ dl_t _curr_dl = (dl); \ for (_el=_curr_dl->first; _el; _el=_next) { \ _next = _el->next; \ (data) = dl_data(type, _el); #define dl_forall_p(type, dl, data_p) \ { \ dl_el *_el, *_next; \ dl_t _curr_dl = (dl); \ for (_el=_curr_dl->first; _el; _el=_next) { \ _next = _el->next; \ (data_p) = dl_data_p(type, _el); #define dl_current() _el #define dl_delete_current() dl_delete(_curr_dl, _el) #define dl_endfor \ } \ } #define dl_forall_reverse(type, dl, data) \ { \ dl_el *_el, *_next; \ dl_t _curr_dl = (dl); \ for (_el=_curr_dl->last; _el; _el=_next) { \ _next = _el->prev; \ (data) = dl_data(type, _el); #define dl_forall_reverse_p(type, dl, data_p) \ { \ dl_el *_el, *_next; \ dl_t _curr_dl = (dl); \ for (_el=_curr_dl->last; _el; _el=_next) { \ _next = _el->prev; \ (data_p) = dl_data_p(type, _el); #define dl_first(type, dl) \ dl_data(type, (dl)->first) #define dl_first_element(dl) (dl)->first #define dl_last(type, dl) \ dl_data(type, (dl)->last) #define dl_pop_first(type, dl, data) \ { \ (data) = dl_first(type, dl); \ dl_delete((dl), (dl)->first); \ } #define dl_pop_last(type, dl, data) \ { (data) = dl_last(type, dl); dl_delete((dl), (dl)->last); } #define dl_insert_before(type, dl, element, data) \ { \ if ((element) == (dl)->first) { \ dl_prepend(type, dl, data); \ } else { \ dl_el *_el = (dl_el*) malloc(sizeof(dl_el)+sizeof(type)); \ if (!_el) { \ printf("Out of memory!!\n"); \ } else { \ memcpy(_el+1, &(data), sizeof(type)); \ _el->prev = (element)->prev; _el->next = (element); \ (element)->prev->next = _el; (element)->prev = _el; \ (dl)->count++; \ } \ } \ } #define dl_insert_after(type, dl, element, data) \ { \ if ((element) == (dl)->last) { \ dl_append(type, dl, data); \ } else { \ dl_el *_el = (dl_el*) malloc(sizeof(dl_el)+sizeof(type)); \ if (!_el) { \ printf("Out of memory!!\n"); \ } else { \ memcpy(_el+1, &(data), sizeof(type)); \ _el->next = (element)->next; _el->prev = (element); \ (element)->next->prev = _el; (element)->next = _el; \ (dl)->count++; \ } \ } \ } #define dl_append(type, dl, data) \ { \ dl_el *_el = (dl_el*) malloc(sizeof(dl_el)+sizeof(type)); \ if (!_el) { \ printf("Out of memory!!\n"); \ } else { \ memcpy(_el+1, &(data), sizeof(type)); \ _el->next = 0; \ if ((dl)->count <= 0) { \ _el->prev = 0; \ (dl)->first = (dl)->last = _el; \ (dl)->count = 1; \ } else { \ _el->prev = (dl)->last; \ (dl)->last->next = _el; \ (dl)->last = _el; \ (dl)->count++; \ } \ } \ } #define dl_prepend(type, dl, data) \ { \ dl_el *_el = (dl_el*) malloc(sizeof(dl_el)+sizeof(type)); \ if (!_el) { \ printf("Out of memory!!\n"); \ } else { \ memcpy(_el+1, &(data), sizeof(type)); \ _el->prev = 0; \ if ((dl)->count <= 0) { \ _el->next = 0; \ (dl)->first = (dl)->last = _el; \ (dl)->count = 1; \ } else { \ _el->next = (dl)->first; \ (dl)->first->prev = _el; \ (dl)->first = _el; \ (dl)->count++; \ } \ } \ } #define dl_free(dl) \ { \ dl_clear(dl); free(dl); dl = 0; \ } #define dl_duplicate(dest, src, type) \ { \ dest = dl_alloc(); \ type _data_el; \ dl_forall(type, src, _data_el) { \ dl_append(type, dest, _data_el); \ } dl_endfor; \ } #endif ================================================ FILE: src/flute/err.c ================================================ #include #include /**************************************************************************/ /* print error message and continue */ void err_msg( char* msg ) { fprintf(stderr, "%s\n", msg); } /**************************************************************************/ /* print error message and exit */ void err_exit( char* msg ) { fprintf(stderr, "%s\n", msg); exit(1); } ================================================ FILE: src/flute/err.h ================================================ #ifndef _ERR_H_ #define _ERR_H_ void err_msg( char* msg ); void err_exit( char* msg ); #endif ================================================ FILE: src/flute/flute.c ================================================ #include #include #include #include #include "flute.h" #if D<=7 #define MGROUP 5040/4 // Max. # of groups, 7! = 5040 #define MPOWV 15 // Max. # of POWVs per group #elif D==8 #define MGROUP 40320/4 // Max. # of groups, 8! = 40320 #define MPOWV 33 // Max. # of POWVs per group #elif D==9 #define MGROUP 362880/4 // Max. # of groups, 9! = 362880 #define MPOWV 79 // Max. # of POWVs per group #endif int numgrp[10]={0,0,0,0,6,30,180,1260,10080,90720}; struct csoln { unsigned char parent; unsigned char seg[11]; // Add: 0..i, Sub: j..10; seg[i+1]=seg[j-1]=0 unsigned char rowcol[D-2]; // row = rowcol[]/16, col = rowcol[]%16, unsigned char neighbor[2*D-2]; }; struct csoln *LUT[D+1][MGROUP]; // storing 4 .. D int numsoln[D+1][MGROUP]; struct point { DTYPE x, y; int o; }; void readLUT(); DTYPE flute_wl(int d, DTYPE x[], DTYPE y[], int acc); DTYPE flutes_wl_LD(int d, DTYPE xs[], DTYPE ys[], int s[]); DTYPE flutes_wl_MD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); DTYPE flutes_wl_RDP(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); Tree flute(int d, DTYPE x[], DTYPE y[], int acc); Tree flutes_LD(int d, DTYPE xs[], DTYPE ys[], int s[]); Tree flutes_MD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); Tree flutes_RDP(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); Tree dmergetree(Tree t1, Tree t2); Tree hmergetree(Tree t1, Tree t2, int s[]); Tree vmergetree(Tree t1, Tree t2); void local_refinement(Tree *tp, int p); DTYPE wirelength(Tree t); void printtree(Tree t); void plottree(Tree t); void readLUT() { unsigned char charnum[256], line[32], *linep, c; FILE *fpwv, *fprt; struct csoln *p; int d, i, j, k, kk, ns, nn; init_param(); for (i=0; i<=255; i++) { if ('0'<=i && i<='9') charnum[i] = i - '0'; else if (i>='A') charnum[i] = i - 'A' + 10; else // if (i=='$' || i=='\n' || ... ) charnum[i] = 0; } fpwv=fopen(POWVFILE, "r"); if (fpwv == NULL) { printf("Error in opening %s\n", POWVFILE); exit(1); } #if ROUTING==1 fprt=fopen(POSTFILE, "r"); if (fprt == NULL) { printf("Error in opening %s\n", POSTFILE); exit(1); } #endif int status_code; // useles, just to stop compile warning for (d=4; d<=D; d++) { status_code = fscanf(fpwv, "d=%d\n", &d); #if ROUTING==1 status_code = fscanf(fprt, "d=%d\n", &d); #endif for (k=0; kparent = charnum[*(linep++)]; j = 0; while ((p->seg[j++] = charnum[*(linep++)]) != 0) ; j = 10; while ((p->seg[j--] = charnum[*(linep++)]) != 0) ; #if ROUTING==1 nn = 2*d-2; status_code = fread(line, 1, d-2, fprt); linep=line; for (j=d; jrowcol[j-d] = c; } status_code = fread(line, 1, nn/2+1, fprt); linep=line; // last char \n for (j=0; jneighbor[j++] = c/16; p->neighbor[j++] = c%16; } #endif p++; } } } } } DTYPE flute_wl(int d, DTYPE x[], DTYPE y[], int acc) { DTYPE xs[MAXD], ys[MAXD], minval, l, xu, xl, yu, yl; int s[MAXD]; int i, j, k, minidx; struct point pt[MAXD], *ptp[MAXD], *tmpp; if (d==2) l = ADIFF(x[0], x[1]) + ADIFF(y[0], y[1]); else if (d==3) { if (x[0] > x[1]) { xu = flute_max(x[0], x[2]); xl = flute_min(x[1], x[2]); } else { xu = flute_max(x[1], x[2]); xl = flute_min(x[0], x[2]); } if (y[0] > y[1]) { yu = flute_max(y[0], y[2]); yl = flute_min(y[1], y[2]); } else { yu = flute_max(y[1], y[2]); yl = flute_min(y[0], y[2]); } l = (xu-xl) + (yu-yl); } else { for (i=0; ix; minidx = i; for (j=i+1; j ptp[j]->x) { minval = ptp[j]->x; minidx = j; } } tmpp = ptp[i]; ptp[i] = ptp[minidx]; ptp[minidx] = tmpp; } #if REMOVE_DUPLICATE_PIN==1 ptp[d] = &pt[d]; ptp[d]->x = ptp[d]->y = -999999; j = 0; for (i=0; ix == ptp[i]->x; k++) if (ptp[k]->y == ptp[i]->y) // pins k and i are the same break; if (ptp[k]->x != ptp[i]->x) ptp[j++] = ptp[i]; } d = j; #endif for (i=0; ix; ptp[i]->o = i; } // sort y to find s[] for (i=0; iy; minidx = i; for (j=i+1; j ptp[j]->y) { minval = ptp[j]->y; minidx = j; } } ys[i] = ptp[minidx]->y; s[i] = ptp[minidx]->o; ptp[minidx] = ptp[i]; } ys[d-1] = ptp[d-1]->y; s[d-1] = ptp[d-1]->o; l = flutes_wl(d, xs, ys, s, acc); } return l; } // xs[] and ys[] are coords in x and y in sorted order // s[] is a list of nodes in increasing y direction // if nodes are indexed in the order of increasing x coord // i.e., s[i] = s_i as defined in paper // The points are (xs[s[i]], ys[i]) for i=0..d-1 // or (xs[i], ys[si[i]]) for i=0..d-1 DTYPE flutes_wl_RDP(int d, DTYPE xs[], DTYPE ys[], int s[], int acc) { int i, j, ss; for (i=0; i ss) s[j]--; i--; d--; } } return flutes_wl_ALLD(d, xs, ys, s, acc); } // For low-degree, i.e., 2 <= d <= D DTYPE flutes_wl_LD(int d, DTYPE xs[], DTYPE ys[], int s[]) { int k, pi, i, j; struct csoln *rlist; DTYPE dd[2*D-2]; // 0..D-2 for v, D-1..2*D-3 for h DTYPE minl, sum, l[MPOWV+1]; if (d <= 3) minl = xs[d-1]-xs[0]+ys[d-1]-ys[0]; else { k = 0; if (s[0] < s[2]) k++; if (s[1] < s[2]) k++; for (i=3; i<=d-1; i++) { // p0=0 always, skip i=1 for symmetry pi = s[i]; for (j=d-1; j>i; j--) if (s[j] < s[i]) pi--; k = pi + (i+1)*k; } if (k < numgrp[d]) // no horizontal flip for (i=1; i<=d-3; i++) { dd[i]=ys[i+1]-ys[i]; dd[d-1+i]=xs[i+1]-xs[i]; } else { k=2*numgrp[d]-1-k; for (i=1; i<=d-3; i++) { dd[i]=ys[i+1]-ys[i]; dd[d-1+i]=xs[d-1-i]-xs[d-2-i]; } } minl = l[0] = xs[d-1]-xs[0]+ys[d-1]-ys[0]; rlist = LUT[d][k]; for (i=0; rlist->seg[i]>0; i++) minl += dd[rlist->seg[i]]; l[1] = minl; j = 2; while (j <= numsoln[d][k]) { rlist++; sum = l[rlist->parent]; for (i=0; rlist->seg[i]>0; i++) sum += dd[rlist->seg[i]]; for (i=10; rlist->seg[i]>0; i--) sum -= dd[rlist->seg[i]]; minl = flute_min(minl, sum); l[j++] = sum; } } return minl; } // For medium-degree, i.e., D+1 <= d DTYPE flutes_wl_MD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc) { DTYPE x1[MAXD], x2[MAXD], y1[MAXD], y2[MAXD]; int si[MAXD], s1[MAXD], s2[MAXD]; float score[2*MAXD], penalty[MAXD], pnlty, dx, dy; DTYPE ll, minl, extral; int i, r, p, maxbp, nbp, bp, ub, lb, n1, n2, newacc; int ms, mins, maxs, minsi, maxsi; DTYPE distx[MAXD], disty[MAXD], xydiff; if (s[0] < s[d-1]) { ms = flute_max(s[0], s[1]); for (i=2; i<=ms; i++) ms = flute_max(ms, s[i]); if (ms <= d-3) { for (i=0; i<=ms; i++) { x1[i] = xs[i]; y1[i] = ys[i]; s1[i] = s[i]; } x1[ms+1] = xs[ms]; y1[ms+1] = ys[ms]; s1[ms+1] = ms+1; s2[0] = 0; for (i=1; i<=d-1-ms; i++) s2[i] = s[i+ms]-ms; return flutes_wl_LMD(ms+2, x1, y1, s1, acc) + flutes_wl_LMD(d-ms, xs+ms, ys+ms, s2, acc); } } else { // (s[0] > s[d-1]) ms = flute_min(s[0], s[1]); for (i=2; i<=d-1-ms; i++) ms = flute_min(ms, s[i]); if (ms >= 2) { x1[0] = xs[ms]; y1[0] = ys[0]; s1[0] = s[0]-ms+1; for (i=1; i<=d-1-ms; i++) { x1[i] = xs[i+ms-1]; y1[i] = ys[i]; s1[i] = s[i]-ms+1; } x1[d-ms] = xs[d-1]; y1[d-ms] = ys[d-1-ms]; s1[d-ms] = 0; s2[0] = ms; for (i=1; i<=ms; i++) s2[i] = s[i+d-1-ms]; return flutes_wl_LMD(d+1-ms, x1, y1, s1, acc) + flutes_wl_LMD(ms+1, xs, ys+d-1-ms, s2, acc); } } // Find inverse si[] of s[] for (r=0; r=0; r--, pnlty += dx) penalty[r] = pnlty, penalty[d-1-r] = pnlty; for (r = d/2-1, pnlty = dy; r>=0; r--, pnlty += dy) penalty[s[r]] += pnlty, penalty[s[d-1-r]] += pnlty; //#define CCWL 0.16 // for (r=0; r maxs) maxs = s[r]; distx[r] = xs[maxs] - xs[mins]; if (si[r] < minsi) minsi = si[r]; else if (si[r] > maxsi) maxsi = si[r]; disty[r] = ys[maxsi] - ys[minsi] + xydiff; } if (s[d-2] < s[d-1]) mins = s[d-2], maxs = s[d-1]; else mins = s[d-1], maxs = s[d-2]; if (si[d-2] < si[d-1]) minsi = si[d-2], maxsi = si[d-1]; else minsi = si[d-1], maxsi = si[d-2]; for (r=d-3; r>=lb; r--) { if (s[r] < mins) mins = s[r]; else if (s[r] > maxs) maxs = s[r]; distx[r] += xs[maxs] - xs[mins]; if (si[r] < minsi) minsi = si[r]; else if (si[r] > maxsi) maxsi = si[r]; disty[r] += ys[maxsi] - ys[minsi]; } nbp=0; for (r=lb; r<=ub; r++) { if (si[r]==0 || si[r]==d-1) score[nbp] = (xs[r+1] - xs[r-1]) - penalty[r] - AAWL*(ys[d-2]-ys[1]) - DDWL*disty[r]; else score[nbp] = (xs[r+1] - xs[r-1]) - penalty[r] - BBWL*(ys[si[r]+1]-ys[si[r]-1]) - DDWL*disty[r]; nbp++; if (s[r]==0 || s[r]==d-1) score[nbp] = (ys[r+1] - ys[r-1]) - penalty[s[r]] - AAWL*(xs[d-2]-xs[1]) - DDWL*distx[r]; else score[nbp] = (ys[r+1] - ys[r-1]) - penalty[s[r]] - BBWL*(xs[s[r]+1]-xs[s[r]-1]) - DDWL*distx[r]; nbp++; } if (acc <= 3) newacc = 1; else { newacc = acc/2; if (acc >= nbp) acc = nbp-1; } minl = (DTYPE) INT_MAX; for (i=0; i p) { s2[n2] = s[r]-p; y2[n2] = ys[r]; n2++; } else { // if (s[r] == p) i.e., r = si[p] s1[n1] = p; s2[n2] = 0; if (r == d-1 || r == d-2) { y1[n1] = y2[n2] = ys[r-1]; extral = ys[r] - ys[r-1]; } if (r == 0 || r == 1) { y1[n1] = y2[n2] = ys[r+1]; extral = ys[r+1] - ys[r]; } else { y1[n1] = y2[n2] = ys[r]; extral = 0; } n1++; n2++; } } ll = extral + flutes_wl_LMD(p+1, xs, y1, s1, newacc) + flutes_wl_LMD(d-p, xs+p, y2, s2, newacc); } else { // if (!BreakInX(maxbp)) n1 = n2 = 0; for (r=0; r p) { s2[si[r]-p] = n2; x2[n2] = xs[r]; n2++; } else { // if (si[r] == p) i.e., r = s[p] s1[p] = n1; s2[0] = n2; if (r == d-1 || r == d-2) { x1[n1] = x2[n2] = xs[r-1]; extral = xs[r] - xs[r-1]; } if (r == 0 || r == 1) { x1[n1] = x2[n2] = xs[r+1]; extral = xs[r+1] - xs[r]; } else { x1[n1] = x2[n2] = xs[r]; extral = 0; } n1++; n2++; } } ll = extral + flutes_wl_LMD(p+1, x1, ys, s1, newacc) + flutes_wl_LMD(d-p, x2, ys+p, s2, newacc); } if (minl > ll) minl = ll; } return minl; } static int orderx(const void *a, const void *b) { struct point *pa, *pb; pa = *(struct point**)a; pb = *(struct point**)b; if (pa->x < pb->x) return -1; if (pa->x > pb->x) return 1; return 0; } static int ordery(const void *a, const void *b) { struct point *pa, *pb; pa = *(struct point**)a; pb = *(struct point**)b; if (pa->y < pb->y) return -1; if (pa->y > pb->y) return 1; return 0; } Tree flute(int d, DTYPE x[], DTYPE y[], int acc) { DTYPE *xs, *ys, minval; int *s; int i, j, k, minidx; struct point *pt, **ptp, *tmpp; Tree t; if (d==2) { t.deg = 2; t.length = ADIFF(x[0], x[1]) + ADIFF(y[0], y[1]); t.branch = (Branch *) malloc(2*sizeof(Branch)); t.branch[0].x = x[0]; t.branch[0].y = y[0]; t.branch[0].n = 1; t.branch[1].x = x[1]; t.branch[1].y = y[1]; t.branch[1].n = 1; } else { xs = (DTYPE *)malloc(sizeof(DTYPE)*(d)); ys = (DTYPE *)malloc(sizeof(DTYPE)*(d)); s = (int *)malloc(sizeof(int)*(d)); pt = (struct point *)malloc(sizeof(struct point)*(d+1)); ptp = (struct point **)malloc(sizeof(struct point*)*(d+1)); for (i=0; ix; minidx = i; for (j=i+1; j ptp[j]->x) { minval = ptp[j]->x; minidx = j; } } tmpp = ptp[i]; ptp[i] = ptp[minidx]; ptp[minidx] = tmpp; } } else { qsort(ptp, d, sizeof(struct point *), orderx); } #if REMOVE_DUPLICATE_PIN==1 ptp[d] = &pt[d]; ptp[d]->x = ptp[d]->y = -999999; j = 0; for (i=0; ix == ptp[i]->x; k++) if (ptp[k]->y == ptp[i]->y) // pins k and i are the same break; if (ptp[k]->x != ptp[i]->x) ptp[j++] = ptp[i]; } d = j; #endif for (i=0; ix; ptp[i]->o = i; } // sort y to find s[] if (d<200) { for (i=0; iy; minidx = i; for (j=i+1; j ptp[j]->y) { minval = ptp[j]->y; minidx = j; } } ys[i] = ptp[minidx]->y; s[i] = ptp[minidx]->o; ptp[minidx] = ptp[i]; } ys[d-1] = ptp[d-1]->y; s[d-1] = ptp[d-1]->o; } else { qsort(ptp, d, sizeof(struct point *), ordery); for (i=0; iy; s[i] = ptp[i]->o; } } t = flutes(d, xs, ys, s, acc); free(xs); free(ys); free(s); free(pt); free(ptp); } return t; } // xs[] and ys[] are coords in x and y in sorted order // s[] is a list of nodes in increasing y direction // if nodes are indexed in the order of increasing x coord // i.e., s[i] = s_i as defined in paper // The points are (xs[s[i]], ys[i]) for i=0..d-1 // or (xs[i], ys[si[i]]) for i=0..d-1 Tree flutes_RDP(int d, DTYPE xs[], DTYPE ys[], int s[], int acc) { int i, j, ss; for (i=0; i ss) s[j]--; i--; d--; } } return flutes_ALLD(d, xs, ys, s, acc); } // For low-degree, i.e., 2 <= d <= D Tree flutes_LD(int d, DTYPE xs[], DTYPE ys[], int s[]) { int k, pi, i, j; struct csoln *rlist, *bestrlist; DTYPE dd[2*D-2]; // 0..D-2 for v, D-1..2*D-3 for h DTYPE minl, sum, l[MPOWV+1]; int hflip; Tree t; t.deg = d; t.branch = (Branch *) malloc((2*d-2)*sizeof(Branch)); if (d == 2) { minl = xs[1]-xs[0]+ys[1]-ys[0]; t.branch[0].x = xs[s[0]]; t.branch[0].y = ys[0]; t.branch[0].n = 1; t.branch[1].x = xs[s[1]]; t.branch[1].y = ys[1]; t.branch[1].n = 1; } else if (d == 3) { minl = xs[2]-xs[0]+ys[2]-ys[0]; t.branch[0].x = xs[s[0]]; t.branch[0].y = ys[0]; t.branch[0].n = 3; t.branch[1].x = xs[s[1]]; t.branch[1].y = ys[1]; t.branch[1].n = 3; t.branch[2].x = xs[s[2]]; t.branch[2].y = ys[2]; t.branch[2].n = 3; t.branch[3].x = xs[1]; t.branch[3].y = ys[1]; t.branch[3].n = 3; } else { k = 0; if (s[0] < s[2]) k++; if (s[1] < s[2]) k++; for (i=3; i<=d-1; i++) { // p0=0 always, skip i=1 for symmetry pi = s[i]; for (j=d-1; j>i; j--) if (s[j] < s[i]) pi--; k = pi + (i+1)*k; } if (k < numgrp[d]) { // no horizontal flip hflip = 0; for (i=1; i<=d-3; i++) { dd[i]=ys[i+1]-ys[i]; dd[d-1+i]=xs[i+1]-xs[i]; } } else { hflip = 1; k=2*numgrp[d]-1-k; for (i=1; i<=d-3; i++) { dd[i]=ys[i+1]-ys[i]; dd[d-1+i]=xs[d-1-i]-xs[d-2-i]; } } minl = l[0] = xs[d-1]-xs[0]+ys[d-1]-ys[0]; rlist = LUT[d][k]; for (i=0; rlist->seg[i]>0; i++) minl += dd[rlist->seg[i]]; bestrlist = rlist; l[1] = minl; j = 2; while (j <= numsoln[d][k]) { rlist++; sum = l[rlist->parent]; for (i=0; rlist->seg[i]>0; i++) sum += dd[rlist->seg[i]]; for (i=10; rlist->seg[i]>0; i--) sum -= dd[rlist->seg[i]]; if (sum < minl) { minl = sum; bestrlist = rlist; } l[j++] = sum; } t.branch[0].x = xs[s[0]]; t.branch[0].y = ys[0]; t.branch[1].x = xs[s[1]]; t.branch[1].y = ys[1]; for (i=2; ineighbor[i]; } t.branch[d-2].x = xs[s[d-2]]; t.branch[d-2].y = ys[d-2]; t.branch[d-1].x = xs[s[d-1]]; t.branch[d-1].y = ys[d-1]; if (hflip) { if (s[1] < s[0]) { t.branch[0].n = bestrlist->neighbor[1]; t.branch[1].n = bestrlist->neighbor[0]; } else { t.branch[0].n = bestrlist->neighbor[0]; t.branch[1].n = bestrlist->neighbor[1]; } if (s[d-1] < s[d-2]) { t.branch[d-2].n = bestrlist->neighbor[d-1]; t.branch[d-1].n = bestrlist->neighbor[d-2]; } else { t.branch[d-2].n = bestrlist->neighbor[d-2]; t.branch[d-1].n = bestrlist->neighbor[d-1]; } for (i=d; i<2*d-2; i++) { t.branch[i].x = xs[d-1-bestrlist->rowcol[i-d]%16]; t.branch[i].y = ys[bestrlist->rowcol[i-d]/16]; t.branch[i].n = bestrlist->neighbor[i]; } } else { // !hflip if (s[0] < s[1]) { t.branch[0].n = bestrlist->neighbor[1]; t.branch[1].n = bestrlist->neighbor[0]; } else { t.branch[0].n = bestrlist->neighbor[0]; t.branch[1].n = bestrlist->neighbor[1]; } if (s[d-2] < s[d-1]) { t.branch[d-2].n = bestrlist->neighbor[d-1]; t.branch[d-1].n = bestrlist->neighbor[d-2]; } else { t.branch[d-2].n = bestrlist->neighbor[d-2]; t.branch[d-1].n = bestrlist->neighbor[d-1]; } for (i=d; i<2*d-2; i++) { t.branch[i].x = xs[bestrlist->rowcol[i-d]%16]; t.branch[i].y = ys[bestrlist->rowcol[i-d]/16]; t.branch[i].n = bestrlist->neighbor[i]; } } } t.length = minl; return t; } // For medium-degree, i.e., D+1 <= d Tree flutes_MD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc) { DTYPE x1[MAXD], x2[MAXD], y1[MAXD], y2[MAXD]; int si[MAXD], s1[MAXD], s2[MAXD]; float score[2*MAXD], penalty[MAXD], pnlty, dx, dy; DTYPE ll, minl, coord1, coord2; int i, r, p, maxbp, bestbp, bp, nbp, ub, lb, n1, n2, nn1, nn2, newacc; Tree t, t1, t2, bestt1, bestt2; int ms, mins, maxs, minsi, maxsi; DTYPE distx[MAXD], disty[MAXD], xydiff; if (s[0] < s[d-1]) { ms = flute_max(s[0], s[1]); for (i=2; i<=ms; i++) ms = flute_max(ms, s[i]); if (ms <= d-3) { for (i=0; i<=ms; i++) { x1[i] = xs[i]; y1[i] = ys[i]; s1[i] = s[i]; } x1[ms+1] = xs[ms]; y1[ms+1] = ys[ms]; s1[ms+1] = ms+1; s2[0] = 0; for (i=1; i<=d-1-ms; i++) s2[i] = s[i+ms]-ms; t1 = flutes_LMD(ms+2, x1, y1, s1, acc); t2 = flutes_LMD(d-ms, xs+ms, ys+ms, s2, acc); t = dmergetree(t1, t2); free(t1.branch); free(t2.branch); return t; } } else { // (s[0] > s[d-1]) ms = flute_min(s[0], s[1]); for (i=2; i<=d-1-ms; i++) ms = flute_min(ms, s[i]); if (ms >= 2) { x1[0] = xs[ms]; y1[0] = ys[0]; s1[0] = s[0]-ms+1; for (i=1; i<=d-1-ms; i++) { x1[i] = xs[i+ms-1]; y1[i] = ys[i]; s1[i] = s[i]-ms+1; } x1[d-ms] = xs[d-1]; y1[d-ms] = ys[d-1-ms]; s1[d-ms] = 0; s2[0] = ms; for (i=1; i<=ms; i++) s2[i] = s[i+d-1-ms]; t1 = flutes_LMD(d+1-ms, x1, y1, s1, acc); t2 = flutes_LMD(ms+1, xs, ys+d-1-ms, s2, acc); t = dmergetree(t1, t2); free(t1.branch); free(t2.branch); return t; } } // Find inverse si[] of s[] for (r=0; r=2; r--, pnlty += dx) penalty[r] = pnlty, penalty[d-1-r] = pnlty; penalty[1] = pnlty, penalty[d-2] = pnlty; penalty[0] = pnlty, penalty[d-1] = pnlty; for (r = d/2-1, pnlty = dy; r>=2; r--, pnlty += dy) penalty[s[r]] += pnlty, penalty[s[d-1-r]] += pnlty; penalty[s[1]] += pnlty, penalty[s[d-2]] += pnlty; penalty[s[0]] += pnlty, penalty[s[d-1]] += pnlty; //#define CC 0.16 //#define v(r) ((r==0||r==1||r==d-2||r==d-1) ? d-3 : flute_abs(d-1-r-r)) // for (r=0; r maxs) maxs = s[r]; distx[r] = xs[maxs] - xs[mins]; if (si[r] < minsi) minsi = si[r]; else if (si[r] > maxsi) maxsi = si[r]; disty[r] = ys[maxsi] - ys[minsi] + xydiff; } if (s[d-2] < s[d-1]) mins = s[d-2], maxs = s[d-1]; else mins = s[d-1], maxs = s[d-2]; if (si[d-2] < si[d-1]) minsi = si[d-2], maxsi = si[d-1]; else minsi = si[d-1], maxsi = si[d-2]; for (r=d-3; r>=lb; r--) { if (s[r] < mins) mins = s[r]; else if (s[r] > maxs) maxs = s[r]; distx[r] += xs[maxs] - xs[mins]; if (si[r] < minsi) minsi = si[r]; else if (si[r] > maxsi) maxsi = si[r]; disty[r] += ys[maxsi] - ys[minsi]; } nbp=0; for (r=lb; r<=ub; r++) { if (si[r]<=1) score[nbp] = (xs[r+1] - xs[r-1]) - penalty[r] - AA*(ys[2]-ys[1]) - DD*disty[r]; else if (si[r]>=d-2) score[nbp] = (xs[r+1] - xs[r-1]) - penalty[r] - AA*(ys[d-2]-ys[d-3]) - DD*disty[r]; else score[nbp] = (xs[r+1] - xs[r-1]) - penalty[r] - BB*(ys[si[r]+1]-ys[si[r]-1]) - DD*disty[r]; nbp++; if (s[r]<=1) score[nbp] = (ys[r+1] - ys[r-1]) - penalty[s[r]] - AA*(xs[2]-xs[1]) - DD*distx[r]; else if (s[r]>=d-2) score[nbp] = (ys[r+1] - ys[r-1]) - penalty[s[r]] - AA*(xs[d-2]-xs[d-3]) - DD*distx[r]; else score[nbp] = (ys[r+1] - ys[r-1]) - penalty[s[r]] - BB*(xs[s[r]+1]-xs[s[r]-1]) - DD*distx[r]; nbp++; } if (acc <= 3) newacc = 1; else { newacc = acc/2; if (acc >= nbp) acc = nbp-1; } minl = (DTYPE) INT_MAX; bestt1.branch = bestt2.branch = NULL; for (i=0; i p) { s2[n2] = s[r]-p; y2[n2] = ys[r]; n2++; } else { // if (s[r] == p) i.e., r = si[p] s1[n1] = p; s2[n2] = 0; y1[n1] = y2[n2] = ys[r]; nn1 = n1; nn2 = n2; n1++; n2++; } } t1 = flutes_LMD(p+1, xs, y1, s1, newacc); t2 = flutes_LMD(d-p, xs+p, y2, s2, newacc); ll = t1.length + t2.length; coord1 = t1.branch[t1.branch[nn1].n].y; coord2 = t2.branch[t2.branch[nn2].n].y; if (t2.branch[nn2].y > flute_max(coord1, coord2)) ll -= t2.branch[nn2].y - flute_max(coord1, coord2); else if (t2.branch[nn2].y < flute_min(coord1, coord2)) ll -= flute_min(coord1, coord2) - t2.branch[nn2].y; } else { // if (!BreakInX(maxbp)) n1 = n2 = 0; for (r=0; r p) { s2[si[r]-p] = n2; x2[n2] = xs[r]; n2++; } else { // if (si[r] == p) i.e., r = s[p] s1[p] = n1; s2[0] = n2; x1[n1] = x2[n2] = xs[r]; n1++; n2++; } } t1 = flutes_LMD(p+1, x1, ys, s1, newacc); t2 = flutes_LMD(d-p, x2, ys+p, s2, newacc); ll = t1.length + t2.length; coord1 = t1.branch[t1.branch[p].n].x; coord2 = t2.branch[t2.branch[0].n].x; if (t2.branch[0].x > flute_max(coord1, coord2)) ll -= t2.branch[0].x - flute_max(coord1, coord2); else if (t2.branch[0].x < flute_min(coord1, coord2)) ll -= flute_min(coord1, coord2) - t2.branch[0].x; } if (minl > ll) { minl = ll; free(bestt1.branch); free(bestt2.branch); bestt1 = t1; bestt2 = t2; bestbp = maxbp; } else { free(t1.branch); free(t2.branch); } } #if LOCAL_REFINEMENT==1 if (BreakInX(bestbp)) { t = hmergetree(bestt1, bestt2, s); local_refinement(&t, si[BreakPt(bestbp)]); } else { t = vmergetree(bestt1, bestt2); local_refinement(&t, BreakPt(bestbp)); } #else if (BreakInX(bestbp)) { t = hmergetree(bestt1, bestt2, s); } else { t = vmergetree(bestt1, bestt2); } #endif free(bestt1.branch); free(bestt2.branch); return t; } Tree dmergetree(Tree t1, Tree t2) { int i, d, prev, curr, next, offset1, offset2; Tree t; t.deg = d = t1.deg + t2.deg - 2; t.length = t1.length + t2.length; t.branch = (Branch *) malloc((2*d-2)*sizeof(Branch)); offset1 = t2.deg-2; offset2 = 2*t1.deg-4; for (i=0; i<=t1.deg-2; i++) { t.branch[i].x = t1.branch[i].x; t.branch[i].y = t1.branch[i].y; t.branch[i].n = t1.branch[i].n + offset1; } for (i=t1.deg-1; i<=d-1; i++) { t.branch[i].x = t2.branch[i-t1.deg+2].x; t.branch[i].y = t2.branch[i-t1.deg+2].y; t.branch[i].n = t2.branch[i-t1.deg+2].n + offset2; } for (i=d; i<=d+t1.deg-3; i++) { t.branch[i].x = t1.branch[i-offset1].x; t.branch[i].y = t1.branch[i-offset1].y; t.branch[i].n = t1.branch[i-offset1].n + offset1; } for (i=d+t1.deg-2; i<=2*d-3; i++) { t.branch[i].x = t2.branch[i-offset2].x; t.branch[i].y = t2.branch[i-offset2].y; t.branch[i].n = t2.branch[i-offset2].n + offset2; } prev = t2.branch[0].n + offset2; curr = t1.branch[t1.deg-1].n + offset1; next = t.branch[curr].n; while (curr != next) { t.branch[curr].n = prev; prev = curr; curr = next; next = t.branch[curr].n; } t.branch[curr].n = prev; return t; } Tree hmergetree(Tree t1, Tree t2, int s[]) { int i, prev, curr, next, extra, offset1, offset2; int p, ii, n1, n2, nn1, nn2; DTYPE coord1, coord2; Tree t; t.deg = t1.deg + t2.deg - 1; t.length = t1.length + t2.length; t.branch = (Branch *) malloc((2*t.deg-2)*sizeof(Branch)); offset1 = t2.deg-1; offset2 = 2*t1.deg-3; p = t1.deg - 1; n1 = n2 = 0; for (i=0; i p) { t.branch[i].x = t2.branch[n2].x; t.branch[i].y = t2.branch[n2].y; t.branch[i].n = t2.branch[n2].n + offset2; n2++; } else { t.branch[i].x = t2.branch[n2].x; t.branch[i].y = t2.branch[n2].y; t.branch[i].n = t2.branch[n2].n + offset2; nn1 = n1; nn2 = n2; ii = i; n1++; n2++; } } for (i=t.deg; i<=t.deg+t1.deg-3; i++) { t.branch[i].x = t1.branch[i-offset1].x; t.branch[i].y = t1.branch[i-offset1].y; t.branch[i].n = t1.branch[i-offset1].n + offset1; } for (i=t.deg+t1.deg-2; i<=2*t.deg-4; i++) { t.branch[i].x = t2.branch[i-offset2].x; t.branch[i].y = t2.branch[i-offset2].y; t.branch[i].n = t2.branch[i-offset2].n + offset2; } extra = 2*t.deg-3; coord1 = t1.branch[t1.branch[nn1].n].y; coord2 = t2.branch[t2.branch[nn2].n].y; if (t2.branch[nn2].y > flute_max(coord1, coord2)) { t.branch[extra].y = flute_max(coord1, coord2); t.length -= t2.branch[nn2].y - t.branch[extra].y; } else if (t2.branch[nn2].y < flute_min(coord1, coord2)) { t.branch[extra].y = flute_min(coord1, coord2); t.length -= t.branch[extra].y - t2.branch[nn2].y; } else t.branch[extra].y = t2.branch[nn2].y; t.branch[extra].x = t2.branch[nn2].x; t.branch[extra].n = t.branch[ii].n; t.branch[ii].n = extra; prev = extra; curr = t1.branch[nn1].n + offset1; next = t.branch[curr].n; while (curr != next) { t.branch[curr].n = prev; prev = curr; curr = next; next = t.branch[curr].n; } t.branch[curr].n = prev; return t; } Tree vmergetree(Tree t1, Tree t2) { int i, prev, curr, next, extra, offset1, offset2; DTYPE coord1, coord2; Tree t; t.deg = t1.deg + t2.deg - 1; t.length = t1.length + t2.length; t.branch = (Branch *) malloc((2*t.deg-2)*sizeof(Branch)); offset1 = t2.deg-1; offset2 = 2*t1.deg-3; for (i=0; i<=t1.deg-2; i++) { t.branch[i].x = t1.branch[i].x; t.branch[i].y = t1.branch[i].y; t.branch[i].n = t1.branch[i].n + offset1; } for (i=t1.deg-1; i<=t.deg-1; i++) { t.branch[i].x = t2.branch[i-t1.deg+1].x; t.branch[i].y = t2.branch[i-t1.deg+1].y; t.branch[i].n = t2.branch[i-t1.deg+1].n + offset2; } for (i=t.deg; i<=t.deg+t1.deg-3; i++) { t.branch[i].x = t1.branch[i-offset1].x; t.branch[i].y = t1.branch[i-offset1].y; t.branch[i].n = t1.branch[i-offset1].n + offset1; } for (i=t.deg+t1.deg-2; i<=2*t.deg-4; i++) { t.branch[i].x = t2.branch[i-offset2].x; t.branch[i].y = t2.branch[i-offset2].y; t.branch[i].n = t2.branch[i-offset2].n + offset2; } extra = 2*t.deg-3; coord1 = t1.branch[t1.branch[t1.deg-1].n].x; coord2 = t2.branch[t2.branch[0].n].x; if (t2.branch[0].x > flute_max(coord1, coord2)) { t.branch[extra].x = flute_max(coord1, coord2); t.length -= t2.branch[0].x - t.branch[extra].x; } else if (t2.branch[0].x < flute_min(coord1, coord2)) { t.branch[extra].x = flute_min(coord1, coord2); t.length -= t.branch[extra].x - t2.branch[0].x; } else t.branch[extra].x = t2.branch[0].x; t.branch[extra].y = t2.branch[0].y; t.branch[extra].n = t.branch[t1.deg-1].n; t.branch[t1.deg-1].n = extra; prev = extra; curr = t1.branch[t1.deg-1].n + offset1; next = t.branch[curr].n; while (curr != next) { t.branch[curr].n = prev; prev = curr; curr = next; next = t.branch[curr].n; } t.branch[curr].n = prev; return t; } void local_refinement(Tree *tp, int p) { int d, dd, i, ii, j, prev, curr, next, root; int SteinerPin[2*MAXD], index[2*MAXD]; DTYPE x[MAXD], xs[D], ys[D]; int ss[D]; Tree tt; d = tp->deg; root = tp->branch[p].n; // Reverse edges to point to root prev = root; curr = tp->branch[prev].n; next = tp->branch[curr].n; while (curr != next) { tp->branch[curr].n = prev; prev = curr; curr = next; next = tp->branch[curr].n; } tp->branch[curr].n = prev; tp->branch[root].n = root; // Find Steiner nodes that are at pins for (i=d; i<=2*d-3; i++) SteinerPin[i] = -1; for (i=0; ibranch[i].n; if (tp->branch[i].x == tp->branch[next].x && tp->branch[i].y == tp->branch[next].y) SteinerPin[next] = i; // Steiner 'next' at Pin 'i' } SteinerPin[root] = p; // Find pins that are directly connected to root dd = 0; for (i=0; ibranch[i].n; if (SteinerPin[curr] == i) curr = tp->branch[curr].n; while (SteinerPin[curr] < 0) curr = tp->branch[curr].n; if (curr == root) { x[dd] = tp->branch[i].x; if (SteinerPin[tp->branch[i].n] == i && tp->branch[i].n != root) index[dd++] = tp->branch[i].n; // Steiner node else index[dd++] = i; // Pin } } if (4 <= dd && dd <= D) { // Find Steiner nodes that are directly connected to root ii=dd; for (i=0; ibranch[index[i]].n; while (SteinerPin[curr] < 0) { index[ii++] = curr; SteinerPin[curr] = INT_MAX; curr = tp->branch[curr].n; } } index[ii] = root; for (ii=0; iibranch[index[ii]].y; } tt = flutes_LD(dd, xs, ys, ss); // Find new wirelength tp->length += tt.length; for (ii=0; ii<2*dd-3; ii++) { i = index[ii]; j = tp->branch[i].n; tp->length -= ADIFF(tp->branch[i].x, tp->branch[j].x) + ADIFF(tp->branch[i].y, tp->branch[j].y); } // Copy tt into t for (ii=0; iibranch[index[ii]].n = index[tt.branch[ii].n]; } for (; ii<=2*dd-3; ii++) { tp->branch[index[ii]].x = tt.branch[ii].x; tp->branch[index[ii]].y = tt.branch[ii].y; tp->branch[index[ii]].n = index[tt.branch[ii].n]; } free(tt.branch); } return; } DTYPE wirelength(Tree t) { int i, j; DTYPE l=0; for (i=0; i<2*t.deg-2; i++) { j = t.branch[i].n; l += ADIFF(t.branch[i].x, t.branch[j].x) + ADIFF(t.branch[i].y, t.branch[j].y); } return l; } void printtree(Tree t) { int i; for (i=0; i= 5 #define REMOVE_DUPLICATE_PIN 0 // Remove dup. pin for flute_wl() & flute() #ifndef DTYPE // Data type for distance #define DTYPE int #endif /*****************************/ /* User-Callable Functions */ /*****************************/ // void readLUT(); // DTYPE flute_wl(int d, DTYPE x[], DTYPE y[], int acc); // DTYPE flutes_wl(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); // Tree flute(int d, DTYPE x[], DTYPE y[], int acc); // Tree flutes(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); // DTYPE wirelength(Tree t); // void printtree(Tree t); // void plottree(Tree t); /*************************************/ /* Internal Parameters and Functions */ /*************************************/ #define POWVFILE "POWV9.dat" // LUT for POWV (Wirelength Vector) #define POSTFILE "POST9.dat" // LUT for POST (Steiner Tree) #define D 9 // LUT is used for d <= D, D <= 9 #define TAU(A) (8+1.3*(A)) #define D1(A) (25+120/((A)*(A))) // flute_mr is used for D1 < d <= D2 #define D2(A) ((A)<=6 ? 500 : 75+5*(A)) typedef struct { DTYPE x, y; // starting point of the branch int n; // index of neighbor } Branch; typedef struct { int deg; // degree DTYPE length; // total wirelength Branch *branch; // array of tree branches } Tree; // User-Callable Functions // extern void readLUT(); extern DTYPE flute_wl(int d, DTYPE x[], DTYPE y[], int acc); //Macro: DTYPE flutes_wl(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); // extern Tree flute(int d, DTYPE x[], DTYPE y[], int acc); //Macro: Tree flutes(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); extern DTYPE wirelength(Tree t); extern void printtree(Tree t); extern void plottree(Tree t); // Other useful functions extern void init_param(); extern DTYPE flutes_wl_LD(int d, DTYPE xs[], DTYPE ys[], int s[]); extern DTYPE flutes_wl_MD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); extern DTYPE flutes_wl_RDP(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); extern Tree flutes_LD(int d, DTYPE xs[], DTYPE ys[], int s[]); extern Tree flutes_MD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); extern Tree flutes_HD(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); extern Tree flutes_RDP(int d, DTYPE xs[], DTYPE ys[], int s[], int acc); #if REMOVE_DUPLICATE_PIN==1 #define flutes_wl(d, xs, ys, s, acc) flutes_wl_RDP(d, xs, ys, s, acc) #define flutes(d, xs, ys, s, acc) flutes_RDP(d, xs, ys, s, acc) #else #define flutes_wl(d, xs, ys, s, acc) flutes_wl_ALLD(d, xs, ys, s, acc) #define flutes(d, xs, ys, s, acc) flutes_ALLD(d, xs, ys, s, acc) #endif #define flutes_wl_ALLD(d, xs, ys, s, acc) flutes_wl_LMD(d, xs, ys, s, acc) #define flutes_ALLD(d, xs, ys, s, acc) \ (d<=D ? flutes_LD(d, xs, ys, s) \ : (d<=D1(acc) ? flutes_MD(d, xs, ys, s, acc) \ : flutes_HD(d, xs, ys, s, acc))) #define flutes_wl_LMD(d, xs, ys, s, acc) \ (d<=D ? flutes_wl_LD(d, xs, ys, s) : flutes_wl_MD(d, xs, ys, s, acc)) #define flutes_LMD(d, xs, ys, s, acc) \ (d<=D ? flutes_LD(d, xs, ys, s) : flutes_MD(d, xs, ys, s, acc)) #define flute_max(x,y) ((x)>(y)?(x):(y)) #define flute_min(x,y) ((x)<(y)?(x):(y)) #define flute_abs(x) ((x)<0?(-x):(x)) #define ADIFF(x,y) ((x)>(y)?(x-y):(y-x)) // Absolute difference ================================================ FILE: src/flute/flute_mst.c ================================================ #include #include #include #include #include #include #include "dl.h" #include "flute.h" #include "mst2.h" #define INFNTY INT_MAX #define D2M D2(1) // Max net degree that flute_mr will handle #define MR_FOR_SMALL_CASES_ONLY 1 #if MR_FOR_SMALL_CASES_ONLY #define MAXPART D2M // max partition of an MST #define MAXT (D2M/D*2) #else #define MAXPART (d/9*2) //(MAXD/THD*2) // max partition of an MST #define MAXPART2 ((t1.deg+t2.deg)/9*2) #define MAXT (d/5) #endif int D3=INFNTY; int FIRST_ROUND=2; // note that num of total rounds = 1+FIRST_ROUND int EARLY_QUIT_CRITERIA=1; #define DEFAULT_QSIZE (3+flute_min(d,1000)) #define USE_HASHING 1 #if USE_HASHING #define new_ht 1 //int new_ht=1; dl_t ht[D2M+1]; // hash table of subtrees indexed by degree #endif unsigned int curr_mark=0; Tree wmergetree(Tree t1, Tree t2, int *order1, int *order2, DTYPE cx, DTYPE cy, int acc); Tree xmergetree(Tree t1, Tree t2, int *order1, int *order2, DTYPE cx, DTYPE cy); void color_tree(Tree t, int *color); int longest_path_edge(int i, int j, int *e, int *p, int *es); void preprocess_edges(int num_edges, int *edges, DTYPE *len, int *e, int *p, int *es); #define init_queue(q) { q[1] = 2; } void enqueue(int **q, int e) { int _qsize; if ((*q)[0]==(*q)[1]) { _qsize=2*((*q)[0]+1); (*q)=(int*)realloc((*q), _qsize*sizeof(int)); (*q)[0]=_qsize; } (*q)[(*q)[1]++]=e; } #define MAX_HEAP_SIZE (MAXD*2) DTYPE **hdist; typedef struct node_pair_s { // pair of nodes representing an edge int node1, node2; } node_pair; node_pair *heap; //heap[MAXD*MAXD]; int heap_size=0; int max_heap_size = MAX_HEAP_SIZE; int in_heap_order(int e1, int e2) { if (hdist[heap[e1].node1][heap[e1].node2] < hdist[heap[e2].node1][heap[e2].node2]) { return 1; } else { return 0; } } void sift_up(int i) { node_pair tmp; int j; for (j=i/2; j>=1 && in_heap_order(i, j); i=j, j/=2) { tmp = heap[j]; heap[j] = heap[i]; heap[i] = tmp; } } void sift_down(int i) { int left, right, j; node_pair tmp; left = i*2; right = left+1; while (left <= heap_size) { if (left == heap_size || in_heap_order(left, right)) { j = left; } else { j = right; } if (in_heap_order(j, i)) { tmp = heap[j]; heap[j] = heap[i]; heap[i] = tmp; i = j; left = i*2; right = left+1; } else { break; } } } void insert_heap(node_pair *np) { if (heap_size >= max_heap_size) { max_heap_size *= 2; heap = (node_pair*)realloc(heap, sizeof(node_pair)*(max_heap_size+1)); } heap[++heap_size] = *np; sift_up(heap_size); } void extract_heap(node_pair *np) { // caller has to make sure heap is not empty *np = heap[1]; heap[1] = heap[heap_size--]; sift_down(1); } void init_param() { int i; heap = (node_pair*)malloc(sizeof(node_pair)*(max_heap_size+1)); } Tree reftree; // reference for qsort int cmp_branch(const void *a, const void *b) { int n; DTYPE x1, x2, x3; x1 = reftree.branch[*(int*)a].x; n = reftree.branch[*(int*)a].n; x3 = reftree.branch[n].x; if (x3 < x1) x1=x3; x2 = reftree.branch[*(int*)b].x; n = reftree.branch[*(int*)b].n; x3 = reftree.branch[n].x; if (x3 < x2) x2=x3; return (x1 <= x2) ? -1 : 1; } void update_dist2(Tree t, DTYPE **dist, DTYPE longest, int *host, int *min_node1, int *min_node2, int **nb) { int i, j, m, n, dd, node1, node2, node3, node4, p1, p2, pi, pn; DTYPE min_dist, smallest; DTYPE x1, x2, x3, x4, y1, y2, y3, y4; DTYPE threshold_x, threshold_y; DTYPE md = dist[*min_node1][*min_node2]; #if MR_FOR_SMALL_CASES_ONLY int isPin_base[D2M], *isPin, id[2*D2M]; int u, v, b[D2M*2]; #else int *isPin_base, *isPin, *id; int u, v, *b; isPin_base = (int*)malloc(sizeof(int)*t.deg); id = (int*)malloc(sizeof(int)*t.deg*2); b = (int*)malloc(sizeof(int)*t.deg*2); #endif isPin = &(isPin_base[0]) - t.deg; dd = t.deg*2-2; for (i=0; i=0 || n==i) { continue; } if (id[i] < id[n]) { id[n] = id[i]; } else { id[i] = id[n]; } } for (i=0; ithreshold_x || ADIFF(t.branch[i].y, t.branch[j].y)>threshold_y) continue; m = t.branch[j].n; node3 = host[j]; node4 = host[m]; if (node3 < 0 && node4 < 0) { continue; } if (t.branch[j].x <= t.branch[m].x) { x1 = t.branch[j].x; x2 = t.branch[m].x; } else { x1 = t.branch[m].x; x2 = t.branch[j].x; } if (t.branch[j].y <= t.branch[m].y) { y1 = t.branch[j].y; y2 = t.branch[m].y; } else { y1 = t.branch[m].y; y2 = t.branch[j].y; } if (x2 < x3) { min_dist = x3 - x2; } else if (x4 < x1) { min_dist = x1 - x4; } else { min_dist = 0; } if (min_dist >= threshold_x) { break; } if (y2 < y3) { min_dist += y3 - y2; } else if (y4 < y1) { min_dist += y1 - y4; } if (min_dist >= longest) { continue; } p1 = (node1 < 0) ? node2 : ((node2 < 0) ? node1 : -1); p2 = (node3 < 0) ? node4 : ((node4 < 0) ? node3 : -1); if (p1 >= 0 && p2 < 0) { dist[p1][node3] = ADIFF(t.branch[p1].x, t.branch[node3].x) + ADIFF(t.branch[p1].y, t.branch[node3].y); dist[p1][node4] = ADIFF(t.branch[p1].x, t.branch[node4].x) + ADIFF(t.branch[p1].y, t.branch[node4].y); p2 = (dist[p1][node3] <= dist[p1][node4]) ? node3 : node4; } else if (p1 < 0 && p2 >= 0) { dist[node1][p2] = ADIFF(t.branch[node1].x, t.branch[p2].x) + ADIFF(t.branch[node1].y, t.branch[p2].y); dist[node2][p2] = ADIFF(t.branch[node2].x, t.branch[p2].x) + ADIFF(t.branch[node2].y, t.branch[p2].y); p1 = (dist[node1][p2] <= dist[node2][p2]) ? node1 : node2; } else if (p1 < 0 && p2 < 0) { // all 4 nodes are real, pick the closest pair dist[node1][node3] = ADIFF(t.branch[node1].x, t.branch[node3].x) + ADIFF(t.branch[node1].y, t.branch[node3].y); dist[node1][node4] = ADIFF(t.branch[node1].x, t.branch[node4].x) + ADIFF(t.branch[node1].y, t.branch[node4].y); dist[node2][node3] = ADIFF(t.branch[node2].x, t.branch[node3].x) + ADIFF(t.branch[node2].y, t.branch[node3].y); dist[node2][node4] = ADIFF(t.branch[node2].x, t.branch[node4].x) + ADIFF(t.branch[node2].y, t.branch[node4].y); p1 = node1; p2 = node3; smallest = dist[p1][p2]; if (dist[node2][node3] < smallest) { p1 = node2; smallest = dist[p1][p2]; } if (dist[node1][node4] < smallest) { p1 = node1; p2 = node4; smallest = dist[p1][p2]; } if (dist[node2][node4] < smallest) { p1 = node2; p2 = node4; smallest = dist[p1][p2]; } } else { dist[p1][p2] = ADIFF(t.branch[p1].x, t.branch[p2].x) + ADIFF(t.branch[p1].y, t.branch[p2].y); } if (min_dist < dist[p1][p2]) { dist[p1][p2] = dist[p2][p1] = min_dist; enqueue(&nb[p1], p2); enqueue(&nb[p2], p1); if (min_dist < md) { md = min_dist; *min_node1 = p1; *min_node2 = p2; } } } } #if !(MR_FOR_SMALL_CASES_ONLY) free(isPin_base); free(id); free(b); #endif } void mst_from_heap(int d, DTYPE **dist, int node1, int node2, int **nb, int *edges, int *tree_id) { int i, j, itr, idx; node_pair e; hdist = dist; heap_size=0; for (i=0; i1; j--) { i=nb[node1][j]; if (tree_id[i]) continue; { e.node2 = i; insert_heap(&e); } } for (itr=d-2; itr>=1; itr--) { e.node1 = node2; for (j=nb[node2][1]-1; j>1; j--) { i=nb[node2][j]; if (tree_id[i]) continue; { e.node2 = i; insert_heap(&e); } } do { //assert(heap_size>0); //extract_heap(&e); e = heap[1]; while (tree_id[heap[heap_size].node2]) { heap_size--; } heap[1] = heap[heap_size--]; sift_down(1); node2 = e.node2; } while (tree_id[node2]); node1 = e.node1; tree_id[node2] = tree_id[node1]; edges[idx++] = node1; edges[idx++] = node2; } //assert(idx==2*d-2); } void build_rmst(long d, DTYPE *x, DTYPE *y, int *edges, int *inMST) { int i, j, idx, n; int *map = (int*)calloc(d, sizeof(int)); Point *pt = (Point*)calloc( 4*d, sizeof(Point) ); long *parent = (long*)calloc( 4*d, sizeof(long) ); long *par = (long*)calloc( 4*d, sizeof(long) ); int *size = (int*)calloc(d, sizeof(int)); for (i=0; i=0; j--) { if (pt[j].x==pt[i].x && pt[j].y==pt[i].y && par[j]>=0) { par[i]=j; break; } } } } for (i=0; i=0); size[parent[i]]++; } idx = 2*d-3; for (i=0; i0) { //assert(!inMST[j]); inMST[j] = 1; edges[idx--] = j; edges[idx--] = j = parent[j]; size[j]--; } } //assert(idx==-1); inMST[edges[0]]=1; free(pt); free(map); free(parent); free(par); free(size); } /* cached version */ Tree flutes_c(int d, DTYPE *xs, DTYPE *ys, int *s, int acc) { int i; //int orig_ht_flag; Tree t, tdup; #if USE_HASHING dl_forall(Tree, ht[d], t) { for (i=0; i= d) { // found a match tdup = t; tdup.branch = (Branch*)malloc(sizeof(Branch)*(2*d-2)); for (i=2*d-3; i>=0; i--) { tdup.branch[i] = t.branch[i]; } return tdup; } } dl_endfor; //orig_ht_flag = new_ht; //new_ht = 0; #endif t = flutes_LMD(d, xs, ys, s, acc); #if USE_HASHING //new_ht = orig_ht_flag; tdup = t; tdup.branch = (Branch*)malloc(sizeof(Branch)*(2*d-2)); for (i=2*d-3; i>=0; i--) { tdup.branch[i] = t.branch[i]; } dl_prepend(Tree, ht[d], tdup); #endif return t; } Tree flute_mr(int d, DTYPE *xs, DTYPE *ys, int *s, int acc, int rounds, DTYPE **dist, DTYPE *threshold_x, DTYPE *threshold_y, DTYPE *threshold, int *best_round, int *min_node1, int *min_node2, int **nb) { int i, j, k, m, n, itr, node1, node2; DTYPE min_dist, longest; DTYPE dist1, dist2; Tree t, best_t, *subtree, ttmp; DTYPE min_x, max_x; #if MR_FOR_SMALL_CASES_ONLY int num_subtree, subroot[MAXPART], suproot[MAXPART], isSuperRoot[D2M]; int tree_id[D2M], tid, tree_size[D2M], edges[2*D2M]; int idx[MAXPART], offset[MAXPART], *order[MAXT], order_base[MAXT*D2M]; DTYPE x[D2M+MAXPART], y[D2M+MAXPART]; int new_s[D2M+MAXPART], si[D2M], xmap[D2M+MAXPART]; #else int num_subtree, *subroot, *suproot, *isSuperRoot; int *tree_id, tid, *tree_size, *edges; int *idx, *offset, **order, *order_base; DTYPE *x, *y; int *new_s, *si, *xmap; subroot = (int*)malloc(sizeof(int)*MAXPART); suproot = (int*)malloc(sizeof(int)*MAXPART); idx = (int*)malloc(sizeof(int)*MAXPART); offset = (int*)malloc(sizeof(int)*MAXPART); order = (int**)malloc(sizeof(int*)*MAXT); isSuperRoot = (int*)malloc(sizeof(int)*d); tree_id = (int*)malloc(sizeof(int)*d); tree_size = (int*)malloc(sizeof(int)*d); edges = (int*)malloc(sizeof(int)*d*2); order_base = (int*)malloc(sizeof(int)*d*MAXT); new_s = (int*)malloc(sizeof(int)*(d+MAXPART)); si = (int*)malloc(sizeof(int)*d); xmap = (int*)malloc(sizeof(int)*(d+MAXPART)); x = (DTYPE*)malloc(sizeof(DTYPE)*(d+MAXPART)); y = (DTYPE*)malloc(sizeof(DTYPE)*(d+MAXPART)); #endif #if USE_HASHING if (new_ht) { for (i=0; i<=d; i++) { ht[i] = dl_alloc(); } } #endif best_t.branch = NULL; best_t.length = INFNTY; for (i=0; i=0) { for (i=0; i=0; ) { node2 = edges[i--]; node1 = edges[i--]; j = tree_size[node1]+tree_size[node2]; //Chris if (j >= TAU(acc)) { isSuperRoot[node1] = 1; suproot[num_subtree] = node1; subroot[num_subtree++] = node2; } else { tree_size[node1] = j; } } //assert(num_subtree<=MAXT); for (i=1; i= EARLY_QUIT_CRITERIA) { if (t.branch) { free(t.branch); } break; } } else if (best_t.length == t.length) { *best_round = rounds; } else if (best_t.length > t.length) { if (best_t.branch) { free(best_t.branch); } best_t = t; *best_round = rounds; } if (rounds > 0) { for (i=0; i=0; ) { node2 = edges[i--]; node1 = edges[i--]; j = tree_size[node1]+tree_size[node2]; //if (j >= d/2) { if (j >= d/2 && num_subtree<2) { isSuperRoot[node1] = 1; suproot[num_subtree] = node1; subroot[num_subtree++] = node2; } else { tree_size[node1] = j; } } */ for (i=2*d-3; i>=0; ) { node2 = edges[i--]; node1 = edges[i--]; tree_size[node1] += tree_size[node2]; } j = 0; smallest_gap = ADIFF(tree_size[j], d/2); for (i=1; i=0; ) { node2 = edges[i--]; node1 = edges[i--]; if (node2==j) { isSuperRoot[node1] = 1; suproot[num_subtree] = node1; subroot[num_subtree++] = node2; tree_size[subroot[0]] -= tree_size[j]; break; } } //assert(num_subtree<=MAXT); for (i=1; i= INFNTY && d > 1000) { D3 = (d <= 10000) ? 1000 : 10000; } t = flute_am(d, xs, ys, s, A, &threshold_x, &threshold_y, &threshold); if (orig_D3 >= INFNTY) { D3 = orig_D3; } } return t; } int pickWin(Tree t, DTYPE cx, DTYPE cy, int inWin[]) { #if MR_FOR_SMALL_CASES_ONLY int i, j, n, dd, cnt, stack[D2M*2], top=0, prev, curr, next; int isPin_base[D2M], *isPin, nghbr_base[D2M], *nghbr, q[2*D2M]; #else int i, j, n, dd, cnt, *stack, top=0, prev, curr, next; int *isPin_base, *isPin, *nghbr_base, *nghbr, *q; stack = (int*)malloc(sizeof(int)*t.deg*2); isPin_base = (int*)malloc(sizeof(int)*t.deg); nghbr_base = (int*)malloc(sizeof(int)*t.deg); q = (int*)malloc(sizeof(int)*t.deg*2); #endif if (t.deg <= 3) { for (i=0; i 0); while (top > 0) { i = stack[--top]; if (inWin[i]) { continue; } inWin[i] = 1; if (i < t.deg) { cnt++; continue; } n = isPin[i]; if (n >= 0) { if (!inWin[n]) { inWin[n] = 1; cnt++; } } else { stack[top++] = t.branch[i].n; for (j=nghbr[i]; j0); #if !(MR_FOR_SMALL_CASES_ONLY) free(stack); free(isPin_base); free(nghbr_base); free(q); #endif return cnt; } /* merge tree t2 into tree t1, which have shared common nodes. The intention is to add the non-common tree nodes of t2 into t1, as well as the associated steiner nodes */ Tree merge_into(Tree t1, Tree t2, int common[], int nc, int *o1, int *o2) { Tree t; DTYPE cx, cy; #if MR_FOR_SMALL_CASES_ONLY int i, j, k, d, n, offset, map[2*D2M], reachable[2*D2M]; int o[D2M+MAXPART]; #else int i, j, k, d, n, offset, *map, *reachable; int *o; map = (int*)malloc(sizeof(int)*(t1.deg+t2.deg)*2); reachable = (int*)malloc(sizeof(int)*(t1.deg+t2.deg)*2); o = (int*)malloc(sizeof(int)*(t1.deg+t2.deg+MAXPART2)); #endif if (t2.deg <= nc) { free(t2.branch); #if !(MR_FOR_SMALL_CASES_ONLY) free(map); free(reachable); free(o); #endif return t1; } t.deg = t1.deg + t2.deg - nc; t.branch = (Branch *) malloc((2*t.deg-2)*sizeof(Branch)); offset = t2.deg - nc; for (i=t1.deg; i=0; i--) { if (!common[i] && t2.branch[i].n!=i) { reachable[t2.branch[i].n] = 1; } } for (i=2*t2.deg-3; i>=0; i--) { map[i] = -1; } d = t1.deg*2 - 2; /* a slow method; could be sped up here */ for (i=0; i=t2.deg) { for (; i=t1.deg) { for (; k=t1.deg); t.branch[j].n = map[n] + offset; o[j] = o2[k]; j++; } } else if (o1[i] < o2[k]) { t.branch[j] = t1.branch[i]; t.branch[j].n = t1.branch[i].n + offset; o[j] = o1[i]; j++; i++; } else { t.branch[j] = t2.branch[k]; n = t2.branch[k].n; //assert(map[n]>=t1.deg); t.branch[j].n = map[n] + offset; o[j] = o2[k]; j++; do { k++; } while (k=t1.deg); t.branch[map[i]+offset].n = map[n] + offset; j++; } } j = d+offset; //assert(j <= t.deg*2-2); while (j < t.deg*2-2) { /* redundant steiner nodes */ t.branch[j] = t2.branch[0]; t.branch[j].n = j; j++; } /* for (i=0; i=t.deg); } */ t.length = wirelength(t); free(t1.branch); free(t2.branch); #if !(MR_FOR_SMALL_CASES_ONLY) free(map); free(reachable); free(o); #endif return t; } /* simply merge two trees at their common node */ Tree smergetree(Tree t1, Tree t2, int *o1, int *o2, DTYPE cx, DTYPE cy) { Tree t; int d, i, j, k, n, ci, cn, mapped_cn, prev, curr, next, offset; #if MR_FOR_SMALL_CASES_ONLY int o[D2M+MAXPART], map[2*D2M]; #else int *o, *map; map = (int*)malloc(sizeof(int)*(t1.deg+t2.deg)*2); o = (int*)malloc(sizeof(int)*(t1.deg+t2.deg+MAXPART2)); #endif t.deg = t1.deg + t2.deg - 1; t.branch = (Branch *) malloc((2*t.deg-2)*sizeof(Branch)); offset = t2.deg - 1; d = t1.deg*2-2; for (i=0; i=t2.deg) { for (; i=t1.deg) { for (; k2 && t2.deg>2) { if (d= t2.deg) { for (; i1= t1.deg) { for (; i2 2) { for (i=0; i0) { dl_pop_first(TreeNode*, subtree, p); p->e = p; grandp = p->parent; if (grandp) { p->len = p->blen = ADIFF(p->x, grandp->x) + ADIFF(p->y, grandp->y); if (p->len < grandp->len) { p->len = grandp->len; p->e = grandp->e; } } else { p->len = 0; } if (id) { p->id = id; } dl_forall(TreeNode*, p->children, child) { dl_prepend(TreeNode*, subtree, child); } dl_endfor; } dl_free(subtree); } TreeNode *createRootedTree(Tree t, int *order, int id, dl_t list_of_nodes) { int i, dd, n; TreeNode *root=0, **nodes, *p; dd = t.deg*2-2; nodes = (TreeNode**)malloc(sizeof(TreeNode*)*dd); for (i=0; imark = curr_mark; nodes[i]->children = dl_alloc(); } curr_mark++; for (i=0; imark = curr_mark; n = t.branch[i].n; if (i==n) { if (i < t.deg) { //assert(root==0); nodes[i]->parent = 0; root = nodes[i]; } else { /* must be redundant */ dl_free(nodes[i]->children); free(nodes[i]); nodes[i] = 0; continue; } } else { p = nodes[n]; nodes[i]->parent = p; dl_append(TreeNode*, p->children, nodes[i]); } nodes[i]->order = (i < t.deg) ? order[i] : -1; nodes[i]->id = id; nodes[i]->x = t.branch[i].x; nodes[i]->y = t.branch[i].y; /* len will be computed in update_subtree nodes[i]->blen = ADIFF(t.branch[i].x, t.branch[n].x)+ADIFF(t.branch[i].y, t.branch[n].y); nodes[i]->e = nodes[i]; nodes[i]->len = ADIFF(t.branch[i].x, t.branch[n].x)+ADIFF(t.branch[i].y, t.branch[n].y); */ dl_append(TreeNode*, list_of_nodes, nodes[i]); } //assert(root); update_subtree(root, 0); for (i=0; imark!=curr_mark) { dl_free(nodes[i]->children); free(nodes[i]); } } free(nodes); return root; } void freeTree(TreeNode *t) { TreeNode *child; dl_forall(TreeNode *, t->children, child) { freeTree(child); } dl_endfor; dl_free(t->children); free(t); } int cmpNodeByYX(const void* a, const void* b) { DTYPE ay = (*(TreeNode**)a)->y; DTYPE by = (*(TreeNode**)b)->y; DTYPE ax, bx; if (ay < by) return -1; if (ay > by) return 1; ax = (*(TreeNode**)a)->x; bx = (*(TreeNode**)b)->x; if (ax < bx) return -1; if (ax > bx) return 1; return 0; } int cmpNodeByXY(const void* a, const void* b) { DTYPE ax = (*(TreeNode**)a)->x; DTYPE bx = (*(TreeNode**)b)->x; DTYPE ay, by; if (ax < bx) return -1; if (ax > bx) return 1; ay = (*(TreeNode**)a)->y; by = (*(TreeNode**)b)->y; if (ay < by) return -1; if (ay > by) return 1; return 0; } void remove_child(dl_t children_list, TreeNode* c) { TreeNode *child; dl_forall(TreeNode*, children_list, child) { if (child==c) { dl_delete_current(); break; } } dl_endfor; } void cleanTree(TreeNode* tn) { /* TreeNode *c, *p; dl_forall(TreeNode*, tn->children, c) { cleanTree(c); } dl_endfor; p = tn->parent; if (!p) return; if (tn->order >= 0) return; // don't clean pin nodes if (dl_length(tn->children)<=0) { remove_child(p->children, tn); dl_free(tn->children); free(tn); } else if (dl_length(tn->children)<=1) { c = dl_first(TreeNode*, tn->children); c->parent = p; dl_append(TreeNode*, p->children, c); remove_child(p->children, tn); dl_free(tn->children); free(tn); } */ // non-recursive version TreeNode *c, *p; dl_t nlist=dl_alloc(); dl_append(TreeNode*, nlist, tn); while (dl_length(nlist)>0) { dl_pop_first(TreeNode*, nlist, tn); dl_forall(TreeNode*, tn->children, c) { dl_append(TreeNode*, nlist, c); } dl_endfor; p = tn->parent; if (p && tn->order < 0) { if (dl_length(tn->children)<=0) { remove_child(p->children, tn); dl_free(tn->children); free(tn); } else if (dl_length(tn->children)<=1) { c = dl_first(TreeNode*, tn->children); c->parent = p; dl_append(TreeNode*, p->children, c); remove_child(p->children, tn); dl_free(tn->children); free(tn); } } } dl_free(nlist); } int cmpNodeByOrder(void* a, void* b) { int ax = (*(TreeNode**)a)->order; int bx = (*(TreeNode**)b)->order; if (ax < bx) return -1; if (ax > bx) return 1; return 0; } Tree mergeRootedTrees(TreeNode *tn1, TreeNode *tn2, int *order1) { int i, n, redundant; Tree t; TreeNode *child, *p; dl_t list_of_nodes=dl_alloc(); dl_t pin_nodes=dl_alloc(), steiner_nodes=dl_alloc(); //assert(tn1->x==tn2->x && tn1->y==tn2->y); /* merge tn2 to tn1 */ while (dl_length(tn2->children)>0) { dl_pop_first(TreeNode*, tn2->children, child); child->parent = tn1; dl_append(TreeNode*, tn1->children, child); } dl_free(tn2->children); free(tn2); cleanTree(tn1); /* convert tn1 back to a Tree */ dl_append(TreeNode*, list_of_nodes, tn1); do { dl_pop_first(TreeNode*, list_of_nodes, child); if (child->order < 0) { if (dl_length(child->children)==1) { /* redundant steiner node */ p = dl_first(TreeNode*, child->children); p->parent = child->parent; /* note that p->parent's children list is already gone */ dl_append(TreeNode*, list_of_nodes, p); dl_free(child->children); free(child); continue; } else if (dl_length(child->children)==0) { dl_free(child->children); free(child); continue; } dl_append(TreeNode*, steiner_nodes, child); } else { dl_append(TreeNode*, pin_nodes, child); } dl_concat(list_of_nodes, child->children); } while (dl_length(list_of_nodes)>0); dl_free(list_of_nodes); dl_sort(pin_nodes, sizeof(TreeNode*), cmpNodeByOrder); i=0; dl_forall(TreeNode*, pin_nodes, child) { child->id = i++; } dl_endfor; t.deg = i; dl_forall(TreeNode*, steiner_nodes, child) { child->id = i++; } dl_endfor; //assert(i<=2*t.deg-2); t.branch = (Branch*)malloc(sizeof(Branch)*(t.deg*2-2)); redundant = i; for (; i<2*t.deg-2; i++) { t.branch[i].n = i; t.branch[i].x = tn1->x; t.branch[i].y = tn1->y; } t.branch[tn1->id].n = -1; dl_forall(TreeNode*, pin_nodes, child) { i = child->id; if (child->order >= 0) { order1[i] = child->order; } t.branch[i].x = child->x; t.branch[i].y = child->y; p = child->parent; if (p) { if (p->id >= t.deg) { t.branch[i].n = p->id; } else { //assert(p==tn1); //assert(redundantid].n = redundant; t.branch[redundant].x = p->x; t.branch[redundant].y = p->y; redundant++; } } } dl_endfor; dl_forall(TreeNode*, steiner_nodes, child) { i = child->id; if (child->order >= 0) { order1[i] = child->order; } t.branch[i].x = child->x; t.branch[i].y = child->y; p = child->parent; if (p->id < t.deg) { // must be the root if (t.branch[p->id].n < 0) { t.branch[p->id].n = i; t.branch[i].n = i; } else { n = t.branch[p->id].n; if (t.branch[p->id].x==t.branch[n].x && t.branch[p->id].y==t.branch[n].y) { t.branch[i].n = n; } else { //assert(redundantid].x; t.branch[redundant].y = t.branch[p->id].y; t.branch[redundant].n = t.branch[p->id].n; t.branch[p->id].n = redundant; t.branch[i].n = redundant; redundant++; } } } else { t.branch[i].n = p->id; } } dl_endfor; dl_forall(TreeNode*, pin_nodes, child) { free(child); } dl_endfor; dl_free(pin_nodes); dl_forall(TreeNode*, steiner_nodes, child) { free(child); } dl_endfor; dl_free(steiner_nodes); t.length = wirelength(t); return t; } void collect_nodes(TreeNode* tn, dl_t nlist) { /* TreeNode* c; dl_append(TreeNode*, nlist, tn); dl_forall(TreeNode*, tn->children, c) { collect_nodes(c, nlist); }dl_endfor; */ // non-recursive version TreeNode* c; dl_el *curr; dl_append(TreeNode*, nlist, tn); for (curr=nlist->last; curr; curr=curr->next) { tn = dl_data(TreeNode*, curr); dl_forall(TreeNode*, tn->children, c) { dl_append(TreeNode*, nlist, c); }dl_endfor; } } typedef struct { TreeNode *n1, *n2; DTYPE new_x, new_y, gain; } xdata; int cmpXdata(void *a, void *b) { DTYPE ga = (*(xdata*)a).gain; DTYPE gb = (*(xdata*)b).gain; if (ga > gb) return -1; if (ga < gb) return 1; return 0; } TreeNode *cedge_lca(TreeNode* n1, TreeNode* n2, DTYPE *len, int *n2ton1) { int i; TreeNode *curr, *lca, *e; curr_mark++; curr = n1; while (curr) { curr->mark = curr_mark; curr = curr->parent; } lca = n2; while (lca && lca->mark!=curr_mark) { lca->mark = curr_mark; lca = lca->parent; } if (!lca) { n1 = n1->parent; if (n1 && n1!=lca && (n1->len > n2->len)) { *n2ton1 = 0; *len = n1->len; return n1->e; } else { *n2ton1 = 1; *len = n2->len; return n2->e; } } if (lca==n1 || lca==n1->parent || lca==n2) { if (lca!=n2) { *n2ton1 = 1; *len = n2->blen; e = n2; curr = n2->parent; } else { *n2ton1 = 0; *len = n1->blen; e = n1; curr = n1->parent; } while (curr != lca) { if (*len < curr->blen) { *len = curr->blen; e = curr; } curr = curr->parent; } return e; } /* lca is above both n1 and n2 */ *n2ton1 = 0; n1 = n1->parent; *len = n1->blen; e = n1; curr = n1; for (i=0; i<2; i++, curr=n2) { while (curr != lca) { if (*len < curr->blen) { if (i>0) { *n2ton1 = 1; } *len = curr->blen; e = curr; } curr = curr->parent; } } return e; } TreeNode *critical_edge(TreeNode* n1, TreeNode* n2, DTYPE *len, int *n2ton1) { if (n1->id != n2->id) { n1 = n1->parent; if (n1 && (n1->len > n2->len)) { *n2ton1 = 0; *len = n1->len; return n1->e; } else { *n2ton1 = 1; *len = n2->len; return n2->e; } } return cedge_lca(n1, n2, len, n2ton1); } void splice2(TreeNode *n1, TreeNode *n2, TreeNode *e) { TreeNode *curr, *prev, *next, *s; //assert(n2->parent); //assert(e->id==n2->id); prev = n2; curr = n2->parent; next = curr->parent; while (prev != e) { remove_child(curr->children, prev); curr->parent = prev; dl_append(TreeNode*, prev->children, curr); prev = curr; curr = next; next = curr->parent; } remove_child(curr->children, prev); n2->parent = n1; dl_append(TreeNode*, n1->children, n2); update_subtree(n1, n1->parent->id); } void cut_and_splice(TreeNode *n1, TreeNode *n2, DTYPE new_x, DTYPE new_y, DTYPE *x1, DTYPE *y1, DTYPE *x2, DTYPE *y2, TreeNode *e, int n2ton1) { TreeNode *p1, *node, *s; /* new steiner node */ p1 = n1->parent; remove_child(p1->children, n1); node = (TreeNode*)malloc(sizeof(TreeNode)); node->x = new_x; node->y = new_y; node->mark = curr_mark; node->parent = p1; dl_append(TreeNode*, p1->children, node); n1->parent = node; node->children = dl_alloc(); dl_append(TreeNode*, node->children, n1); node->order = -1; node->e = n1->e; node->id = n1->id; if (*x1==n1->x) { *x2 = new_x; } else { *x1 = new_x; } if (*y1==n1->y) { *y2 = new_y; } else { *y1 = new_y; } if (n2->order >= 0) { /* n2 is a pin, need to replicate a steiner node */ s = n2->parent; if (s->x!=n2->x || s->y!=n2->y) { s = (TreeNode*)malloc(sizeof(TreeNode)); s->mark = curr_mark; s->order = -1; s->id = n2->id; s->x = n2->x; s->y = n2->y; s->e = n2->e; if (s->e == n2) { s->e = s; } if (e == n2) { e = s; } s->len = n2->len; s->blen = n2->blen; n2->blen = 0; remove_child(n2->parent->children, n2); dl_append(TreeNode*, n2->parent->children, s); s->parent = n2->parent; n2->parent = s; s->children = dl_alloc(); dl_append(TreeNode*, s->children, n2); } n2 = s; } if (n2ton1) { splice2(node, n2, e); } else { splice2(n2, node, e); } } typedef struct { TreeNode *n1, *n2; DTYPE min_dist, new_x, new_y; int n2ton1; } splice_info; DTYPE exchange_branches_order_x(int num_nodes, TreeNode **nodes, DTYPE threshold_x, DTYPE threshold_y, DTYPE max_len) { int n2ton1; TreeNode *n1, *p1, *n2, *p2, *node, *e, *s; DTYPE x1, x2, y1, y2, min_dist, new_x, new_y, len; DTYPE gain=0; int i, j, curr_row, next_header, num_rows, start, end, mid; int *header=(int*)malloc(sizeof(int)*(num_nodes+1)); dl_t batch_list=dl_alloc(); splice_info sinfo; int batch_mode = (num_nodes >= D3); header[0]=0; y1 = nodes[0]->y; for (i=num_rows=1; iy == y1) { continue; } header[num_rows++] = i; y1 = nodes[i]->y; } header[num_rows] = i; curr_row = 0; next_header = header[1]; for (i=0; i= next_header) { curr_row++; next_header = header[curr_row+1]; } n1 = nodes[i]; p1 = n1->parent; if (!p1) { continue; } if (p1->x == n1->x && p1->y == n1->y) { continue; } if (n1->x <= p1->x) { x1 = n1->x; x2 = p1->x; } else { x1 = p1->x; x2 = n1->x; } if (n1->y <= p1->y) { y1 = n1->y; y2 = p1->y; } else { y1 = p1->y; y2 = n1->y; } if (curr_row > 0) { for (j=curr_row-1; j>0; j--) { if (y1 - threshold_y > nodes[header[j]]->y) { j++; break; } } } else { j = 0; } for (;j < num_rows && nodes[header[j]]->y <= y2 + threshold_y; j++) { /* find the closest node on row j */ start = header[j]; end = header[j+1]; while (start < end) { mid = (start+end)/2; if (nodes[mid]->x <= x1) { start = mid + 1; } else { end = mid; } } //assert(start==end); if (start >= header[j+1]) { continue; } n2 = nodes[start]; if (batch_mode && n1->id==n2->id) continue; if (!n2->parent) { continue; } min_dist = n2->x - x2; if (flute_abs(min_dist) > threshold_x) { continue; } else if (min_dist < 0) { min_dist = 0; new_x = n2->x; } else { new_x = x2; } if (n2->y < y1) { min_dist += y1 - n2->y; new_y = y1; } else if (n2->y > y2) { min_dist += n2->y - y2; new_y = y2; } else { new_y = n2->y; } if (min_dist ==0 || min_dist > max_len) { continue; } e = critical_edge(n1, n2, &len, &n2ton1); if (min_dist < len && e!=n1) { if (batch_mode) { sinfo.n1 = n1; sinfo.n2 = n2; sinfo.min_dist = min_dist; sinfo.new_x = new_x; sinfo.new_y = new_y; sinfo.n2ton1 = n2ton1; dl_append(splice_info, batch_list, sinfo); } else { gain += len - min_dist; cut_and_splice(n1, n2, new_x, new_y, &x1, &y1, &x2, &y2, e, n2ton1); } } } } dl_forall(splice_info, batch_list, sinfo) { n1 = sinfo.n1; n2 = sinfo.n2; n2ton1 = sinfo.n2ton1; min_dist = sinfo.min_dist; e = critical_edge(n1, n2, &len, &n2ton1); if (min_dist < len && e!=n1) { gain += len - min_dist; cut_and_splice(n1, n2, sinfo.new_x, sinfo.new_y, &x1, &y1, &x2, &y2, e, n2ton1); } } dl_endfor; dl_free(batch_list); free(header); return gain; } DTYPE exchange_branches_order_y(int num_nodes, TreeNode **nodes, DTYPE threshold_x, DTYPE threshold_y, DTYPE max_len) { int n2ton1; TreeNode *n1, *p1, *n2, *p2, *node, *e, *s; DTYPE x1, x2, y1, y2, min_dist, new_x, new_y, len; DTYPE gain=0; int i, j, curr_row, next_header, num_rows, start, end, mid; int *header=(int*)malloc(sizeof(int)*(num_nodes+1)); dl_t batch_list=dl_alloc(); splice_info sinfo; int batch_mode = (num_nodes >= D3); header[0]=0; x1 = nodes[0]->x; for (i=num_rows=1; ix == x1) { continue; } header[num_rows++] = i; x1 = nodes[i]->x; } header[num_rows] = i; curr_row = 0; next_header = header[1]; for (i=0; i= next_header) { curr_row++; next_header = header[curr_row+1]; } n1 = nodes[i]; p1 = n1->parent; if (!p1) { continue; } if (p1->x == n1->x && p1->y == n1->y) { continue; } if (n1->x <= p1->x) { x1 = n1->x; x2 = p1->x; } else { x1 = p1->x; x2 = n1->x; } if (n1->y <= p1->y) { y1 = n1->y; y2 = p1->y; } else { y1 = p1->y; y2 = n1->y; } if (curr_row > 0) { for (j=curr_row-1; j>0; j--) { if (x1 - threshold_x > nodes[header[j]]->x) { j++; break; } } } else { j = 0; } for (;j < num_rows && nodes[header[j]]->x <= x2 + threshold_x; j++) { /* find the closest node on row j */ start = header[j]; end = header[j+1]; while (start < end) { mid = (start+end)/2; if (nodes[mid]->y <= y1) { start = mid + 1; } else { end = mid; } } //assert(start==end); if (start >= header[j+1]) { continue; } n2 = nodes[start]; if (batch_mode && n1->id==n2->id) continue; if (!n2->parent) { continue; } min_dist = n2->y - y2; if (flute_abs(min_dist) > threshold_y) { continue; } else if (min_dist < 0) { min_dist = 0; new_y = n2->y; } else { new_y = y2; } if (n2->x < x1) { min_dist += x1 - n2->x; new_x = x1; } else if (n2->x > x2) { min_dist += n2->x - x2; new_x = x2; } else { new_x = n2->x; } if (min_dist ==0 || min_dist > max_len) { continue; } e = critical_edge(n1, n2, &len, &n2ton1); if (min_dist < len && e!=n1) { if (batch_mode) { sinfo.n1 = n1; sinfo.n2 = n2; sinfo.min_dist = min_dist; sinfo.new_x = new_x; sinfo.new_y = new_y; sinfo.n2ton1 = n2ton1; dl_append(splice_info, batch_list, sinfo); } else { gain += len - min_dist; cut_and_splice(n1, n2, new_x, new_y, &x1, &y1, &x2, &y2, e, n2ton1); } } } } dl_forall(splice_info, batch_list, sinfo) { n1 = sinfo.n1; n2 = sinfo.n2; n2ton1 = sinfo.n2ton1; min_dist = sinfo.min_dist; e = critical_edge(n1, n2, &len, &n2ton1); if (min_dist < len && e!=n1) { gain += len - min_dist; cut_and_splice(n1, n2, sinfo.new_x, sinfo.new_y, &x1, &y1, &x2, &y2, e, n2ton1); } } dl_endfor; dl_free(batch_list); free(header); return gain; } /* cross exchange branches after merging */ Tree xmergetree(Tree t1, Tree t2, int *order1, int *order2, DTYPE cx, DTYPE cy) { int i, num, cnt, order_by_x=1; Tree t; TreeNode *tn1, *tn2, *n1, *p1, **nodes; dl_t list_of_nodes=dl_alloc(); DTYPE threshold_x, threshold_y; DTYPE min_x, max_x, max_len, len, gain; if (t1.deg <= 0) { for (i=0; ix; for (i=0; iparent; if (p1) { len = ADIFF(n1->x, p1->x) + ADIFF(n1->y, p1->y); if (len > max_len) { max_len = len; } } if (n1->x < min_x) { min_x = n1->x; } else if (n1->x > max_x) { max_x = n1->x; } } threshold_x = (max_x - min_x)/4; threshold_y = (nodes[num-1]->y - nodes[0]->y)/4; threshold_x = flute_min(threshold_x, max_len); threshold_y = flute_min(threshold_y, max_len); for (cnt=(t1.deg+t2.deg)/2; cnt>0; cnt--) { gain = (order_by_x) ? exchange_branches_order_x(num, nodes, threshold_x, threshold_y, max_len): exchange_branches_order_y(num, nodes, threshold_x, threshold_y, max_len); //assert(gain>=0); if (gain <= 0 && !order_by_x) { break; } if (cnt>1) { collect_nodes(tn1, list_of_nodes); num = dl_length(list_of_nodes); if (num <= 1) { break; } collect_nodes(tn2, list_of_nodes); if (dl_length(list_of_nodes)-num <= 1) { break; } free(nodes); num = dl_length(list_of_nodes); nodes = (TreeNode**)malloc(sizeof(TreeNode*)*num); i = 0; dl_forall(TreeNode*, list_of_nodes, n1) { nodes[i++] = n1; } dl_endfor; dl_clear(list_of_nodes); if (order_by_x) { order_by_x = 0; qsort(nodes, num, sizeof(TreeNode*), cmpNodeByXY); } else { order_by_x = 1; qsort(nodes, num, sizeof(TreeNode*), cmpNodeByYX); } } } dl_free(list_of_nodes); free(nodes); t = mergeRootedTrees(tn1, tn2, order1); free(t1.branch); free(t2.branch); return t; } ================================================ FILE: src/flute/global.h ================================================ #ifndef _GLOBAL_H_ #define _GLOBAL_H_ #include #define TRUE 1 #define FALSE 0 #define MAXLONG 0x7fffffffL struct point { long x, y; }; typedef struct point Point; typedef long nn_array[8]; #endif /* _GLOBAL_H_ */ ================================================ FILE: src/flute/heap.c ================================================ /****************************************************************************/ /* Binary heap routines for use in Prim's algorithm, with points are numbered from 0 to n-1 */ #include #include "heap.h" #include "err.h" Heap* _heap = (Heap*)NULL; long _max_heap_size = 0; long _heap_size = 0; /****************************************************************************/ /* */ void allocate_heap( long n ) { if( _max_heap_size < n ) { _heap = (Heap*)realloc( (void*)_heap, (size_t)(n+1)*sizeof(Heap) ); if( ! _heap ) { err_exit( "Cannot reallocate memory in allocate_heap!" ); } _max_heap_size = n; } } /****************************************************************************/ /* */ void deallocate_heap() { _max_heap_size = 0; if( _heap ) { free( (void*)_heap ); _heap = (Heap*)NULL; } } /****************************************************************************/ void heap_init( long n ) { register long p; allocate_heap( n ); _heap_size = 0; for( p = 0; p < n; p++ ) { heap_idx( p ) = 0; } } /* END heap_init() */ /****************************************************************************/ void heap_insert( long p, long key ) { register long k; /* hole in the heap */ register long j; /* parent of the hole */ register long q; /* heap_elt(j) */ heap_key( p ) = key; if( _heap_size == 0 ) { _heap_size = 1; heap_elt( 1 ) = p; heap_idx( p ) = 1; return; } k = ++ _heap_size; j = k >> 1; /* k/2 */ while( (j > 0) && (heap_key(q=heap_elt(j)) > key) ) { heap_elt( k ) = q; heap_idx( q ) = k; k = j; j = k>>1; /* k/2 */ } /* store p in the position of the hole */ heap_elt( k ) = p; heap_idx( p ) = k; } /* END heap_insert() */ /****************************************************************************/ void heap_decrease_key ( long p, long new_key ) { register long k; /* hole in the heap */ register long j; /* parent of the hole */ register long q; /* heap_elt(j) */ heap_key( p ) = new_key; k = heap_idx( p ); j = k >> 1; /* k/2 */ if( (j > 0) && (heap_key(q=heap_elt(j)) > new_key) ) { /* change is needed */ do { heap_elt( k ) = q; heap_idx( q ) = k; k = j; j = k>>1; /* k/2 */ } while( (j > 0) && (heap_key(q=heap_elt(j)) > new_key) ); /* store p in the position of the hole */ heap_elt( k ) = p; heap_idx( p ) = k; } } /* END heap_decrease_key() */ /****************************************************************************/ long heap_delete_min() { long min, last; register long k; /* hole in the heap */ register long j; /* child of the hole */ register long l_key; /* key of last point */ if( _heap_size == 0 ) /* heap is empty */ return( -1 ); min = heap_elt( 1 ); last = heap_elt( _heap_size -- ); l_key = heap_key( last ); k = 1; j = 2; while( j <= _heap_size ) { if( heap_key(heap_elt(j)) > heap_key(heap_elt(j+1)) ) j++; if( heap_key(heap_elt(j)) >= l_key) break; /* found a position to insert 'last' */ /* else, sift hole down */ heap_elt(k) = heap_elt(j); /* Note that j <= _heap_size */ heap_idx( heap_elt(k) ) = k; k = j; j = k << 1; } heap_elt( k ) = last; heap_idx( last ) = k; heap_idx( min ) = -1; /* mark the point visited */ return( min ); } /* END heap_delete_min() */ /****************************************************************************/ ================================================ FILE: src/flute/heap.h ================================================ #ifndef _HEAP_H_ #define _HEAP_H_ #include "global.h" struct heap_info { long key; long idx; long elt; }; typedef struct heap_info Heap; extern Heap* _heap; #define heap_key( p ) ( _heap[p].key ) #define heap_idx( p ) ( _heap[p].idx ) #define heap_elt( k ) ( _heap[k].elt ) #define in_heap( p ) ( heap_idx(p) > 0 ) #define never_seen( p ) ( heap_idx(p) == 0 ) void allocate_heap( long n ); void deallocate_heap(); void heap_init( long n ); void heap_insert( long p, long key ); void heap_decrease_key( long p, long new_key ); long heap_delete_min(); #endif /* _HEAP_H_ */ ================================================ FILE: src/flute/license.txt ================================================ READ THIS LICENSE AGREEMENT CAREFULLY BEFORE USING THIS PRODUCT. BY USING THIS PRODUCT YOU INDICATE YOUR ACCEPTANCE OF THE TERMS OF THE FOLLOWING AGREEMENT. THESE TERMS APPLY TO YOU AND ANY SUBSEQUENT LICENSEE OF THIS PRODUCT. License Agreement for FLUTE Copyright (c) 2004 by Dr. Chris C. N. Chu All rights reserved ATTRIBUTION ASSURANCE LICENSE (adapted from the original BSD license) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the conditions below are met. These conditions require a modest attribution to Dr. Chris C. N. Chu (the "Author"). 1. Redistributions of the source code, with or without modification (the "Code"), must be accompanied by any documentation and, each time the resulting executable program or a program dependent thereon is launched, a prominent display (e.g., splash screen or banner text) of the Author's attribution information, which includes: (a) Dr. Chris C. N. Chu ("AUTHOR"), (b) Iowa State University ("PROFESSIONAL IDENTIFICATION"), and (c) http://home.engineering.iastate.edu/~cnchu/ ("URL"). 2. Users who intend to use the Code for commercial purposes will notify Author prior to such commercial use. 3. Neither the name nor any trademark of the Author may be used to endorse or promote products derived from this software without specific prior written permission. 4. Users are entirely responsible, to the exclusion of the Author and any other persons, for compliance with (1) regulations set by owners or administrators of employed equipment, (2) licensing terms of any other software, and (3) local, national, and international regulations regarding use, including those regarding import, export, and use of encryption software. THIS FREE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, EFFECTS OF UNAUTHORIZED OR MALICIOUS NETWORK ACCESS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: src/flute/memAlloc.c ================================================ /* -------------------------------------------------------------------------- Public domain memory allocation and de-allocation routines. Taken from Appendix B of: Numerical Recipes in C: The Art of Scientific Computing, Second Edition, Cambridge University Press, 1992 ----------------------------------------------------------------------------*/ #include #include #include #include "memAlloc.h" #define MEM_END 1 #define FREE_ARG char* void runtimeError(char error_text[]) /* error handler */ { fprintf(stderr, "ERROR: %s \n", error_text); fprintf(stderr, "Aborting !! \n"); fflush(stdout); fflush(stderr); exit(1); } float *vector(long nl, long nh) /* allocate a float vector with subscript range v[nl..nh] */ { float *v; v=(float *)malloc((size_t) ((nh-nl+1+MEM_END)*sizeof(float))); if (!v) runtimeError("allocation failure in vector()"); return v-nl+MEM_END; } int *ivector(long nl, long nh) /* allocate an int vector with subscript range v[nl..nh] */ { int *v; v=(int *)malloc((size_t) ((nh-nl+1+MEM_END)*sizeof(int))); if (!v) runtimeError("allocation failure in ivector()"); return v-nl+MEM_END; } unsigned char *cvector(long nl, long nh) /* allocate an unsigned char vector with subscript range v[nl..nh] */ { unsigned char *v; v=(unsigned char *)malloc((size_t) ((nh-nl+1+MEM_END)*sizeof(unsigned char))); if (!v) runtimeError("allocation failure in cvector()"); return v-nl+MEM_END; } unsigned long *lvector(long nl, long nh) /* allocate an unsigned long vector with subscript range v[nl..nh] */ { unsigned long *v; v=(unsigned long *)malloc((size_t) ((nh-nl+1+MEM_END)*sizeof(long))); if (!v) runtimeError("allocation failure in lvector()"); return v-nl+MEM_END; } double *dvector(long nl, long nh) /* allocate a double vector with subscript range v[nl..nh] */ { double *v; v=(double *)malloc((size_t) ((nh-nl+1+MEM_END)*sizeof(double))); if (!v) runtimeError("allocation failure in dvector()"); return v-nl+MEM_END; } float **matrix(long nrl, long nrh, long ncl, long nch) /* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */ { long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; float **m; /* allocate pointers to rows */ m=(float **) malloc((size_t)((nrow+MEM_END)*sizeof(float*))); if (!m) runtimeError("allocation failure 1 in matrix()"); m += MEM_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl]=(float *) malloc((size_t)((nrow*ncol+MEM_END)*sizeof(float))); if (!m[nrl]) runtimeError("allocation failure 2 in matrix()"); m[nrl] += MEM_END; m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; /* return pointer to array of pointers to rows */ return m; } double **dmatrix(long nrl, long nrh, long ncl, long nch) /* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */ { long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; double **m; /* allocate pointers to rows */ m=(double **) malloc((size_t)((nrow+MEM_END)*sizeof(double*))); if (!m) runtimeError("allocation failure 1 in dmatrix()"); m += MEM_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl]=(double *) malloc((size_t)((nrow*ncol+MEM_END)*sizeof(double))); if (!m[nrl]) runtimeError("allocation failure 2 in dmatrix()"); m[nrl] += MEM_END; m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; /* return pointer to array of pointers to rows */ return m; } int **imatrix(long nrl, long nrh, long ncl, long nch) /* allocate a int matrix with subscript range m[nrl..nrh][ncl..nch] */ { long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; int **m; /* allocate pointers to rows */ m=(int **) malloc((size_t)((nrow+MEM_END)*sizeof(int*))); if (!m) runtimeError("allocation failure 1 in imatrix()"); m += MEM_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl]=(int *) malloc((size_t)((nrow*ncol+MEM_END)*sizeof(int))); if (!m[nrl]) runtimeError("allocation failure 2 in imatrix()"); m[nrl] += MEM_END; m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; /* return pointer to array of pointers to rows */ return m; } char **cmatrix(long nrl, long nrh, long ncl, long nch) /* allocate a char matrix with subscript range m[nrl..nrh][ncl..nch] */ { long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; char **m; /* allocate pointers to rows */ m=(char **) malloc((size_t)((nrow+MEM_END)*sizeof(char*))); if (!m) runtimeError("allocation failure 1 in cmatrix()"); m += MEM_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl]=(char *) malloc((size_t)((nrow*ncol+MEM_END)*sizeof(char))); if (!m[nrl]) runtimeError("allocation failure 2 in cmatrix()"); m[nrl] += MEM_END; m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; /* return pointer to array of pointers to rows */ return m; } unsigned long **lmatrix(long nrl, long nrh, long ncl, long nch) /* allocate a int matrix with subscript range m[nrl..nrh][ncl..nch] */ { long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; unsigned long **m; /* allocate pointers to rows */ m=(unsigned long **) malloc((size_t)((nrow+MEM_END)*sizeof(long*))); if (!m) runtimeError("allocation failure 1 in lmatrix()"); m += MEM_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl]=(unsigned long *) malloc((size_t)((nrow*ncol+MEM_END)*sizeof(long))); if (!m[nrl]) runtimeError("allocation failure 2 in lmatrix()"); m[nrl] += MEM_END; m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; /* return pointer to array of pointers to rows */ return m; } float **submatrix(float **a, long oldrl, long oldrh, long oldcl, long oldch, long newrl, long newcl) /* point a submatrix [newrl..][newcl..] to a[oldrl..oldrh][oldcl..oldch] */ { long i,j,nrow=oldrh-oldrl+1,ncol=oldcl-newcl; float **m; /* allocate array of pointers to rows */ m=(float **) malloc((size_t) ((nrow+MEM_END)*sizeof(float*))); if (!m) runtimeError("allocation failure in submatrix()"); m += MEM_END; m -= newrl; /* set pointers to rows */ for(i=oldrl,j=newrl;i<=oldrh;i++,j++) m[j]=a[i]+ncol; /* return pointer to array of pointers to rows */ return m; } float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch) /* allocate a float matrix m[nrl..nrh][ncl..nch] that points to the matrix declared in the standard C manner as a[nrow][ncol], where nrow=nrh-nrl+1 and ncol=nch-ncl+1. The routine should be called with the address &a[0][0] as the first argument. */ { long i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1; float **m; /* allocate pointers to rows */ m=(float **) malloc((size_t) ((nrow+MEM_END)*sizeof(float*))); if (!m) runtimeError("allocation failure in convert_matrix()"); m += MEM_END; m -= nrl; /* set pointers to rows */ m[nrl]=a-ncl; for(i=1,j=nrl+1;i *(float *)j) return 1; else return 0; } int comp_int(const void *i, const void *j) { return *(int *)i - *(int *)j; } ================================================ FILE: src/flute/memAlloc.h ================================================ /* -------------------------------------------------------------------------- Public domain memory allocation and de-allocation routine header file. Taken from Appendix B of: Numerical Recipes in C: The Art of Scientific Computing, Second Edition, Cambridge University Press, 1992 ----------------------------------------------------------------------------*/ #ifndef _MEMALLOC_H_ #define _MEMALLOC_H_ static float sqrarg; #define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg) static double dsqrarg; #define DSQR(a) ((dsqrarg=(a)) == 0.0 ? 0.0 : dsqrarg*dsqrarg) static double dmaxarg1,dmaxarg2; #define DMAX(a,b) (dmaxarg1=(a),dmaxarg2=(b),(dmaxarg1) > (dmaxarg2) ?\ (dmaxarg1) : (dmaxarg2)) static double dminarg1,dminarg2; #define DMIN(a,b) (dminarg1=(a),dminarg2=(b),(dminarg1) < (dminarg2) ?\ (dminarg1) : (dminarg2)) static float maxarg1,maxarg2; #define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\ (maxarg1) : (maxarg2)) static float minarg1,minarg2; #define FMIN(a,b) (minarg1=(a),minarg2=(b),(minarg1) < (minarg2) ?\ (minarg1) : (minarg2)) static long lmaxarg1,lmaxarg2; #define LMAX(a,b) (lmaxarg1=(a),lmaxarg2=(b),(lmaxarg1) > (lmaxarg2) ?\ (lmaxarg1) : (lmaxarg2)) static long lminarg1,lminarg2; #define LMIN(a,b) (lminarg1=(a),lminarg2=(b),(lminarg1) < (lminarg2) ?\ (lminarg1) : (lminarg2)) static int imaxarg1,imaxarg2; #define IMAX(a,b) (imaxarg1=(a),imaxarg2=(b),(imaxarg1) > (imaxarg2) ?\ (imaxarg1) : (imaxarg2)) static int iminarg1,iminarg2; #define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\ (iminarg1) : (iminarg2)) #define SIGN(a,b) ((b) >= 0.0 ? fflute_abs(a) : -fflute_abs(a)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) #define MIN(a,b) ((a)<(b) ? (a) : (b)) void runtimeError(char error_text[]); float *vector(long nl, long nh); int *ivector(long nl, long nh); unsigned char *cvector(long nl, long nh); unsigned long *lvector(long nl, long nh); double *dvector(long nl, long nh); float **matrix(long nrl, long nrh, long ncl, long nch); double **dmatrix(long nrl, long nrh, long ncl, long nch); int **imatrix(long nrl, long nrh, long ncl, long nch); char **cmatrix(long nrl, long nrh, long ncl, long nch); unsigned long **lmatrix(long nrl, long nrh, long ncl, long nch); float **submatrix(float **a, long oldrl, long oldrh, long oldcl, long oldch, long newrl, long newcl); float **convert_matrix(float *a, long nrl, long nrh, long ncl, long nch); float ***f3tensor(long nrl, long nrh, long ncl, long nch, long ndl, long ndh); unsigned long ***lmatrix3D(long nrl, long nrh, long ncl, long nch, long ndl, long ndh); int ***imatrix3D(int nrl, int nrh, int ncl, int nch, int ndl, int ndh); void free_vector(float *v, long nl, long nh); void free_ivector(int *v, long nl, long nh); void free_cvector(unsigned char *v, long nl, long nh); void free_lvector(unsigned long *v, long nl, long nh); void free_dvector(double *v, long nl, long nh); void free_matrix(float **m, long nrl, long nrh, long ncl, long nch); void free_dmatrix(double **m, long nrl, long nrh, long ncl, long nch); void free_imatrix(int **m, long nrl, long nrh, long ncl, long nch); void free_cmatrix(char **m, long nrl, long nrh, long ncl, long nch); void free_lmatrix(unsigned long **m, long nrl, long nrh, long ncl, long nch); void free_submatrix(float **b, long nrl, long nrh, long ncl, long nch); void free_convert_matrix(float **b, long nrl, long nrh, long ncl, long nch); void free_f3tensor(float ***t, long nrl, long nrh, long ncl, long nch, long ndl, long ndh); void free_lmatrix3D(unsigned long ***t, long nrl, long nrh, long ncl, long nch, long ndl, long ndh); void free_imatrix3D(int ***t, int nrl, int nrh, int ncl, int nch, int ndl, int ndh); int comp_float(const void *i, const void *j); int comp_int(const void *i, const void *j); #endif /* _MEMALLOC_H_ */ ================================================ FILE: src/flute/mst2.c ================================================ #include #include #include #include "global.h" #include "neighbors.h" #include "dist.h" #include "heap.h" #include "err.h" void mst2_package_init( long n ) { allocate_heap( n ); allocate_nn_arrays( n ); } /****************************************************************************/ /* */ void mst2_package_done() { deallocate_heap(); deallocate_nn_arrays(); } /****************************************************************************/ /* */ void mst2 ( long n, Point* pt, long* parent ) { long i, k, nn1; long d; long oct; long root = 0; extern nn_array* nn; // brute_force_nearest_neighbors( n, pt, nn ); dq_nearest_neighbors( n, pt, nn ); /* Binary heap implementation of Prim's algorithm. Runs in O(n*log(n)) time since at most 8n edges are considered */ heap_init( n ); heap_insert( root, 0 ); parent[root] = root; for( k = 0; k < n; k++ ) /* n points to be extracted from heap */ { i = heap_delete_min(); if (i<0) break; #ifdef DEBUG assert( i >= 0 ); #endif /* pt[i] entered the tree, update heap keys for its neighbors */ for( oct = 0; oct < 8; oct++ ) { nn1 = nn[i][oct]; if( nn1 >= 0 ) { d = dist( pt[i], pt[nn1] ); if( in_heap(nn1) && (d < heap_key(nn1)) ) { heap_decrease_key( nn1, d ); parent[nn1] = i; } else if( never_seen(nn1) ) { heap_insert( nn1, d ); parent[nn1] = i; } } } } } /****************************************************************************/ /****************************************************************************/ ================================================ FILE: src/flute/mst2.h ================================================ #ifndef _MST2_H_ #define _MST2_H_ #include "global.h" void mst2_package_init( long n ); void mst2_package_done(); void mst2( long n, Point* pt, long* parent ); #endif ================================================ FILE: src/flute/neighbors.c ================================================ #include #include #include #include "global.h" #include "err.h" #include "dist.h" long octant ( Point from, Point to ); static Point* _pt; /***************************************************************************/ /* For efficiency purposes auxiliary arrays are allocated as globals */ long max_arrays_size = 0; nn_array* nn = (nn_array*)NULL; Point* sheared = (Point*)NULL; long* sorted = (long*)NULL; long* aux = (long*)NULL; /***************************************************************************/ /* resize the auxiliary arrays to fit the specified number of points */ void allocate_nn_arrays( long n ) { if( max_arrays_size < n ) { nn = (nn_array*)realloc( (void*)nn, (size_t)n*sizeof(nn_array) ); sheared = (Point*)realloc( (void*)sheared, (size_t)n*sizeof(Point) ); sorted = (long*)realloc( (void*)sorted, (size_t)n*sizeof(long) ); aux = (long*)realloc( (void*)aux, (size_t)n*sizeof(long) ); if( !nn || !sheared || !sorted || !aux ) { err_exit( "Cannot allocate memory in allocate_nn_arrays!" ); } max_arrays_size = n; } } /***************************************************************************/ /* free memory used by auxiliary arrays */ void deallocate_nn_arrays() { max_arrays_size = 0; if( nn ) { free( (void*)nn ); nn = (nn_array*)NULL; } if( sheared ) { free( (void*)sheared ); sheared = (Point*)NULL; } if( sorted ) { free( (void*)sorted ); sorted = (long*)NULL; } if( aux ) { free( (void*)aux ); aux = (long*)NULL; } } /***************************************************************************/ /* comparison function for use in quicksort */ static int compare_x ( const void* i, const void* j ) { /* points with the same x must appear in increasing order of y */ if( sheared[*((long*)i)].x == sheared[*((long*)j)].x) { return sheared[*((long*)i)].y - sheared[*((long*)j)].y; } else { return sheared[*((long*)i)].x - sheared[*((long*)j)].x; } } /***************************************************************************/ /* Combine step of the Guibas-Stolfi divide-and-conquer NE nearest neighbor algorithm. For efficiency purposes SW nearest neighbors are computed at the same time. */ void ne_sw_combine ( long left, long mid, long right, Point* pt, long* sorted, long* aux, long oct, nn_array* nn ) { long i, j, k, y2; long i1; long i2; long best_i2; /* index of current best nearest-neighbor */ long best_dist; /* distance to best nearest-neighbor */ long d; #ifdef DEBUG assert( right > mid ); assert( mid > left ); #endif /* update north-east nearest neighbors accross the mid-line */ i1 = left; i2 = mid; y2 = pt[ sorted[i2] ].y; while( (i1 < mid) && (pt[ sorted[i1] ].y >= y2) ) { i1++; } if( i1 < mid ) { best_i2 = i2; best_dist = dist2( pt + sorted[i1], pt + sorted[best_i2] ); i2++; while( (i1 < mid) && (i2 < right) ) { if( pt[ sorted[i1] ].y < pt[ sorted[i2] ].y ) { d = dist2( pt + sorted[i1], pt + sorted[i2] ); if( d < best_dist ) { best_i2 = i2; best_dist = d; } i2++; } else { if( (nn[ sorted[i1] ][oct] == -1) || ( best_dist < dist2( pt + sorted[i1], pt + nn[ sorted[i1] ][oct]) ) ) { nn[ sorted[i1] ][oct] = sorted[best_i2]; } i1++; if( i1 < mid ) { best_dist = dist2( pt + sorted[i1], pt + sorted[best_i2] ); } } } while( i1 < mid ) { if( (nn[ sorted[i1] ][oct] == -1) || ( dist2( pt + sorted[i1], pt + sorted[best_i2] ) < dist2( pt + sorted[i1], pt + nn[ sorted[i1] ][oct]) ) ) { nn[ sorted[i1] ][oct] = sorted[best_i2]; } i1++; } } /* repeat for south-west nearest neighbors */ oct = (oct + 4) % 8; i1 = right - 1; i2 = mid - 1; y2 = pt[ sorted[i2] ].y; while( (i1 >= mid) && (pt[ sorted[i1] ].y <= y2) ) { i1--; } if( i1 >= mid ) { best_i2 = i2; best_dist = dist2( pt + sorted[i1], pt + sorted[best_i2] ); i2--; while( (i1 >= mid) && (i2 >= left) ) { if( pt[ sorted[i1] ].y > pt[ sorted[i2] ].y ) { d = dist2( pt + sorted[i1], pt + sorted[i2] ); if( d < best_dist ) { best_i2 = i2; best_dist = d; } i2--; } else { if( (nn[ sorted[i1] ][oct] == -1) || ( best_dist < dist2( pt + sorted[i1], pt + nn[ sorted[i1] ][oct]) ) ) { nn[ sorted[i1] ][oct] = sorted[best_i2]; } i1--; if( i1 >= mid ) { best_dist = dist2( pt + sorted[i1], pt + sorted[best_i2] ); } } } while( i1 >= mid ) { if( (nn[ sorted[i1] ][oct] == -1) || ( dist2( pt + sorted[i1], pt + sorted[best_i2] ) < dist2( pt + sorted[i1], pt + nn[ sorted[i1] ][oct]) ) ) { nn[ sorted[i1] ][oct] = sorted[best_i2]; } i1--; } } /* merge sorted[left..mid-1] with sorted[mid..right-1] by y-coordinate */ i = left; /* first unprocessed element in left list */ j = mid; /* first unprocessed element in right list */ k = left; /* first free available slot in output list */ while( (i < mid) && (j < right) ) { if( pt[ sorted[i] ].y >= pt[ sorted[j] ].y ) { aux[k++] = sorted[i++]; } else { aux[k++] = sorted[j++]; } } /* copy leftovers */ while( i < mid ) { aux[k++] = sorted[i++]; } while( j < right ) { aux[k++] = sorted[j++]; } /* now copy sorted points from 'aux' to 'sorted' */ for( i = left; i < right; i++ ) { sorted[i] = aux[i]; } #if 0 memcpy( (void*)(sorted+left), /* destination */ (void*)(aux+left), /* source */ (size_t)(right-left)*sizeof(long) /* number of bytes */ ); #endif } /***************************************************************************/ /* compute north-east and south-west nearest neighbors for points indexed by {sorted[left],...,sorted[right-1]} */ void ne_sw_nearest_neighbors ( long left, long right, Point* pt, long* sorted, long* aux, long oct, nn_array* nn ) { long mid; #ifdef DEBUG assert( right > left ); #endif if( right == left + 1 ) { nn[ sorted[left] ][oct] = nn[ sorted[left]][(oct+4) % 8] = -1; } else { mid = (left + right) / 2; ne_sw_nearest_neighbors( left, mid, pt, sorted, aux, oct, nn ); ne_sw_nearest_neighbors( mid, right, pt, sorted, aux, oct, nn ); ne_sw_combine( left, mid, right, pt, sorted, aux, oct, nn ); } } /***************************************************************************/ /* Guibas-Stolfi algorithm for computing nearest NE neighbors */ void dq_nearest_neighbors ( long n, Point* pt, nn_array* nn ) { long i, oct; void check_nn( long, Point*, nn_array* ); long shear[4][4] = { {1, -1, 0, 2}, {2, 0, -1, 1}, {1, 1, -2, 0}, {0, 2, -1, -1} }; _pt = pt; for( oct = 0; oct < 4; oct++ ) { for( i = 0; i < n; i++ ) { sheared[i].x = shear[oct][0]*pt[i].x + shear[oct][1]*pt[i].y; sheared[i].y = shear[oct][2]*pt[i].x + shear[oct][3]*pt[i].y; sorted[i] = i; } qsort( sorted, n, sizeof(long), compare_x ); ne_sw_nearest_neighbors( 0, n, sheared, sorted, aux, oct, nn ); } #ifdef DEBUG check_nn( n, pt, nn ); #endif } /***************************************************************************/ /***************************************************************************/ /* Brute-force nearest-neighbor computation for debugging purposes */ /***************************************************************************/ /* Half-open octants are numbered from 0 to 7 in anti-clockwise order starting from ( dx >= dy > 0 ). */ #define sgn(x) ( x>0 ? 1 : (x < 0 ? -1 : 0) ) long octant ( Point from, Point to ) { long dx = to.x - from.x; long dy = to.y - from.y; long sgn1 = sgn(dx)*sgn(dy); long sgn2 = sgn(dx+dy)*sgn(dx-dy); long oct = 0x0; if( (dy < 0) || ((dy==0) && (dx>0)) ) oct += 4; if( (sgn1 < 0) || (dy==0) ) oct += 2; if( (sgn1*sgn2 < 0) || (dy==0) || (dx==0) ) oct += 1; return oct; } /***************************************************************************/ /* O(n^2) algorithm for computing all nearest neighbors */ void brute_force_nearest_neighbors ( long n, Point* pt, nn_array* nn ) { long i, j, oct; long d; /* compute nearest neighbors by inspecting all pairs of points */ for( i = 0; i < n; i++ ) { for( oct = 0; oct < 8; oct++ ) { nn[i][oct] = -1; } } for( i = 0; i < n; i++ ) { for( j = i+1; j < n; j++ ) { d = dist(pt[i], pt[j]); oct = octant( pt[i], pt[j] ); if( ( nn[i][oct] == -1 ) || ( d < dist(pt[i], pt[ nn[i][oct] ]) ) ) { nn[i][oct] = j; } oct = (oct + 4) % 8; if( ( nn[j][oct] == -1 ) || ( d < dist(pt[j], pt[ nn[j][oct] ]) ) ) { nn[j][oct] = i; } } } } /***************************************************************************/ /* compare nearest neighbors against those computed by brute force */ void check_nn ( long n, Point* pt, nn_array* nn ) { long i, j, oct; nn_array* nn1; nn1 = (nn_array*)calloc( (size_t)n, (size_t)sizeof(nn_array) ); brute_force_nearest_neighbors( n, pt, nn1 ); for( i = 0; i < n; i++ ) { for( oct = 0; oct < 8; oct++ ) { if( nn[i][oct] == -1 ) { assert( nn1[i][oct] == -1 ); } else { assert( nn1[i][oct] != -1 ); if( octant(pt[i], pt[ nn[i][oct] ]) != oct ) { printf( "WRONG OCTANT!\noct=%ld\n", oct ); printf( "i=%ld, x=%ld, y=%ld\n", i, pt[i].x, pt[i].y ); j = nn[i][oct]; printf( "nn=%ld, x=%ld, y=%ld, dist = %ld\n", j, pt[j].x, pt[j].y, dist(pt[i], pt[j ]) ); } // assert( octant(pt[i], pt[ nn[i][oct] ]) == oct ); assert( octant(pt[i], pt[ nn1[i][oct] ]) == oct ); if( dist(pt[i], pt[ nn[i][oct] ]) != dist(pt[i], pt[ nn1[i][oct] ]) ) { printf( "NNs DON'T MATCH!\noct=%ld\n", oct ); printf( "i=%ld, x=%ld, y=%ld\n", i, pt[i].x, pt[i].y ); j = nn[i][oct]; printf( "nn=%ld, x=%ld, y=%ld, dist = %ld\n", j, pt[j].x, pt[j].y, dist(pt[i], pt[j ]) ); j = nn1[i][oct]; printf( "nn1=%ld, x=%ld, y=%ld, dist = %ld\n", j, pt[j].x, pt[j].y, dist(pt[i], pt[ j ]) ); } // assert( dist(pt[i], pt[ nn[i][oct] ]) == // dist(pt[i], pt[ nn1[i][oct] ]) ); } } } free( nn1 ); } /***************************************************************************/ /***************************************************************************/ ================================================ FILE: src/flute/neighbors.h ================================================ #include "global.h" void allocate_nn_arrays( long n ); void deallocate_nn_arrays(); void brute_force_nearest_neighbors ( long n, Point* pt, nn_array* nn ); void dq_nearest_neighbors ( long n, Point* pt, nn_array* nn ); ================================================ FILE: src/global.h ================================================ #pragma once #include "utils/utils.h" using utils::log; using utils::print; using utils::printflog; using utils::printlog; // STL libraries #include #include #include #include #include #include #include #include #include #include #include #include #include // Boost libraries #include #include #include #include #include #include #include #include namespace bg = boost::geometry; namespace bgi = boost::geometry::index; // Rsyn #include "rsyn/session/Session.h" #define RSYN_NO_GUI #include "rsyn/core/Rsyn.h" #include "rsyn/phy/PhysicalService.h" #include "rsyn/ispd18/RoutingGuide.h" #include "rsyn/io/reader/ISPD2018Reader.h" using boostPoint = bg::model::point; using boostBox = bg::model::box; using RTree = bgi::rtree, bgi::rstar<32>>; using RTrees = vector, bgi::rstar<32>>>; extern double LARGE_NUM; ================================================ FILE: src/gr_db/GCell.cpp ================================================ #include "GCell.h" namespace gr { void GCellGrid::init() { db::RsynService rsynService; rsynService.init(); const Rsyn::Session session; Rsyn::PhysicalDesign physicalDesign = static_cast(session.getService("rsyn.physical"))->getPhysicalDesign(); const DBU libDBU = physicalDesign.getDatabaseUnits(Rsyn::LIBRARY_DBU); grid.resize(2); grid[0].push_back(database.dieRegion[X].low); grid[1].push_back(database.dieRegion[Y].low); for (const Rsyn::PhysicalGCell &rsynGCell : physicalDesign.allPhysicalGCell()) { int location = rsynGCell.getLocation(); int step = rsynGCell.getStep(); int numStep = rsynGCell.getNumTracks(); Dimension direction = rsynGCell.getDirection() == Rsyn::PhysicalGCellDirection::VERTICAL ? X : Y; for (int i = 1; i < numStep; i++) grid[direction].push_back(location + step * i); } sort(grid[X].begin(), grid[X].end()); sort(grid[Y].begin(), grid[Y].end()); if (grid[X].back() != database.dieRegion[X].high) grid[X].push_back(database.dieRegion[X].high); if (grid[Y].back() != database.dieRegion[Y].high) grid[Y].push_back(database.dieRegion[Y].high); numTracks.resize(database.getLayerNum()); for (int i = 0; i < database.getLayerNum(); i++) { Dimension dir = database.getLayerDir(i); numTracks[i].resize(grid[dir].size() - 1); for (unsigned g = 0; g < grid[dir].size() - 1; g++) { utils::IntervalT coorIntvl(grid[dir][g], grid[dir][g + 1]); if (grid[dir][g] >= database.getLayer(i).lastTrackLoc()) { numTracks[i][g] = numTracks[i][g - 1]; } else { auto trackIntvl = database.rangeSearchTrack(i, coorIntvl); bool includeBnd = database.getLayer(i).tracks[trackIntvl.high].location == coorIntvl.high; numTracks[i][g] = (g == 0 ? 0 : numTracks[i][g - 1]) + trackIntvl.range() + 1 - includeBnd; } } } } GrBoxOnLayer GCellGrid::rangeSearchGCell(const db::BoxOnLayer &box) const { return GrBoxOnLayer(box.layerIdx, rangeSearchGCell(box[X], X), rangeSearchGCell(box[Y], Y)); } utils::IntervalT GCellGrid::rangeSearchGCell(const utils::IntervalT &intvl, Dimension dir) const { int lo_idx = lower_bound(grid[dir].begin(), grid[dir].end(), intvl.low) - grid[dir].begin(); if (grid[dir][lo_idx] > intvl.low) lo_idx--; int hi_idx = lower_bound(grid[dir].begin(), grid[dir].end(), intvl.high) - grid[dir].begin(); hi_idx--; return utils::IntervalT(lo_idx, hi_idx); } vector> GCellGrid::rangeSearchGCellEdge(const db::BoxOnLayer &box) const { Dimension dir = database.getLayerDir(box.layerIdx); auto grBox = rangeSearchGCell(box); vector> edges; edges.resize(grBox[dir].range() + 1); int jMin = max(grBox[1 - dir].low, 0); int jMax = min(grBox[1 - dir].high, getNumGrPoint(1 - dir) - 2); for (int i = grBox[dir].low; i < grBox[dir].high; i++) { for (int j = jMin; j <= jMax; j++) { int lx, ly, hx, hy; if (dir == X) { lx = hx = i; ly = j; hy = j + 1; } else { ly = hy = i; lx = j; hx = j + 1; } GrPoint p1(box.layerIdx, lx, ly), p2(box.layerIdx, hx, hy); edges[i].emplace_back(p1, p2); } } return edges; } utils::IntervalT GCellGrid::getTrackIntvl(const GrPoint &point) const { return getTrackIntvl(point.layerIdx, point[database.getLayerDir(point.layerIdx)]); } utils::IntervalT GCellGrid::getTrackIntvl(int layerIdx, int idx) const { return {idx == 0 ? 0 : numTracks[layerIdx][idx - 1], numTracks[layerIdx][idx] - 1}; } void GCellGrid::print() const { log() << "========= gcell grid info ============" << std::endl; printflog("#gcell=%d*%d=%d, #edge=%d/%d\n", getNumGrLine(X) - 1, getNumGrLine(Y) - 1, (getNumGrLine(X) - 1) * (getNumGrLine(Y) - 1), (getNumGrLine(X) - 1) * (getNumGrLine(Y) - 2), (getNumGrLine(X) - 2) * (getNumGrLine(Y) - 1)); for (int l = 0; l < database.getLayerNum(); l++) { int totTrackNum = 0; for (unsigned i = 0; i < numTracks[l].size(); i++) totTrackNum += getNumTracks(l, i); printlog(database.getLayer(l).name, ": avg #track=", totTrackNum / numTracks[l].size()); } } } // namespace gr ================================================ FILE: src/gr_db/GCell.h ================================================ #pragma once #include "db/RsynService.h" #include "global.h" #include "GrGeoPrimitive.h" #include "db/Database.h" namespace gr { class GCellGrid { public: void init(); int getNumTracks(int layerIdx, int idx) const { return getTrackIntvl(layerIdx, idx).range() + 1; } utils::IntervalT getTrackIntvl(const GrPoint &point) const; utils::IntervalT getCoorIntvl(const GrPoint &point, Dimension dir) const { return getCoorIntvl(point, (int)dir); } utils::IntervalT getCoorIntvl(const GrPoint &point, int dir) const { return {getCoor(point[dir], dir), getCoor(point[dir] + 1, dir)}; } DBU getDist(const GrPoint &point1, const GrPoint &point2) const { return getDist(point1, point2, X) + getDist(point1, point2, Y); } DBU getDist(const GrPoint &point1, const GrPoint &point2, Dimension dir) const { return getDist(point1, point2, (int)dir); } DBU getDist(const GrPoint &point1, const GrPoint &point2, int dir) const { return abs(getCoorIntvl(point1, dir).center() - getCoorIntvl(point2, dir).center()); } DBU getCoor(int idx, Dimension dir) const { return getCoor(idx, (int)dir); } DBU getCoor(int idx, int dir) const { return grid[dir][idx]; } int getNumGrPoint(Dimension dir) const { return getNumGrPoint((int)dir); } int getNumGrPoint(int dir) const { return grid[dir].size() - 1; } int getNumGrLine(Dimension dir) const { return getNumGrLine((int)dir); } int getNumGrLine(int dir) const { return grid[dir].size(); } int getNumGrEdge(int layerIdx) const { return getNumGrPoint(1 - database.getLayerDir(layerIdx)) - 1; } GrBoxOnLayer rangeSearchGCell(const db::BoxOnLayer &box) const; utils::IntervalT rangeSearchGCell(const utils::IntervalT &intvl, Dimension dir) const; vector> rangeSearchGCellEdge(const db::BoxOnLayer &box) const; void print() const; protected: vector> numTracks; vector> grid; utils::IntervalT getXIntvl(int idx) const { return {getX(idx), getX(idx + 1)}; } utils::IntervalT getYIntvl(int idx) const { return {getY(idx), getY(idx + 1)}; } DBU getX(int idx) const { return getCoor(idx, X); } DBU getY(int idx) const { return getCoor(idx, Y); } utils::IntervalT getTrackIntvl(int layerIdx, int idx) const; }; } // namespace gr ================================================ FILE: src/gr_db/GrDatabase.cpp ================================================ #include "GrDatabase.h" #include gr::GrDatabase grDatabase; namespace gr { void GrDatabase::init() { GrRouteGrid::init(); GrNetlist::init(*this); GrRouteGrid::print(); } void GrDatabase::writeGuides(std::string filename) { log() << "Writing guides to file..." << std::endl; std::stringstream ss; auto printGrGuides = [&](const vector& guides) { for (const auto& guide : guides) { ss << getCoor(guide[X].low, X) << " "; ss << getCoor(guide[Y].low, Y) << " "; ss << getCoor(guide[X].high + 1, X) << " "; ss << getCoor(guide[Y].high + 1, Y) << " "; ss << database.getLayer(guide.layerIdx).name << std::endl; } }; for (const auto& net : grDatabase.nets) { ss << net.getName() << std::endl; ss << "(" << std::endl; printGrGuides(net.wireRouteGuides); printGrGuides(net.viaRouteGuides); printGrGuides(net.patchRouteGuides); ss << ")" << std::endl; } std::ofstream fout(filename); fout << ss.str(); fout.close(); } } // namespace gr ================================================ FILE: src/gr_db/GrDatabase.h ================================================ #pragma once #include "db/Database.h" #include "GrRouteGrid.h" #include "global.h" #include "GrNet.h" namespace gr { class GrDatabase : public GrRouteGrid, public GrRouteGrid2D, public GrNetlist { public: void init(); void writeGuides(std::string filename); private: }; } // namespace gr extern gr::GrDatabase grDatabase; ================================================ FILE: src/gr_db/GrGeoPrimitive.cpp ================================================ #include "GrGeoPrimitive.h" namespace gr { // GrPoint bool GrPoint::operator==(const GrPoint& rhs) const { return layerIdx == rhs.layerIdx && x == rhs.x && y == rhs.y; } bool GrPoint::operator!=(const GrPoint& rhs) const { return layerIdx != rhs.layerIdx || x != rhs.x || y != rhs.y; } ostream& operator<<(ostream& os, const GrPoint& gp) { os << "gPt(l=" << gp.layerIdx << ", xIdx=" << gp.x << ", yIdx=" << gp.y << ")"; return os; } // PointOnLayer bool PointOnLayer::operator==(const PointOnLayer& rhs) const { return layerIdx == rhs.layerIdx && x == rhs.x && y == rhs.y; } bool PointOnLayer::operator!=(const PointOnLayer& rhs) const { return layerIdx != rhs.layerIdx || x != rhs.x || y != rhs.y; } ostream& operator<<(ostream& os, const PointOnLayer& gp) { os << "gPt(l=" << gp.layerIdx << ", xIdx=" << gp.x << ", yIdx=" << gp.y << ")"; return os; } // GrEdge ostream& operator<<(ostream& os, const GrEdge& edge) { os << "gEdge(" << edge.u << " " << edge.v << ")"; return os; } bool GrEdge::operator==(const GrEdge& rhs) const { return u == rhs.u && v == rhs.v; } // GrBoxOnLayer bool GrBoxOnLayer::operator==(const GrBoxOnLayer& rhs) const { return layerIdx == rhs.layerIdx && x == rhs.x && y == rhs.y; } ostream& operator<<(ostream& os, const GrBoxOnLayer& gb) { os << "gBox(l=" << gb.layerIdx << ", xIdx=" << gb.x << ", yIdx=" << gb.y << ")"; return os; } // slice polygons along sliceDir // sliceDir: 0 for x/vertical, 1 for y/horizontal void GrBoxOnLayer::sliceGrPolygons(vector& boxes, bool mergeAdj) { if (boxes.size() <= 1) return; auto dir = database.getLayerDir(boxes[0].layerIdx); vector locs; for (const auto& box : boxes) { locs.push_back(box[dir].low); locs.push_back(box[dir].high); } sort(locs.begin(), locs.end()); locs.erase(unique(locs.begin(), locs.end()), locs.end()); // slice each box vector slicedBoxes; for (const auto& box : boxes) { GrBoxOnLayer slicedBox = box; auto itLoc = lower_bound(locs.begin(), locs.end(), box[dir].low); auto itEnd = upper_bound(itLoc, locs.end(), box[dir].high); slicedBox[dir].Set(*itLoc); slicedBoxes.push_back(slicedBox); // front boundary while ((itLoc + 1) != itEnd) { int left = *itLoc, right = *(itLoc + 1); if ((right - left) > 1) { slicedBox[dir].Set(left + 1, right - 1); slicedBoxes.push_back(slicedBox); // middle } slicedBox[dir].Set(right); slicedBoxes.push_back(slicedBox); // back boundary ++itLoc; } } boxes = move(slicedBoxes); // merge overlaped boxes over crossPoints utils::MergeRects(boxes, 1 - dir); // stitch boxes over tracks utils::MergeRects(boxes, dir); if (mergeAdj) { // merge box on adjacent gridline std::sort(boxes.begin(), boxes.end(), [&](const BoxT& lhs, const BoxT& rhs) { return lhs[dir].low < rhs[dir].low || (lhs[dir].low == rhs[dir].low && lhs[1 - dir].low < rhs[1 - dir].low); }); std::vector mergedBoxes; mergedBoxes.push_back(boxes.front()); for (int i = 1; i < boxes.size(); ++i) { auto& lastBox = mergedBoxes.back(); auto& slicedBox = boxes[i]; if (abs(slicedBox[dir].high - lastBox[dir].low) <= 1 && slicedBox[1 - dir] == lastBox[1 - dir]) { lastBox[dir] = lastBox[dir].UnionWith(slicedBox[dir]); } else { // neither misaligned not seperated mergedBoxes.push_back(slicedBox); } } boxes = move(mergedBoxes); } } } // namespace gr ================================================ FILE: src/gr_db/GrGeoPrimitive.h ================================================ #pragma once #include "global.h" #include "db/Database.h" namespace gr { // GrPoint class GrPoint : public utils::PointT { public: int layerIdx; GrPoint(int layerIndex = -1, int xx = -1, int yy = -1) : PointT(xx, yy), layerIdx(layerIndex) {} int getPrefIdx() const { return database.getLayerDir(layerIdx) == X ? x : y; } bool operator==(const GrPoint& rhs) const; bool operator!=(const GrPoint& rhs) const; friend ostream& operator<<(ostream& os, const GrPoint& gp); }; // PointOnLayer class PointOnLayer : public utils::PointT { public: int layerIdx; PointOnLayer(int layerIndex = -1, int xx = -1, int yy = -1) : PointT(xx, yy), layerIdx(layerIndex) {} PointOnLayer(const GrPoint& point) : PointT(point[X], point[Y]), layerIdx(point.layerIdx) {} bool operator==(const PointOnLayer& rhs) const; bool operator!=(const PointOnLayer& rhs) const; friend ostream& operator<<(ostream& os, const PointOnLayer& gp); }; // GrEdge class GrEdge { public: GrPoint u, v; GrEdge(const GrPoint& nodeU, const GrPoint& nodeV) { // ensure u is always smaller than v if (nodeU[0] <= nodeV[0] && nodeU[1] <= nodeV[1]) { u = nodeU; v = nodeV; } else { u = nodeV; v = nodeU; } } GrEdge(int layerIdx, int g, int cp) { auto dir = database.getLayerDir(layerIdx); if (dir == X) { u = GrPoint(layerIdx, g, cp); v = GrPoint(layerIdx, g, cp + 1); } else { u = GrPoint(layerIdx, cp, g); v = GrPoint(layerIdx, cp + 1, g); } } GrEdge(int layerIdx, int g, int lo_cp, int hi_cp) { auto dir = database.getLayerDir(layerIdx); if (dir == X) { u = GrPoint(layerIdx, g, lo_cp); v = GrPoint(layerIdx, g, hi_cp); } else { u = GrPoint(layerIdx, lo_cp, g); v = GrPoint(layerIdx, hi_cp, g); } } int getLayerIdx() const { if (isVia()) return -1; else return u.layerIdx; } int getCutLayerIdx() const { if (isVia()) return lowerGrPoint().layerIdx; else return -1; } DBU getGrLen() const { DBU len = 0; if (!isVia()) len = v[X] - u[X] + v[Y] - u[Y]; return len; } // two types of GridEdge: 1. via, 2. segment bool isVia() const { return u.layerIdx != v.layerIdx; } const GrPoint& lowerGrPoint() const { return u.layerIdx <= v.layerIdx ? u : v; } const GrPoint& upperGrPoint() const { return u.layerIdx > v.layerIdx ? u : v; } bool operator==(const GrEdge& rhs) const; friend ostream& operator<<(ostream& os, const GrEdge& edge); }; // GrBoxOnLayer class GrBoxOnLayer : public utils::BoxT { public: int layerIdx; GrBoxOnLayer() : layerIdx(-1) {} // default to be invalid GrBoxOnLayer(int layerIndex, const utils::IntervalT& xx, const utils::IntervalT& yy) : layerIdx(layerIndex), utils::BoxT(xx, yy) {} bool includePoint(const GrPoint& point, bool ignoreLayer = false) const { return (ignoreLayer || layerIdx == point.layerIdx) && x.Contain(point[X]) && y.Contain(point[Y]); } // slice polygons along pref direction // assume boxes are on the same layer static void sliceGrPolygons(vector& boxes, bool mergeAdj); bool operator==(const GrBoxOnLayer& rhs) const; friend ostream& operator<<(ostream& os, const GrBoxOnLayer& gb); }; } // namespace gr namespace std { // hash function for GrPoint template <> struct hash { std::size_t operator()(const gr::GrPoint& gp) const { return (std::hash()(gp.layerIdx) ^ std::hash()(gp.x) ^ std::hash()(gp.y)); } }; // hash for gr::GrEdge template <> struct hash { std::size_t operator()(const gr::GrEdge edge) const { // return 0; return std::hash()(edge.u.layerIdx) ^ std::hash()(edge.u.x) ^ std::hash()(edge.u.y) ^ std::hash()(edge.v.x) ^ std::hash()(edge.v.y); } }; // hash function for PointOnLayer template <> struct hash { std::size_t operator()(const gr::PointOnLayer& point) const { return (std::hash()(point.layerIdx) ^ std::hash()(point.x) ^ std::hash()(point.y)); } }; } // namespace std ================================================ FILE: src/gr_db/GrNet.cpp ================================================ #include "GrNet.h" #include "GrDatabase.h" namespace gr { void GrNet::init(const GCellGrid& gcellGrid) { initPinAccessBoxes(gcellGrid); // get overlap points for (int p1 = 0; p1 < numOfPins(); p1++) { for (int p2 = p1 + 1; p2 < numOfPins(); p2++) { for (const auto& point1 : pinAccessBoxes[p1]) { for (const auto& point2 : pinAccessBoxes[p2]) { if (point1 == point2) ovlpPoints.insert(point1); } } } } // judge if it is one pin net std::unordered_map pointSet; for (const auto& pin : pinAccessBoxes) { for (const auto& point : pin) pointSet[point]++; } for (const auto& pair : pointSet) { if (pair.second == numOfPins()) { isOnePin = true; break; } } for (const auto& pinBox : pinAccessBoxes) { for (const auto& grpnt : pinBox) { boundingBox[X].Update(grpnt[X]); boundingBox[Y].Update(grpnt[Y]); } } } // merged pins with same coor vector> GrNet::getMergedPinAccessBoxes( const std::function& pointHash) const { vector> mergedPinAccessBoxes; vector> hashedPinAccessBoxes(numOfPins()); for (int p = 0; p < numOfPins(); p++) for (const auto& point : pinAccessBoxes[p]) hashedPinAccessBoxes[p].push_back(pointHash(point)); vector> pinConn(numOfPins()); for (int p1 = 0; p1 < numOfPins(); p1++) { for (int p2 = p1 + 1; p2 < numOfPins(); p2++) { bool overlap = false; for (const auto& point1 : hashedPinAccessBoxes[p1]) { if (overlap) break; for (const auto& point2 : hashedPinAccessBoxes[p2]) { if (overlap) break; if (point1 == point2) { pinConn[p1].push_back(p2); pinConn[p2].push_back(p1); overlap = true; } } } } } vector visited(numOfPins(), false); for (int p = 0; p < numOfPins(); p++) { if (visited[p]) continue; std::queue q; q.push(p); vector points; while (!q.empty()) { int node = q.front(); q.pop(); copy(hashedPinAccessBoxes[node].begin(), hashedPinAccessBoxes[node].end(), std::back_inserter(points)); visited[node] = true; for (auto child : pinConn[node]) if (!visited[child]) q.push(child); } mergedPinAccessBoxes.resize(mergedPinAccessBoxes.size() + 1); mergedPinAccessBoxes.back() = move(points); } for (auto& points : mergedPinAccessBoxes) { std::sort(points.begin(), points.end(), [&](const PointOnLayer& lhs, const PointOnLayer& rhs) { if (lhs.layerIdx != rhs.layerIdx) { return lhs.layerIdx < rhs.layerIdx; } else { if (lhs[X] != rhs[X]) { return lhs[X] < rhs[X]; } else { return lhs[Y] < rhs[Y]; } } }); points.erase(std::unique(points.begin(), points.end()), points.end()); } return mergedPinAccessBoxes; } void GrNet::initPinAccessBoxes(const GCellGrid& gcellGrid) { // transform coor to grPoint, construct pinAccessBoxes pinAccessBoxes.resize(numOfPins()); for (int i = 0; i < numOfPins(); i++) { const auto& boxes = dbNet.pinAccessBoxes[i]; std::unordered_set pointSet; DBU smallestVio = std::numeric_limits::max(); vector smallestBoxes; for (const auto& box : boxes) { int vio = database.getOvlpFixedMetalArea(box, dbNet.idx); if (vio <= smallestVio) { if (vio < smallestVio) smallestBoxes.clear(); smallestVio = vio; smallestBoxes.push_back(&box); } if (vio == 0) { auto grBox = gcellGrid.rangeSearchGCell(box); for (int x = grBox[X].low; x <= grBox[X].high; x++) for (int y = grBox[Y].low; y <= grBox[Y].high; y++) pointSet.emplace(box.layerIdx, x, y); } } // all have vio, add those with smallest vio if (pointSet.empty()) { for (auto box : smallestBoxes) { auto grBox = gcellGrid.rangeSearchGCell(*box); for (int x = grBox[X].low; x <= grBox[X].high; x++) for (int y = grBox[Y].low; y <= grBox[Y].high; y++) pointSet.emplace(box->layerIdx, x, y); } } for (auto& point : pointSet) pinAccessBoxes[i].push_back(point); } } void GrNetlist::init(const GCellGrid& gcellGrid) { for (int i = 0, sz = database.nets.size(); i < sz; i++) nets.emplace_back(i); runJobsMT(database.nets.size(), [&](int i) { nets[i].init(gcellGrid); }); } void GrNet::postOrderVisitGridTopo(const std::function)>& visit) const { for (const std::shared_ptr& tree : gridTopo) { GrSteiner::postOrder(tree, visit); } } void GrNet::preOrderVisitGridTopo(const std::function)>& visit) const { for (const std::shared_ptr& tree : gridTopo) { GrSteiner::preOrder(tree, visit); } } DBU GrNet::getWirelength() const { DBU wirelength = 0; postOrderVisitGridTopo([&](std::shared_ptr node) { auto parent = node; for (auto child : parent->children) { if (parent->layerIdx == child->layerIdx) wirelength += grDatabase.getDist(*parent, *child); } }); return wirelength; } } // namespace gr ================================================ FILE: src/gr_db/GrNet.h ================================================ #pragma once #include "db/Database.h" #include "GrGeoPrimitive.h" #include "GCell.h" #include "GridTopo.h" namespace gr { class GrNet { public: db::Net& dbNet; vector> pinAccessBoxes; std::unordered_set ovlpPoints; GrBoxOnLayer boundingBox; vector> gridTopo; vector wireRouteGuides; vector viaRouteGuides; vector patchRouteGuides; GrNet(int i) : dbNet(database.nets[i]) {} void init(const GCellGrid& gcellGrid); unsigned numOfPins() const { return dbNet.numOfPins(); } const std::string& getName() const { return dbNet.getName(); } void postOrderVisitGridTopo(const std::function)>& visit) const; void preOrderVisitGridTopo(const std::function)>& visit) const; DBU getWirelength() const; vector> getMergedPinAccessBoxes(const std::function& pointHash) const; bool needToRoute() { return !isOnePin; } private: void initPinAccessBoxes(const GCellGrid& gcellGrid); bool isOnePin = false; }; class GrNetlist { public: vector nets; void init(const GCellGrid& gcellGrid); }; } // namespace gr ================================================ FILE: src/gr_db/GrRouteGrid.cpp ================================================ #include "GrRouteGrid.h" #include "db/Database.h" #include "GrDatabase.h" #include "db/Setting.h" namespace gr { void GrRouteGrid::init() { int numLayers = database.getLayerNum(); routedWireMap.resize(numLayers); fixedMetalMap.resize(numLayers); histWireUsageMap.resize(numLayers); routedViaMap.resize(numLayers); GCellGrid::init(); for (int l = 0; l < numLayers; l++) { auto dir = database.getLayerDir(l); routedWireMap[l].resize(getNumGrPoint(dir), vector(getNumGrEdge(l))); fixedMetalMap[l].resize(getNumGrPoint(dir), vector>(getNumGrEdge(l))); histWireUsageMap[l].resize(getNumGrPoint(dir), vector(getNumGrEdge(l), 0)); routedViaMap[l].resize(getNumGrPoint(X), vector(getNumGrPoint(Y))); } markFixedMetals(); } void GrRouteGrid::clear() { routedWireMap.clear(); fixedMetalMap.clear(); histWireUsageMap.clear(); routedViaMap.clear(); } void GrRouteGrid::markFixed(int layerIdx, int gridline, int cp, int num_track, DBU avg_length) { fixedMetalMap[layerIdx][gridline][cp] = std::make_pair(num_track, avg_length); } void GrRouteGrid::useWire(int layerIdx, int gridline, int cp, double usage) { routedWireMap[layerIdx][gridline][cp] += usage; } void GrRouteGrid::useVia(int layerIdx, int x, int y, double usage) { routedViaMap[layerIdx][x][y] += usage; } void GrRouteGrid::useWire(const GrBoxOnLayer& box) { int layerIdx = box.layerIdx; auto dir = database.getLayerDir(layerIdx); double usage = 1.0 / (box[dir].range() + 1); for (int gridline = box[dir].low; gridline <= box[dir].high; gridline++) for (int cp = box[1 - dir].low; cp < box[1 - dir].high; cp++) useWire(layerIdx, gridline, cp, usage); } void GrRouteGrid::useVia(const GrBoxOnLayer& box) { double usage = 1.0 / ((box[X].range() + 1) * (box[Y].range() + 1)); for (int x = box[X].low; x <= box[X].high; x++) for (int y = box[Y].low; y <= box[Y].high; y++) useVia(box.layerIdx, x, y, usage); } void GrRouteGrid::useNet(const GrNet& net) { for (const auto& guide : net.wireRouteGuides) useWire(guide); const auto& viaGuides = net.viaRouteGuides; for (int g1 = 0; g1 < viaGuides.size(); g1++) { for (int g2 = g1 + 1; g2 < viaGuides.size(); g2++) { if (abs(viaGuides[g1].layerIdx - viaGuides[g2].layerIdx) != 1) continue; auto xIntvl = viaGuides[g1][X].IntersectWith(viaGuides[g2][X]); auto yIntvl = viaGuides[g1][Y].IntersectWith(viaGuides[g2][Y]); if (xIntvl.IsValid() && yIntvl.IsValid()) useVia({min(viaGuides[g1].layerIdx, viaGuides[g2].layerIdx), xIntvl, yIntvl}); } } } // Note: may accumulate the size of each recorder void GrRouteGrid::removeWire(const GrBoxOnLayer& box) { int layerIdx = box.layerIdx; auto dir = database.getLayerDir(layerIdx); double usage = 1.0 / (box[dir].range() + 1); for (int gridline = box[dir].low; gridline <= box[dir].high; gridline++) for (int cp = box[1 - dir].low; cp < box[1 - dir].high; cp++) routedWireMap[layerIdx][gridline][cp] -= usage; } void GrRouteGrid::removeVia(const GrBoxOnLayer& box) { double usage = 1.0 / ((box[X].range() + 1) * (box[Y].range() + 1)); for (int x = box[X].low; x <= box[X].high; x++) for (int y = box[Y].low; y <= box[Y].high; y++) routedViaMap[box.layerIdx][x][y] -= usage; // for (auto& pair : routedViaMap[box.layerIdx][x][y]) // if (pair.first == netIdx) pair.second = 0; } void GrRouteGrid::removeNet(GrNet& net) { for (const auto& guide : net.wireRouteGuides) removeWire(guide); const auto& viaGuides = net.viaRouteGuides; for (int g1 = 0; g1 < viaGuides.size(); g1++) { for (int g2 = g1 + 1; g2 < viaGuides.size(); g2++) { if (abs(viaGuides[g1].layerIdx - viaGuides[g2].layerIdx) != 1) continue; auto xIntvl = viaGuides[g1][X].IntersectWith(viaGuides[g2][X]); auto yIntvl = viaGuides[g1][Y].IntersectWith(viaGuides[g2][Y]); if (xIntvl.IsValid() && yIntvl.IsValid()) removeVia({min(viaGuides[g1].layerIdx, viaGuides[g2].layerIdx), xIntvl, yIntvl}); } } net.wireRouteGuides.clear(); net.viaRouteGuides.clear(); } double GrRouteGrid::getWireCapacity(const GrEdge& edge) const { if (abs(edge.u[X] - edge.v[X]) > 1 || abs(edge.u[Y] - edge.v[Y]) > 1) printlog("ERROR: in GrRouteGrid::getWireCapacity, edge len > 1"); int layerIdx = edge.getLayerIdx(); return getNumTracks(layerIdx, edge.u[database.getLayerDir(layerIdx)]) * wireCapDiscount; } double GrRouteGrid::getInCellArea(const GrPoint& point) const { int layerIdx = point.layerIdx; auto dir = database.getLayerDir(layerIdx); return getNumTracks(layerIdx, point[dir]); } double GrRouteGrid::getFixedUsage(const GrEdge& edge) const { // get num of tracks blocked by fixed metal if (edge.getGrLen() != 1) printlog("Error"); auto dir = database.getLayerDir(edge.getLayerIdx()); return getFixedUsage(edge.getLayerIdx(), edge.u[dir], edge.u[1 - dir]); } DBU GrRouteGrid::getFixedLength(const GrEdge& edge) const { // get avg length of the tracks blocked by fixed metal if (edge.getGrLen() != 1) printlog("Error"); auto dir = database.getLayerDir(edge.getLayerIdx()); return fixedMetalMap[edge.getLayerIdx()][edge.u[dir]][edge.u[1 - dir]].second; } double GrRouteGrid::getWireUsage(const GrEdge& edge) const { if (edge.getGrLen() != 1) printlog("Error"); auto dir = database.getLayerDir(edge.getLayerIdx()); return getWireUsage(edge.getLayerIdx(), edge.u[dir], edge.u[1 - dir]); } double GrRouteGrid::getViaUsage(const GrPoint& via) const { return getViaUsage(via.layerIdx, via[X], via[Y]); } double GrRouteGrid::getCellUsage(const GrPoint& point) const { return getCellUsage(point.layerIdx, point.x, point.y); } double GrRouteGrid::getInCellUsedArea(const GrPoint& point) const { // note: the area defined here = # of used tracks * avg_used_length (total used length of tracks in the gcell) // todo: consider boundary effect double used_area = 0; int layerIdx = point.layerIdx; auto dir = database.getLayerDir(layerIdx); int low_x = point.x - (dir == Y); int low_y = point.y - (dir == X); auto low_edge = GrEdge({layerIdx, low_x, low_y}, point); if (low_x >= 0 && low_y >= 0) { used_area += getFixedUsage(low_edge) + getWireUsage(low_edge); } int high_x = point.x + (dir == Y); int high_y = point.y + (dir == X); auto high_edge = GrEdge(point, {layerIdx, high_x, high_y}); if (high_x < getNumGrPoint(X) && high_y < getNumGrPoint(Y)) { used_area += getFixedUsage(high_edge) + getWireUsage(high_edge); } return used_area / 2; } double GrRouteGrid::getFixedUsedArea(const GrEdge& edge) const { // a little different to the area of a point, this is the area of an edge, which is half of 2 gcell's area combined return getFixedUsage(edge) * getFixedLength(edge); } double GrRouteGrid::getInCellViaNum(const GrPoint& point) const { // get the num of vias passing through the gcell double num = 0; for (int side = -1; side <= 0; side++) { // a cell is used by both the via from lower layer and that from higher layer // side = -1, from lower layer to current layer; side = 0 from current layer to upper layer auto via_point = GrPoint({point.layerIdx + side, point.x, point.y}); if (via_point.layerIdx < 0 || via_point.layerIdx >= database.getLayerNum() - 1) continue; num += getViaUsage(via_point); } return num; } // double GrRouteGrid::getUnitViaArea(const GrPoint& point, int side) const { // // side = -1, from lower layer to current layer; side = 0 from current layer to upper layer // auto& viaType = database.getCutLayer(point.layerIdx).defaultViaType(); // auto viaBox = (side == 1 ? viaType.top : viaType.bot); // // auto dir = database.getLayerDir(point.layerIdx); // int nBlockedTrack = viaBox[dir].range() * grDatabase.getNumTracks(point.layerIdx, point[dir]) / // grDatabase.getCoorIntvl(point, dir).range() + 1; return viaBox[1 - dir].range() * nBlockedTrack; // } double GrRouteGrid::getFixedUsage(int layerIdx, int gridline, int cp) const { // get num of tracks blocked by fixed metal return fixedMetalMap[layerIdx][gridline][cp].first; } double GrRouteGrid::getWireUsage(int layerIdx, int gridline, int cp) const { return routedWireMap[layerIdx][gridline][cp]; } double GrRouteGrid::getViaUsage(int layerIdx, int x, int y) const { return routedViaMap[layerIdx][x][y]; } double GrRouteGrid::GrRouteGrid::getCellUsage(int layerIdx, int x, int y) const { auto layerDir = database.getLayerDir(layerIdx); double totalRsrc = grDatabase.getNumTracks(layerIdx, layerDir == X ? x : y); double cellUsage = 0; int low_x = x - (layerDir == Y); int low_y = y - (layerDir == X); if (low_x >= 0 && low_y >= 0) { auto low_edge = gr::GrEdge({layerIdx, low_x, low_y}, {layerIdx, x, y}); cellUsage += grDatabase.getFixedUsage(low_edge) + grDatabase.getWireUsage(low_edge); } int high_x = x + (layerDir == Y); int high_y = y + (layerDir == X); if (high_x < grDatabase.getNumGrPoint(X) && high_y < grDatabase.getNumGrPoint(Y)) { auto high_edge = gr::GrEdge({layerIdx, x, y}, {layerIdx, high_x, high_y}); cellUsage += grDatabase.getFixedUsage(high_edge) + grDatabase.getWireUsage(high_edge); } cellUsage /= 2; cellUsage += sqrt(grDatabase.getInCellViaNum({layerIdx, x, y})) * db::setting.unitSqrtViaUsage; return totalRsrc - cellUsage; } void GrRouteGrid::print() const { GCellGrid::print(); } void GrRouteGrid::printAllUsageAndVio() const { const int width = 10; auto wlVia = printAllUsage(); double numShort = printAllVio(); log() << "--- Estimated Scores ---" << std::endl; vector items = {"wirelength", "# vias", "short"}; vector metrics = {wlVia.first, wlVia.second, numShort}; vector weights = {db::setting.weightWirelength, db::setting.weightViaNum, db::setting.weightShortArea}; double totalScore = 0; for (int i = 0; i < items.size(); ++i) { totalScore += metrics[i] * weights[i]; } log() << std::setw(width) << "item" << " | " << std::setw(width + 2) << "metric" << " | " << std::setw(width) << "weight" << " | " << std::setw(width + 2) << "score" << " | " << std::setw(width) << "\%" << std::endl; for (int i = 0; i < items.size(); ++i) { double score = metrics[i] * weights[i]; log() << std::setw(width) << items[i] << " | " << std::setw(width + 2) << metrics[i] << " | " << std::setw(width) << weights[i] << " | " << std::setw(width + 2) << score << " | " << std::setw(width) << score / totalScore << std::endl; } log() << "total score = " << totalScore << std::endl; } double GrRouteGrid::getAllWireUsage(const vector& buckets, vector& wireUsageGrid, vector& wireUsageLength) const { double wirelength = 0; wireUsageGrid.assign(buckets.size(), 0); wireUsageLength.assign(buckets.size(), 0); for (int layerIdx = 0; layerIdx < database.getLayerNum(); ++layerIdx) { Dimension dir = database.getLayerDir(layerIdx); for (int gridline = 0; gridline < getNumGrPoint(dir); gridline++) { for (int cp = 0; cp < getNumGrEdge(layerIdx); cp++) { double numWire = getWireUsage(layerIdx, gridline, cp); double usage = (numWire + getFixedUsage({layerIdx, gridline, cp})) / getNumTracks(layerIdx, gridline); DBU dist = (getCoor(cp + 2, 1 - dir) - getCoor(cp, 1 - dir)) / 2; int bucketIdx = buckets.size() - 1; while (buckets[bucketIdx] >= usage) --bucketIdx; bucketIdx = max(bucketIdx, 0); wireUsageGrid[bucketIdx]++; wireUsageLength[bucketIdx] += dist; wirelength += dist * numWire; } } } return wirelength; } double GrRouteGrid::getWirelength() const { double wirelength = 0; for (auto& net : grDatabase.nets) wirelength += net.getWirelength(); return wirelength; } void GrRouteGrid::getAllInCellUsage(const vector& buckets, vector& inCellUsage) const { inCellUsage.assign(buckets.size(), 0); for (int layerIdx = 0; layerIdx < database.getLayerNum(); ++layerIdx) { for (int x = 0; x < getNumGrPoint(X); x++) { for (int y = 0; y < getNumGrPoint(Y); y++) { double usage = getInCellUsedArea({layerIdx, x, y}) / getInCellArea({layerIdx, x, y}); int bucketIdx = buckets.size() - 1; while (buckets[bucketIdx] >= usage) --bucketIdx; bucketIdx = max(bucketIdx, 0); inCellUsage[bucketIdx]++; } } } } double GrRouteGrid::getTotViaNum() const { double viaNum = 0; for (int layerIdx = 0; (layerIdx + 1) < database.getLayerNum(); ++layerIdx) { for (int x = 0; x < getNumGrPoint(X); x++) { for (int y = 0; y < getNumGrPoint(Y); y++) { viaNum += getViaUsage(layerIdx, x, y); } } } return viaNum; } std::pair GrRouteGrid::printAllUsage() const { const int width = 10; vector buckets = { -1, 0, 0.3, 0.6, 0.8, 0.9, 1, 1.1, 1.3, 1.5, 2, 3}; // the i-th bucket: buckets[i] <= x < buckets[i+1] auto getRangeStr = [](const vector& buckets, int i) { std::string range; if (i == 0) { range = " " + std::to_string_with_precision(0.0, 2) + " "; } else if ((i + 1) < buckets.size()) { range = "(" + std::to_string_with_precision(buckets[i], 2) + "~" + std::to_string_with_precision(buckets[i + 1], 2) + "]"; } else { range = "(" + std::to_string_with_precision(buckets[i], 2) + "~inf" + ")"; } return range; }; // Wire vector routedWireUsageGrid; vector routedWireUsageLength; double wireLength = getAllWireUsage(buckets, routedWireUsageGrid, routedWireUsageLength); log() << "--- Wire Usage ---" << std::endl; log() << std::setw(width) << "usage" << " | " << std::setw(width) << " grid " << " | " << std::setw(width) << " length " << std::endl; for (int i = 0; i < buckets.size(); ++i) { if (routedWireUsageGrid[i] == 0 && routedWireUsageLength[i] == 0) continue; log() << std::setw(width) << getRangeStr(buckets, i) << " | " << std::setw(width) << routedWireUsageGrid[i] << " | " << std::setw(width) << routedWireUsageLength[i] / double(database.getLayer(1).pitch) << std::endl; } wireLength /= double(database.getLayer(1).pitch); // in-Cell vector routedViaUsage; getAllInCellUsage(buckets, routedViaUsage); log() << "--- in-Cell Usage ---" << std::endl; log() << std::setw(width) << "usage" << " | " << std::setw(width) << "routed" << std::endl; for (int i = 0; i < buckets.size(); ++i) { if (routedViaUsage[i] == 0) continue; log() << std::setw(width) << getRangeStr(buckets, i) << " | " << std::setw(width) << routedViaUsage[i] << std::endl; } double viaNum = getTotViaNum(); return {wireLength, viaNum}; } double GrRouteGrid::printAllVio() const { const int width = 10; auto sumVec = [](const vector& vec) { int sum = 0; for (int val : vec) { sum += val; } return sum; }; // Wire violations vector shortLen(database.getLayerNum(), 0.0); for (int layerIdx = 0; layerIdx < database.getLayerNum(); ++layerIdx) { Dimension dir = database.getLayerDir(layerIdx); for (int gridline = 0; gridline < getNumGrPoint(dir); gridline++) { for (int cp = 0; cp < getNumGrEdge(layerIdx); cp++) { double numWire = getWireUsage(layerIdx, gridline, cp) + getFixedUsage(layerIdx, gridline, cp); DBU dist = (getCoor(cp + 2, 1 - dir) - getCoor(cp, 1 - dir)) / 2; double overflow = max(0.0, numWire - getNumTracks(layerIdx, gridline)); shortLen[layerIdx] += overflow * dist; } } } log() << "--- Wire-Wire Short Vios ---" << std::endl; log() << std::setw(width) << "usage" << " | " << std::setw(width * 2 + 3) << " short area " << std::endl; log() << std::setw(width) << "layer" << " | " << std::setw(width) << "wire-wire" << std::endl; double routedShortArea = 0; for (int i = 0; i < database.getLayerNum(); ++i) { if (shortLen[i] == 0) continue; const auto& layer = database.getLayer(i); double routedArea = double(shortLen[i]) * layer.width / database.getLayer(1).pitch / database.getLayer(1).pitch; log() << std::setw(width) << database.getLayer(i).name << " | " << std::setw(width) << routedArea << std::endl; routedShortArea += routedArea; } log() << std::setw(width) << "SumW" << " | " << std::setw(width) << routedShortArea << std::endl; // Via violations vector shortNum(database.getLayerNum() - 1, 0.0); for (int layerIdx = 0; layerIdx < database.getLayerNum() - 1; ++layerIdx) { for (int x = 0; x < getNumGrPoint(X); x++) { for (int y = 0; y < getNumGrPoint(Y); y++) { double overflow = getNumVio(GrPoint({layerIdx, x, y}), 0); shortNum[layerIdx] += overflow; } } } log() << "--- Via-Via Short Vios ---" << std::endl; log() << std::setw(width) << "usage" << " | " << std::setw(width * 2 + 3) << " #short " << std::endl; log() << std::setw(width) << "layer" << " | " << std::setw(width) << "via-via" << std::endl; double routedShortViaNum = 0; for (int i = 0; i < database.getLayerNum() - 1; ++i) { if (shortNum[i] == 0) continue; log() << std::setw(width) << database.getCutLayer(i).name << " | " << std::setw(width) << shortNum[i] << std::endl; routedShortViaNum += shortNum[i]; } log() << std::setw(width) << "SumW" << " | " << std::setw(width) << routedShortViaNum << std::endl; routedShortArea += routedShortViaNum; return routedShortArea; } void GrRouteGrid::markFixedMetals() { for (int l = 0; l < database.getLayerNum(); l++) { std::unordered_map, vector, DBU>>, boost::hash>> markingBuffer; // (gridline, cp) -> (interval,netIdx) Dimension dir = database.getLayerDir(l); const RTree& tree = database.getFixedMetals(l); auto bit = tree.qbegin(bgi::satisfies([](auto const&) { return true; })), eit = tree.qend(); for (auto iter = bit; iter != eit; iter++) { const auto& pair = *iter; int netIdx = pair.second; db::BoxOnLayer box(l, bg::get(pair.first), bg::get(pair.first), bg::get(pair.first), bg::get(pair.first)); // compute the forbid region of a fixed metal db::AggrParaRunSpace aggr = db::AggrParaRunSpace::DEFAULT; if (database.getLayer(0).parallelLength.size() <= 1) { // hack for ISPD'18 test cases aggr = db::AggrParaRunSpace::LARGER_WIDTH; if (min(box.width(), box.height()) == database.getLayer(box.layerIdx).width && database.getOvlpFixedMetals(box, -2).size() == 1) { aggr = db::AggrParaRunSpace::DEFAULT; } } else { // hack for ISPD'19 test cases aggr = db::AggrParaRunSpace::LARGER_LENGTH; } auto forbidRegion = database.getMetalRectForbidRegion(box, aggr); auto gridBox = database.rangeSearch(forbidRegion, aggr == db::AggrParaRunSpace::LARGER_WIDTH); // TODO: change to false if (!database.isValid(gridBox)) continue; box = database.getLoc(gridBox); auto grBox = rangeSearchGCell(box); auto trackIntvl = database.rangeSearchTrack(l, box[dir]); if (!trackIntvl.IsValid()) continue; // mark wire usage int jMin = max(grBox[1 - dir].low - 1, 0); int jMax = min(grBox[1 - dir].high, getNumGrPoint(1 - dir) - 2); for (int i = grBox[dir].low; i <= grBox[dir].high; i++) { for (int j = jMin; j <= jMax; j++) { utils::IntervalT gcellIntvl1 = {getCoor(j, 1 - dir), getCoor(j + 1, 1 - dir)}; utils::IntervalT gcellIntvl2 = {getCoor(j + 1, 1 - dir), getCoor(j + 2, 1 - dir)}; utils::IntervalT edgeIntvl = {gcellIntvl1.center(), gcellIntvl2.center()}; auto blocked_length = box[1 - dir].IntersectWith(edgeIntvl).range(); if (blocked_length > 0) { auto gcellTrackIntvl = getTrackIntvl(l, i); auto blockedIntvl = gcellTrackIntvl.IntersectWith(trackIntvl); if (blockedIntvl.IsValid()) markingBuffer[std::make_pair(i, j)].emplace_back( std::make_pair(blockedIntvl, blocked_length)); } } } } for (auto& buf : markingBuffer) { auto gcellTrackIntvl = getTrackIntvl(l, buf.first.first); vector trackBlocked(gcellTrackIntvl.range() + 1, 0); // blocked track length for (auto& pair : buf.second) { for (int t = pair.first.low; t <= pair.first.high; t++) trackBlocked[t - gcellTrackIntvl.low] += pair.second; } int num_blocked = 0; DBU avg_blocked_len = 0; for (auto& len : trackBlocked) { if (len > 0) { num_blocked++; avg_blocked_len += len; } } avg_blocked_len /= num_blocked; markFixed(l, buf.first.first, buf.first.second, num_blocked, avg_blocked_len); } } } db::CostT GrRouteGrid::getViaCost(const GrPoint& via) const { return database.getUnitViaCost() * (unitViaMultiplier + getViaShortCost(via)); } db::CostT GrRouteGrid::getStackViaCost(const GrPoint& via, int height) const { db::CostT cost = 0; for (int i = 0; i < height; i++) { cost += getViaCost(gr::GrPoint(via.layerIdx + i, via.x, via.y)); } return cost; }; db::CostT GrRouteGrid::getWireDistCost(const GrEdge& edge) const { Dimension dir = database.getLayerDir(edge.getLayerIdx()); return getDist(edge.lowerGrPoint(), edge.upperGrPoint(), 1 - dir); } // logistic cost, ref: nctugr (8) // " With a growing number of rip-up and rerouting iterations, // the value of slope also grows to free the edge usage constraint. " db::CostT GrRouteGrid::getWireShortCost(const GrEdge& edge) const { // Note: didn't consider occurrence penalty int layerIdx = edge.getLayerIdx(); auto dir = database.getLayerDir(layerIdx); db::CostT cost = 0; int gridline = edge.u[dir]; for (int i = edge.u[1 - dir]; i < edge.v[1 - dir]; i++) { GrEdge tempEdge(layerIdx, gridline, i); auto fixed_used = getFixedUsage(tempEdge); auto wire_used = getWireUsage(tempEdge); DBU expected_of_len = fixed_used * getFixedLength(tempEdge) + wire_used * getWireDistCost(tempEdge); expected_of_len /= grDatabase.getNumTracks(layerIdx, edge.u[dir]); auto demand = fixed_used + wire_used + 1; demand += sqrt((getInCellViaNum(tempEdge.u) + getInCellViaNum(tempEdge.v)) / 2) * db::setting.unitSqrtViaUsage; auto capacity = getWireCapacity(tempEdge); cost += expected_of_len / (1.0 + exp(-logisticSlope * (demand - capacity))); } return cost * database.getUnitShortCost(layerIdx); } db::CostT GrRouteGrid::getViaShortCost(const GrPoint& via) const { double cost = 0; for (int side = 0; side <= 1; side++) { auto side_point = GrPoint({via.layerIdx + side, via.x, via.y}); double incell_used = getInCellUsedArea(side_point); double incell_area = getInCellArea(side_point); cost += 1.0 / (1.0 + exp(-logisticSlope * (incell_used - incell_area))); } return cost; // return cost; } db::CostT GrRouteGrid::getWireCost(const GrEdge& edge) const { if (edge.getLayerIdx() == 0) return LARGE_NUM; return getWireDistCost(edge) + getWireShortCost(edge); // return db::setting.wirelenCostWeight*getWireDistCost(edge) + getWireShortCost(edge); } bool GrRouteGrid::hasVio(const GrNet& net, bool hasCommit) const { return getNumVio(net, hasCommit) > 0; } bool GrRouteGrid::hasVio(const GrEdge& edge, bool hasCommit) const { return getNumVio(edge, !hasCommit) > 0; } bool GrRouteGrid::hasVio(const GrPoint& via, bool hasCommit) const { return getNumVio(via, !hasCommit) > 0; } double GrRouteGrid::getNumVio(const GrNet& net, bool hasCommit) const { double numVio = 0; const auto& guides = net.wireRouteGuides; for (const auto& guide : guides) { auto dir = database.getLayerDir(guide.layerIdx); double usage = 1.0 / (guide[dir].range() + 1); for (int gridline = guide[dir].low; gridline <= guide[dir].high; gridline++) { GrEdge tempEdge = (dir == X) ? GrEdge(guide.layerIdx, gridline, guide[Y].low, guide[Y].high) : GrEdge(guide.layerIdx, gridline, guide[X].low, guide[X].high); numVio += getNumVio(tempEdge, hasCommit ? 0 : usage); } } const auto& viaGuides = net.viaRouteGuides; for (int g1 = 0; g1 < viaGuides.size(); g1++) { for (int g2 = g1 + 1; g2 < viaGuides.size(); g2++) { if (abs(viaGuides[g1].layerIdx - viaGuides[g2].layerIdx) != 1) continue; auto xIntvl = viaGuides[g1][X].IntersectWith(viaGuides[g2][X]); auto yIntvl = viaGuides[g1][Y].IntersectWith(viaGuides[g2][Y]); if (xIntvl.IsValid() && yIntvl.IsValid()) { double usage = 1.0 / ((xIntvl.range() + 1) * (yIntvl.range() + 1)); for (int x = xIntvl.low; x <= xIntvl.high; x++) for (int y = yIntvl.low; y <= yIntvl.high; y++) numVio += getNumVio(GrPoint(min(viaGuides[g1].layerIdx, viaGuides[g2].layerIdx), x, y), hasCommit ? 0 : usage); } } } return numVio; } double GrRouteGrid::getNumVio(const GrEdge& edge, double selfUsage) const { int layerIdx = edge.getLayerIdx(); auto dir = database.getLayerDir(layerIdx); int gridline = edge.u[dir]; double numVio = 0; for (int i = edge.u[1 - dir]; i < edge.v[1 - dir]; i++) { GrEdge tempEdge(layerIdx, gridline, i); numVio += max( 0.0, getWireUsage(tempEdge) + selfUsage + getFixedUsage(tempEdge) + sqrt((getInCellViaNum(tempEdge.u) + getInCellViaNum(tempEdge.v)) / 2) * db::setting.unitSqrtViaUsage - getWireCapacity(tempEdge)); } return numVio; } double GrRouteGrid::getNumVio(const GrPoint& via, double selfUsage) const { double via_usage = getViaUsage(via) + selfUsage; double numVio = 0; for (int side = 0; side <= 1; side++) { auto side_point = GrPoint({via.layerIdx + side, via.x, via.y}); auto incell_area = getInCellArea(side_point); auto incell_used_area = getInCellUsedArea(side_point); if (incell_area >= incell_used_area) { // have remaining area } else { // have no remaining area numVio += via_usage; } } // if (numVio != 0) // log() << numVio << std::endl; return numVio; } void GrRouteGrid::setViaCapDiscount(double discount) { printflog("viaCapDiscount change: %.2f->%.2f\n", viaCapDiscount, discount); viaCapDiscount = discount; } void GrRouteGrid::setWireCapDiscount(double discount) { printflog("wireCapDiscount change: %.2f->%.2f\n", wireCapDiscount, discount); wireCapDiscount = discount; } void GrRouteGrid::setUnitViaMultiplier(double multiplier) { printflog("unitViaMultiplier change: %.2f->%.2f\n", unitViaMultiplier, multiplier); unitViaMultiplier = multiplier; } void GrRouteGrid::setLogisticSlope(double slope) { printflog("logisticSlope change: %.2f->%.2f\n", logisticSlope, slope); logisticSlope = slope; } void GrRouteGrid::addHistCost() { if (db::setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { printlog("Add hist cost"); } for (int layerIdx = 0; layerIdx < database.getLayerNum(); ++layerIdx) { auto dir = database.getLayerDir(layerIdx); for (int g = 0; g < getNumGrPoint(dir); ++g) { for (int cp = 0; cp < getNumGrEdge(layerIdx); ++cp) { GrEdge tempEdge(layerIdx, g, cp); if (hasVio(tempEdge)) useHistWire(layerIdx, g, cp, 1); } } } } void GrRouteGrid::useHistWire(int layerIdx, int gridline, int cp, double usage) { histWireUsageMap[layerIdx][gridline][cp] += usage; } void GrRouteGrid::fadeHistCost() { if (db::setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { printlog("Fade hist cost by", db::setting.rrrFadeCoeff, "..."); } for (int layerIdx = 0; layerIdx < database.getLayerNum(); ++layerIdx) { auto dir = database.getLayerDir(layerIdx); // wire for (int g = 0; g < getNumGrPoint(dir); ++g) for (int cp = 0; cp < getNumGrEdge(layerIdx); ++cp) histWireUsageMap[layerIdx][g][cp] *= db::setting.rrrFadeCoeff; } } void GrRouteGrid::statHistCost() const { if (db::setting.dbVerbose >= +db::VerboseLevelT::MIDDLE) { std::map histWireUsage, histViaUsage; for (int layerIdx = 0; layerIdx < database.getLayerNum(); ++layerIdx) { auto dir = database.getLayerDir(layerIdx); // wire for (int g = 0; g < getNumGrPoint(dir); ++g) for (int cp = 0; cp < getNumGrEdge(layerIdx); ++cp) ++histWireUsage[histWireUsageMap[layerIdx][g][cp]]; // via } printlog("Hist wire usage is", histWireUsage); printlog("Hist via usage is", histViaUsage); } } void GrRouteGrid2D::init2DMaps(const GrRouteGrid& routeGrid) { int numLayers = database.getLayerNum(); wireUsageMap2D.resize(2); fixedMetalMap2D.resize(2); capacityMap2D.resize(2); int xNumGrPoint = routeGrid.getNumGrPoint(X); int yNumGrPoint = routeGrid.getNumGrPoint(Y); int xNumGrEdge = yNumGrPoint - 1; int yNumGrEdge = xNumGrPoint - 1; wireUsageMap2D[X].resize(xNumGrPoint, vector(xNumGrEdge, 0)); fixedMetalMap2D[X].resize(xNumGrPoint, vector(xNumGrEdge, 0)); capacityMap2D[X].resize(xNumGrPoint, vector(xNumGrEdge, 0)); wireUsageMap2D[Y].resize(yNumGrPoint, vector(yNumGrEdge, 0)); fixedMetalMap2D[Y].resize(yNumGrPoint, vector(yNumGrEdge, 0)); capacityMap2D[Y].resize(yNumGrPoint, vector(yNumGrEdge, 0)); for (int l = 0; l < numLayers; l++) { auto dir = database.getLayerDir(l); if (dir == X) { for (int gridline = 0; gridline < xNumGrPoint; gridline++) { for (int cp = 0; cp < xNumGrEdge; cp++) { GrEdge tempEdge(l, gridline, cp); fixedMetalMap2D[X][gridline][cp] += routeGrid.getFixedUsage(tempEdge); capacityMap2D[X][gridline][cp] += routeGrid.getWireCapacity(tempEdge); } } } else { for (int gridline = 0; gridline < yNumGrPoint; gridline++) { for (int cp = 0; cp < yNumGrEdge; cp++) { GrEdge tempEdge(l, gridline, cp); fixedMetalMap2D[Y][gridline][cp] += routeGrid.getFixedUsage(tempEdge); capacityMap2D[Y][gridline][cp] += routeGrid.getWireCapacity(tempEdge); } } } } } void GrRouteGrid2D::useWire2D(int dir, int gridline, int cp, double usage) { wireUsageMap2D[dir][gridline][cp] += usage; } void GrRouteGrid2D::removeUsage2D(int dir, int gridline, int cp, double usage) { wireUsageMap2D[dir][gridline][cp] -= usage; } double GrRouteGrid2D::getCost2D(int dir, int gridline, int cp) const { double cost = 0; double fixed_usage = fixedMetalMap2D[dir][gridline][cp]; double wire_usage = wireUsageMap2D[dir][gridline][cp]; double cap = capacityMap2D[dir][gridline][cp]; double demand = fixed_usage + wire_usage; cost += 1 / (1.0 + exp(-1 * grDatabase.getLogisticSlope() * (demand - cap))); return cost; } } // namespace gr ================================================ FILE: src/gr_db/GrRouteGrid.h ================================================ #pragma once #include "GCell.h" #include "GrGeoPrimitive.h" #include "GrNet.h" namespace gr { class GrRouteGrid : public GCellGrid { public: using UsageT = double; using UsageMapT = vector>>; int edge_shifted =0; int tot_edge = 0; void init(); void clear(); void useNet(const GrNet& net); void removeNet(GrNet& net); db::CostT getViaCost(const GrPoint& via) const; db::CostT getStackViaCost(const GrPoint& via, int height) const; db::CostT getWireCost(const GrEdge& edge) const; db::CostT getHistCost(int layerIdx, int gridline, int cp) const; double getCellUsage(const GrPoint& point) const; // Note: simplified version bool hasVio(const GrNet& net, bool hasCommit = true) const; bool hasVio(const GrEdge& edge, bool hasCommit = true) const; bool hasVio(const GrPoint& via, bool hasCommit = true) const; void print() const; void printAllUsageAndVio() const; double getWirelength() const; void setViaCapDiscount(double discount = 1); void setWireCapDiscount(double discount = 1); void setUnitViaMultiplier(double multiplier = 1); void setLogisticSlope(double slope = 1); double getLogisticSlope() const { return logisticSlope; } // for ripup and reroute void addHistCost(); void fadeHistCost(); void statHistCost() const; friend class GrRouteGrid2D; private: // only pref-dir is modeled UsageMapT routedWireMap; // model cross-cell routing UsageMapT routedViaMap; vector>>> fixedMetalMap; // layer, x, y, (# blocked tracks, avg blocked length) vector>> histWireUsageMap; db::CostT getWireDistCost(const GrEdge& edge) const; db::CostT getWireShortCost(const GrEdge& edge) const; db::CostT getViaShortCost(const GrPoint& via) const; double viaCapDiscount = 1; double wireCapDiscount = 1; double unitViaMultiplier = 1; double logisticSlope = 1; std::pair printAllUsage() const; double printAllVio() const; double getAllWireUsage(const vector& buckets, vector& wireUsageGrid, vector& wireUsageLength) const; void getAllInCellUsage(const vector& buckets, vector& viaUsage) const; double getTotViaNum() const; void markFixedMetals(); void markFixed(int layerIdx, int gridline, int cp, int num_track, DBU avg_length); double getNumVio(const GrNet& net, bool hasCommit) const; double getNumVio(const GrEdge& edge, double selfUsage) const; double getNumVio(const GrPoint& via, double selfUsage) const; double getFixedUsage(int layerIdx, int gridline, int cp) const; double getFixedUsage(const GrEdge& edge) const; double getWireUsage(int layerIdx, int gridline, int cp) const; double getWireUsage(const GrEdge& edge) const; double getViaUsage(int layerIdx, int x, int y) const; double getViaUsage(const GrPoint& via) const; double getCellUsage(int layerIdx, int x, int y) const; double getWireCapacity(const GrEdge& edge) const; double getInCellArea(const GrPoint& point) const; double getInCellUsedArea(const GrPoint& point) const; double getFixedUsedArea(const GrEdge& edge) const; // fixed used area of the area of an edge DBU getFixedLength(const GrEdge& edge) const; double getInCellViaNum(const GrPoint& point) const; // double getUnitViaArea(const GrPoint& point, int side) const; void removeWire(const GrBoxOnLayer& box); void removeVia(const GrBoxOnLayer& box); void useWire(const GrBoxOnLayer& box); void useWire(int layerIdx, int gridline, int cp, double usage = 1); void useVia(const GrBoxOnLayer& box); void useVia(int layerIdx, int x, int y, double usage = 1); void useHistWire(int layerIdx, int gridline, int cp, double usage); }; class GrRouteGrid2D { public: using UsageT = double; using UsageMapT = vector>>; void init2DMaps(const GrRouteGrid& routeGrid); void useWire2D(int dir, int gridline, int cp, double usage = 1); void removeUsage2D(int dir, int gridline, int cp, double usage = 1); double getCost2D(int dir, int gridline, int cp) const; private: UsageMapT wireUsageMap2D; // 2d, first dim show X,Y UsageMapT fixedMetalMap2D; // 2d, first dim show X,Y UsageMapT capacityMap2D; // 2d, first dim show X,Y }; } // namespace gr ================================================ FILE: src/gr_db/GridTopo.cpp ================================================ #include "GridTopo.h" namespace gr { void GrSteiner::setParent(std::shared_ptr childNode, std::shared_ptr parentNode) { parentNode->children.push_back(childNode); childNode->parent = parentNode; } void GrSteiner::resetParent(std::shared_ptr node) { assert(node->parent); auto& n = node->parent->children; auto it = find(n.begin(), n.end(), node); assert(it != n.end()); *it = n.back(); n.pop_back(); node->parent.reset(); } void GrSteiner::preOrder(std::shared_ptr node, const std::function)>& visit) { visit(node); for (auto c : node->children) preOrder(c, visit); } void GrSteiner::postOrder(std::shared_ptr node, const std::function)>& visit) { for (auto c : node->children) postOrder(c, visit); visit(node); } void GrSteiner::postOrderCopy(std::shared_ptr node, const std::function)>& visit) { auto tmp = node->children; for (auto c : tmp) postOrderCopy(c, visit); visit(node); } void GrSteiner::mergeNodes(std::shared_ptr root) { postOrderCopy(root, [](std::shared_ptr node) { // parent - node - child if (node->parent && node->parent->layerIdx == node->layerIdx && node->children.size() == 1 && node->pinIdx < 0) { auto oldChild = node->children[0]; if (node->layerIdx == oldChild->layerIdx && node->getPrefIdx() == oldChild->getPrefIdx() && node->parent->getPrefIdx() == node->getPrefIdx()) { auto oldParent = node->parent; resetParent(node); resetParent(oldChild); setParent(oldChild, oldParent); } } }); } void GrSteiner::removeRedundancy(std::shared_ptr root) { for (int i = 0; i < root->children.size(); i++) { if (GrPoint(*root) == GrPoint(*root->children[i])) { auto child_ptr = root->children[i]; root->children.erase(root->children.begin() + i); i--; for (auto& grand_child : child_ptr->children) { setParent(grand_child, root); } } } for (auto& child : root->children) { removeRedundancy(child); } } bool GrSteiner::checkConnectivity(std::shared_ptr root, vector& pins) { bool detached_node = false; std::unordered_map pin_visited; for (int i = 0; i < pins.size(); i++) { pin_visited[pins[i]] = false; } preOrder(root, [&](std::shared_ptr node) { if (pin_visited.find(GrPoint(*node)) != pin_visited.end()) { node->pinIdx = 1; pin_visited[GrPoint(*node)] = true; } for (auto& child : node->children) { // If two nodes are connected, at least 2 of their coordinates should be the same if (node->layerIdx == child->layerIdx) { if (node->x != child->x && node->y != child->y) { detached_node = true; } } else if (abs(node->layerIdx - child->layerIdx) <= 1) { if (node->x != child->x || node->y != child->y) { detached_node = true; } } else { detached_node = true; } int match_cnt = 0; if (node->x == child->x) match_cnt++; if (node->y == child->y) match_cnt++; if (node->layerIdx == child->layerIdx) match_cnt++; if (match_cnt < 2) detached_node = true; } }); for (auto& p_v : pin_visited) { if (p_v.second == false) return false; } if (detached_node) return false; return true; } ostream& operator<<(ostream& os, const GrSteiner& node) { os << GrPoint(node); if (node.pinIdx >= 0) os << " pin" << node.pinIdx; return os; } void GrSteiner::printTree(ostream& os, int depth) { os << *this << ", "; bool first = true; for (auto child : children) { if (!first) { for (int i = 0; i < depth; ++i) os << '.'; os << *this << ", "; } child->printTree(os, depth + 1); if (children.size() > 1) { os << std::endl; } first = false; } } } // namespace gr ================================================ FILE: src/gr_db/GridTopo.h ================================================ #pragma once #include "GrGeoPrimitive.h" namespace gr { class GrSteiner : public GrPoint { public: int pinIdx; // -1 stands for "not pin" std::shared_ptr parent; vector> children; GrSteiner(const GrPoint& grPoint, int pinIndex = -1) : GrPoint(grPoint), pinIdx(pinIndex) {} bool isRealPin() const { return pinIdx >= 0; } // Set/reset parent static void setParent(std::shared_ptr childNode, std::shared_ptr parentNode); static void resetParent(std::shared_ptr node); // Traverse static void preOrder(std::shared_ptr node, const std::function)>& visit); static void postOrder(std::shared_ptr node, const std::function)>& visit); static void postOrderCopy(std::shared_ptr node, const std::function)>& visit); // Merge two same-layer edges (assume they are on the same track) static void mergeNodes(std::shared_ptr root); // Remove redundant nodes static void removeRedundancy(std::shared_ptr root); static bool checkConnectivity(std::shared_ptr root, vector& pins); friend ostream& operator<<(ostream& os, const GrSteiner& node); void printTree(ostream& os = std::cout, int depth = 0); }; } // namespace gr ================================================ FILE: src/main.cpp ================================================ #include "db/Database.h" #include "global.h" #include "multi_net/Router.h" #include "gr_db/GrDatabase.h" double LARGE_NUM = 100000000; // ----------------------------------------------------------------------------- void signalHandler(int signum) { std::cout << "Signal (" << signum << ") received. Exiting...\n"; // cleanup and close up stuff here std::exit(signum); } // ----------------------------------------------------------------------------- void runISPD18Flow(const boost::program_options::variables_map& vm) { // db::setting.makeItSilent(); Rsyn::Session session; // Parse options // required std::string lefFile = vm.at("lef").as(); std::string defFile = vm.at("def").as(); db::setting.numThreads = vm.at("threads").as(); db::setting.outputFile = vm.at("output").as(); // optional if (vm.count("tat")) { db::setting.tat = vm.at("tat").as(); } // multi_net if (vm.count("multiNetVerbose")) { db::setting.multiNetVerbose = db::VerboseLevelT::_from_string(vm.at("multiNetVerbose").as().c_str()); } if (vm.count("multiNetScheduleSortAll")) { db::setting.multiNetScheduleSortAll = vm.at("multiNetScheduleSortAll").as(); } if (vm.count("multiNetScheduleReverse")) { db::setting.multiNetScheduleReverse = vm.at("multiNetScheduleReverse").as(); } if (vm.count("multiNetScheduleSort")) { db::setting.multiNetScheduleSort = vm.at("multiNetScheduleSort").as(); } if (vm.count("rrrIters")) { db::setting.rrrIterLimit = vm.at("rrrIters").as(); } if (vm.count("rrrWriteEachIter")) { db::setting.rrrWriteEachIter = vm.at("rrrWriteEachIter").as(); } if (vm.count("rrrInitVioCostDiscount")) { db::setting.rrrInitVioCostDiscount = vm.at("rrrInitVioCostDiscount").as(); } if (vm.count("rrrFadeCoeff")) { db::setting.rrrFadeCoeff = vm.at("rrrFadeCoeff").as(); } if (vm.count("edgeShiftingIter")) { db::setting.edgeShiftingIter = vm.at("edgeShiftingIter").as(); } // single_net if (vm.count("fixOpenBySST")) { db::setting.fixOpenBySST = vm.at("fixOpenBySST").as(); } // db if (vm.count("dbVerbose")) { db::setting.dbVerbose = db::VerboseLevelT::_from_string(vm.at("dbVerbose").as().c_str()); } if (vm.count("dbInitHistUsageForPinAccess")) { db::setting.dbInitHistUsageForPinAccess = vm.at("dbInitHistUsageForPinAccess").as(); } vector strs; boost::split(strs, db::setting.outputFile, boost::is_any_of(".")); db::setting.name = strs[0]; // Read benchmarks Rsyn::ISPD2018Reader reader; const Rsyn::Json params = { {"lefFile", lefFile}, {"defFile", defFile}, }; log() << std::endl; if (db::setting.dbVerbose >= +db::VerboseLevelT::HIGH) { log() << "################################################################" << std::endl; log() << "Start reading benchmarks" << std::endl; } reader.load(params); if (db::setting.dbVerbose >= +db::VerboseLevelT::HIGH) { log() << "Finish reading benchmarks" << std::endl; log() << "MEM: cur=" << utils::mem_use::get_current() << "MB, peak=" << utils::mem_use::get_peak() << "MB" << std::endl; log() << std::endl; } // Route database.init(); db::setting.adapt(); grDatabase.init(); log() << "finish reading benchmark" << std::endl; Router router; router.run(); grDatabase.writeGuides(db::setting.outputFile); database.clear(); grDatabase.clear(); log() << "MEM: cur=" << utils::mem_use::get_current() << "MB, peak=" << utils::mem_use::get_peak() << "MB" << std::endl; log() << std::endl; } // ----------------------------------------------------------------------------- int main(int argc, char* argv[]) { signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); Rsyn::Session::init(); printlog("------------------------------------------------------------------------------"); printlog(" ICCAD 2019 - Global Routing Contest "); printlog(" Team number : 15 "); printlog(" Team name : CU-GR "); printlog(" Members: Jinwei Liu, Chak-Wa Pui, Fangzhou Wang, "); printlog(" Evangeline F.Y. Young "); printlog(" Affiliation: The Chinese University of Hong Kong "); printlog("------------------------------------------------------------------------------"); std::cout << std::boolalpha; // set std::boolalpha to std::cout try { using namespace boost::program_options; options_description desc{"Options"}; // clang-format off desc.add_options() ("help", "Help message.") ("lef", value()->required(), "Input .lef file") ("def", value()->required(), "Input .def file.") ("threads", value()->required(), "# of threads") ("output", value()->required(), "Output file name") // optional ("tat", value(), "Runtime limit (sec)") ("multiNetVerbose", value()) ("multiNetScheduleSortAll", value()) ("multiNetScheduleReverse", value()) ("multiNetScheduleSort", value()) ("rrrIters", value()) ("rrrWriteEachIter", value()) ("rrrInitVioCostDiscount", value()) ("rrrFadeCoeff", value()) ("edgeShiftingIter", value()) ("fixOpenBySST", value()) ("dbVerbose", value()) ("dbInitHistUsageForPinAccess", value()) ; // clang-format on variables_map vm; store(command_line_parser(argc, argv) .options(desc) .style(command_line_style::unix_style | command_line_style::allow_long_disguise) .run(), vm); notify(vm); if (vm.count("help")) { std::cout << desc << std::endl; return 0; } for (const auto& option : desc.options()) { if (vm.count(option->long_name())) { std::string name = option->description().empty() ? option->long_name() : option->description(); log() << std::left << std::setw(18) << name << ": "; const auto& value = vm.at(option->long_name()).value(); if (auto v = boost::any_cast(&value)) { std::cout << *v; } else if (auto v = boost::any_cast(&value)) { std::cout << *v; } else if (auto v = boost::any_cast(&value)) { std::cout << *v; } else if (auto v = boost::any_cast(&value)) { std::cout << *v; } else { std::cout << "unresolved type"; } std::cout << std::endl; } } runISPD18Flow(vm); } catch (const boost::program_options::error& e) { printlog(e.what()); } printlog("---------------------------------------------------------------------------"); printlog(" Terminated... "); printlog("---------------------------------------------------------------------------"); return 0; } ================================================ FILE: src/multi_net/CongestionMap.cpp ================================================ #include "CongestionMap.h" #include "global.h" double CongestionMap::calcCrsnEdgeCost(const gr::PointOnLayer& u, const gr::PointOnLayer& v) { if (u.layerIdx != v.layerIdx && abs(u[X] - v[X]) + abs(u[Y] - v[Y]) != 1) { printlog("Warning: CongestionMap::calcCrsnEdgeCost,", "edge longer than one,", u, v); return std::numeric_limits::max(); } int layerIdx = u.layerIdx; auto layerDir = database.getLayerDir(layerIdx); if (layerIdx == 0) return LARGE_NUM; utils::BoxT box; auto u_box = getGrBox(u); auto v_box = getGrBox(v); double cost = 0; box = u_box; double avgRsrc = 0; for (int x_idx = box.x.low; x_idx <= box.x.high; x_idx++) { for (int y_idx = box.y.low; y_idx <= box.y.high; y_idx++) { avgRsrc += rsrcMap[layerIdx][x_idx][y_idx]; } } avgRsrc /= (box.x.range() + 1) * (box.y.range() + 1); cost += double(layerDir == X ? yCrsnScale : xCrsnScale) * 1.0 / max(avgRsrc, 0.1); box = v_box; avgRsrc = 0; for (int x_idx = box.x.low; x_idx <= box.x.high; x_idx++) { for (int y_idx = box.y.low; y_idx <= box.y.high; y_idx++) { avgRsrc += rsrcMap[layerIdx][x_idx][y_idx]; } } avgRsrc /= (box.x.range() + 1) * (box.y.range() + 1); cost += double(layerDir == X ? yCrsnScale : xCrsnScale) * 1.0 / max(avgRsrc, 0.1); return cost; } double CongestionMap::calcCrsnViaCost(const gr::PointOnLayer& via) { utils::BoxT box = getGrBox(via); double cost = 0; for (int l_idx = via.layerIdx; l_idx <= via.layerIdx + 1; l_idx++) { double avgRsrc = 0; for (int x_idx = box.x.low; x_idx <= box.x.high; x_idx++) { for (int y_idx = box.y.low; y_idx <= box.y.high; y_idx++) { avgRsrc += rsrcMap[l_idx][x_idx][y_idx]; } } avgRsrc /= (box.x.range() + 1) * (box.y.range() + 1); cost += 1.0 / max(avgRsrc, 0.1); } return cost; } double CongestionMap::getCrsnEdgeCost(const gr::PointOnLayer& u, const gr::PointOnLayer& v) const { if (u.layerIdx != v.layerIdx && abs(u[X] - v[X]) + abs(u[Y] - v[Y]) != 1) { printlog("Warning: CongestionMap::calcCrsnEdgeCost,", "edge longer than one,", u, v); return std::numeric_limits::max(); } int layerIdx = u.layerIdx; auto layerDir = database.getLayerDir(layerIdx); int gridline = u[layerDir]; int cp = min(u[1 - layerDir], v[1 - layerDir]); return crsnEdgeCostMap[layerIdx][gridline][cp]; } double CongestionMap::getCrsnViaCost(const gr::PointOnLayer& via) const { return crsnViaCostMap[via.layerIdx][via.x][via.y]; } utils::BoxT CongestionMap::getGrBox(const gr::PointOnLayer& u) const { // get the gcell box in a coarsened cell utils::BoxT gcellBox; gcellBox.x.Update(u[X] * xCrsnScale); gcellBox.x.Update(min(u[X] * xCrsnScale + xCrsnScale, grDatabase.getNumGrPoint(X)) - 1); gcellBox.y.Update(u[Y] * yCrsnScale); gcellBox.y.Update(min(u[Y] * yCrsnScale + yCrsnScale, grDatabase.getNumGrPoint(Y)) - 1); return gcellBox; } gr::PointOnLayer CongestionMap::grPointToPoint(const gr::GrPoint& point) const { return {point.layerIdx, point[X] / xCrsnScale, point[Y] / yCrsnScale}; } void CongestionMap::init(int x_crsn_scale, int y_crsn_scale) { xCrsnScale = x_crsn_scale; yCrsnScale = y_crsn_scale; rsrcMap.assign(database.getLayerNum(), vector>(grDatabase.getNumGrPoint(X), vector(grDatabase.getNumGrPoint(Y), 0))); for (int l_idx = 0; l_idx < database.getLayerNum(); l_idx++) for (int x_idx = 0; x_idx < grDatabase.getNumGrPoint(X); x_idx++) for (int y_idx = 0; y_idx < grDatabase.getNumGrPoint(Y); y_idx++) rsrcMap[l_idx][x_idx][y_idx] = grDatabase.getCellUsage({l_idx, x_idx, y_idx}); xNumCrsnCell = ceil(grDatabase.getNumGrPoint(X) / (double)xCrsnScale); yNumCrsnCell = ceil(grDatabase.getNumGrPoint(Y) / (double)xCrsnScale); crsnViaCostMap.clear(); crsnEdgeCostMap.clear(); crsnViaCostMap.resize(database.getLayerNum() - 1, vector>(xNumCrsnCell, vector(yNumCrsnCell))); crsnEdgeCostMap.resize(database.getLayerNum()); for (int l = 0; l < database.getLayerNum(); l++) { if (database.getLayerDir(l) == X) crsnEdgeCostMap[l].resize(xNumCrsnCell, vector(yNumCrsnCell - 1)); else crsnEdgeCostMap[l].resize(yNumCrsnCell, vector(xNumCrsnCell - 1)); } for (int l = 0; l < database.getLayerNum(); l++) { if (database.getLayerDir(l) == X) { for (int gridline = 0; gridline < xNumCrsnCell; gridline++) for (int cp = 0; cp < yNumCrsnCell - 1; cp++) crsnEdgeCostMap[l][gridline][cp] = calcCrsnEdgeCost({l, gridline, cp}, {l, gridline, cp + 1}); } else { for (int gridline = 0; gridline < yNumCrsnCell; gridline++) for (int cp = 0; cp < xNumCrsnCell - 1; cp++) crsnEdgeCostMap[l][gridline][cp] = calcCrsnEdgeCost({l, cp, gridline}, {l, cp + 1, gridline}); } } for (int l = 0; l < database.getLayerNum() - 1; l++) { for (int x = 0; x < xNumCrsnCell; x++) for (int y = 0; y < yNumCrsnCell; y++) crsnViaCostMap[l][x][y] = calcCrsnViaCost({l, x, y}); } } void CongestionMap::update(const gr::GrNet& net) { std::unordered_set pointSet; auto updateBox = [&](const gr::GrBoxOnLayer& box) { int l_idx = box.layerIdx; for (int x_idx = box[X].low; x_idx <= box[X].high; x_idx++) { for (int y_idx = box[Y].low; y_idx <= box[Y].high; y_idx++) { rsrcMap[l_idx][x_idx][y_idx] = grDatabase.getCellUsage({l_idx, x_idx, y_idx}); pointSet.insert(grPointToPoint({l_idx, x_idx, y_idx})); } } }; for (auto& guide : net.wireRouteGuides) { // enlarge the updating box auto box = guide; if (database.getLayerDir(guide.layerIdx) == X) { box[Y].Update(max(guide[Y].low - 1, 0)); box[Y].Update(min(guide[Y].high + 1, grDatabase.getNumGrPoint(Y) - 1)); } else { box[X].Update(max(guide[X].low - 1, 0)); box[X].Update(min(guide[X].high + 1, grDatabase.getNumGrPoint(X) - 1)); } updateBox(box); } for (auto& guide : net.viaRouteGuides) { updateBox(guide); } for (auto& point : pointSet) { updateViaCostMap(point); updateWireCostMap(point); } } void CongestionMap::updateViaCostMap(const gr::PointOnLayer& point) { int layerIdx = point.layerIdx; if (layerIdx < database.getLayerNum() - 1) crsnViaCostMap[layerIdx][point.x][point.y] = calcCrsnViaCost(point); if (layerIdx > 0) crsnViaCostMap[layerIdx - 1][point.x][point.y] = calcCrsnViaCost({layerIdx - 1, point.x, point.y}); } void CongestionMap::updateWireCostMap(const gr::PointOnLayer& point) { int layerIdx = point.layerIdx; auto layerDir = database.getLayerDir(layerIdx); int gridline = point[layerDir]; int cp = point[1 - layerDir]; int cpNum = (layerDir == X) ? yNumCrsnCell : xNumCrsnCell; if (layerDir == X) { if (cp > 0) crsnEdgeCostMap[layerIdx][gridline][cp - 1] = calcCrsnEdgeCost({layerIdx, point.x, point.y - 1}, {layerIdx, point.x, point.y}); if (cp < cpNum - 1) crsnEdgeCostMap[layerIdx][gridline][cp] = calcCrsnEdgeCost({layerIdx, point.x, point.y}, {layerIdx, point.x, point.y + 1}); } else { if (cp > 0) crsnEdgeCostMap[layerIdx][gridline][cp - 1] = calcCrsnEdgeCost({layerIdx, point.x - 1, point.y}, {layerIdx, point.x, point.y}); if (cp < cpNum - 1) crsnEdgeCostMap[layerIdx][gridline][cp] = calcCrsnEdgeCost({layerIdx, point.x, point.y}, {layerIdx, point.x + 1, point.y}); } } ================================================ FILE: src/multi_net/CongestionMap.h ================================================ #pragma once #include "db/Database.h" #include "gr_db/GrDatabase.h" // create remaining gcell resource map (for congestion overview) class CongestionMap { public: double getCrsnEdgeCost(const gr::PointOnLayer& u, const gr::PointOnLayer& v) const; double getCrsnViaCost(const gr::PointOnLayer& via) const; int getCellWidth() const { return xCrsnScale; } int getCellHeight() const { return yCrsnScale; } gr::PointOnLayer grPointToPoint(const gr::GrPoint& point) const; double getRsrcUsage(int l, int x, int y) const { return rsrcMap[l][x][y]; }; void init(int x_crsn_scale, int y_crsn_scale); void update(const gr::GrNet& net); private: bool getCrsnFixed(const gr::PointOnLayer& u) const; utils::BoxT getGrBox(const gr::PointOnLayer& u) const; // get the gcell box in a coarsened cell void updateViaCostMap(const gr::PointOnLayer& point); void updateWireCostMap(const gr::PointOnLayer& point); double calcCrsnEdgeCost(const gr::PointOnLayer& u, const gr::PointOnLayer& v); double calcCrsnViaCost(const gr::PointOnLayer& via); int xCrsnScale; int yCrsnScale; int xNumCrsnCell; int yNumCrsnCell; vector>> rsrcMap; // note that this is not coarsened vector>> crsnEdgeCostMap; vector>> crsnViaCostMap; }; ================================================ FILE: src/multi_net/Router.cpp ================================================ #include "Router.h" #include "flute/flute.h" #include "Scheduler.h" #include "single_net/InitRoute.h" extern "C" { void readLUT(); } const MTStat& MTStat::operator+=(const MTStat& rhs) { auto dur = rhs.durations; std::sort(dur.begin(), dur.end()); if (durations.size() < dur.size()) { durations.resize(dur.size(), 0.0); } for (int i = 0; i < dur.size(); ++i) { durations[i] += dur[i]; } return *this; } ostream& operator<<(ostream& os, const MTStat mtStat) { double minDur = std::numeric_limits::max(), maxDur = 0.0, avgDur = 0.0; for (double dur : mtStat.durations) { minDur = min(minDur, dur); maxDur = max(maxDur, dur); avgDur += dur; } avgDur /= mtStat.durations.size(); os << "#threads=" << mtStat.durations.size() << " (dur: min=" << minDur << ", max=" << maxDur << ", avg=" << avgDur << ")"; return os; } void Router::run() { allNetStatus.resize(database.nets.size(), db::RouteStatus::FAIL_UNPROCESSED); for (iter = 0; iter < db::setting.rrrIterLimit; iter++) { log() << std::endl; log() << "################################################################" << std::endl; log() << "Start RRR iteration " << iter << std::endl; log() << std::endl; db::routeStat.clear(); guideGenStat.reset(); vector netsToRoute = getNetsToRoute(); if (netsToRoute.empty()) { if (db::setting.multiNetVerbose >= +db::VerboseLevelT::MIDDLE) { log() << "No net is identified for this iteration of RRR." << std::endl; log() << std::endl; } break; } sortNets(netsToRoute); // Note: only effective when doing mazeroute sequentially updateCost(); grDatabase.statHistCost(); if (iter > 0) { ripup(netsToRoute); congMap.init(cellWidth, cellHeight); } routeApprx(netsToRoute); log() << std::endl; log() << "Finish RRR iteration " << iter << std::endl; log() << "MEM: cur=" << utils::mem_use::get_current() << "MB, peak=" << utils::mem_use::get_peak() << "MB" << std::endl; if (db::setting.multiNetVerbose >= +db::VerboseLevelT::MIDDLE) db::routeStat.print(); } // postprocessing for (auto& net : grDatabase.nets) { GuideGenerator guideGen(net); guideGen.genPatchGuides(); } if (db::setting.multiNetVerbose >= +db::VerboseLevelT::MIDDLE) guideGenStat.print(); // congMap.printCrsnMap(1, {80, 1000}, {40, 70}); log() << std::endl; log() << "################################################################" << std::endl; database.setUnitVioCost(1); // set the cost back to without discount log() << "Finish all RRR iterations and PostRoute" << std::endl; log() << "MEM: cur=" << utils::mem_use::get_current() << "MB, peak=" << utils::mem_use::get_peak() << "MB" << std::endl; printStat(); } Router::Router() { readLUT(); // read flute LUT } void Router::ripup(const vector& netsToRoute) { for (auto id : netsToRoute) { grDatabase.removeNet(grDatabase.nets[id]); grDatabase.nets[id].gridTopo.clear(); allNetStatus[id] = db::RouteStatus::FAIL_UNPROCESSED; } } void Router::updateCost() { if (iter > 0) { // apply in rrr stages grDatabase.addHistCost(); grDatabase.fadeHistCost(); grDatabase.setUnitViaMultiplier( max(100 / pow(5, iter - 1), 4.0)); // enlarge unit via cost to avoid extra use of vias grDatabase.setLogisticSlope(db::setting.initLogisticSlope * pow(2, iter)); } if (db::setting.rrrIterLimit > 1) { double step = (1.0 - db::setting.rrrInitVioCostDiscount) / (db::setting.rrrIterLimit - 1); database.setUnitVioCost(db::setting.rrrInitVioCostDiscount + step * iter); } } vector> Router::getBatches(vector& routers, const vector& netsToRoute, bool seqEq) { vector batch(netsToRoute.size()); for (int i = 0; i < netsToRoute.size(); i++) batch[i] = i; runJobsMT(batch.size(), [&](int jobIdx) { auto& router = routers[batch[jobIdx]]; const auto mergedPinAccessBoxes = grDatabase.nets[netsToRoute[jobIdx]].getMergedPinAccessBoxes( [](const gr::GrPoint& point) { return gr::PointOnLayer(point.layerIdx, point[X], point[Y]); }); utils::IntervalT xIntvl, yIntvl; for (auto& points : mergedPinAccessBoxes) { for (auto& point : points) { xIntvl.Update(point[X]); yIntvl.Update(point[Y]); } } router.guides.emplace_back(0, xIntvl, yIntvl); }); Scheduler scheduler(routers); const vector>& batches = seqEq ? scheduler.scheduleOrderEq() : scheduler.schedule(); if (db::setting.multiNetVerbose >= +db::VerboseLevelT::MIDDLE) { log() << "Finish multi-thread scheduling" << ((db::setting.numThreads == 0) ? " using simple mode" : "") << ". There will be " << batches.size() << " batches for " << netsToRoute.size() << " nets." << std::endl; log() << std::endl; } return batches; } void Router::routeApprx(const vector& netsToRoute) { if (iter == 0) { fluteAllAndRoute(netsToRoute); } else { vector routers; routers.reserve(netsToRoute.size()); for (auto id : netsToRoute) routers.emplace_back(grDatabase.nets[id]); vector> batches = getBatches(routers, netsToRoute, false); for (const vector& batch : batches) { runJobsMT(batch.size(), [&](int jobIdx) { auto& router = routers[batch[jobIdx]]; router.planMazeRoute(congMap); }); for (auto jobIdx : batch) { auto& router = routers[jobIdx]; router.mazeRoute(); router.finish(); int netIdx = netsToRoute[jobIdx]; congMap.update(grDatabase.nets[netIdx]); allNetStatus[netIdx] = router.status; } } } } void Router::fluteAllAndRoute(const vector& netsToRoute) { vector routers; vector initRouters; routers.reserve(netsToRoute.size()); initRouters.reserve(netsToRoute.size()); for (auto id : netsToRoute) routers.emplace_back(grDatabase.nets[id]); for (auto id : netsToRoute) initRouters.emplace_back(grDatabase.nets[id]); grDatabase.init2DMaps(grDatabase); for (auto& router : initRouters) if (router.grNet.needToRoute()) router.plan_fluteOnly(); printlog("finish planning"); for (int i = 0; i < db::setting.edgeShiftingIter; i++) { grDatabase.edge_shifted = 0; for (auto& router : initRouters) if (router.grNet.needToRoute()) router.edge_shift2d(router.getRouteNodes()); log() << "Total Number of edges in Iter " << i << " : " << grDatabase.tot_edge << ". Edge Shifted: " << grDatabase.edge_shifted << "(" << 100.0 * grDatabase.edge_shifted / grDatabase.tot_edge << "%)" << std::endl; } for (auto& router : initRouters) if (router.grNet.needToRoute()) router.getRoutingOrder(); printlog("finish edge shifting"); vector> batches = getBatches(routers, netsToRoute, true); for (const vector& batch : batches) { runJobsMT(batch.size(), [&](int jobIdx) { int idx = batch[jobIdx]; auto& router = routers[idx]; router.initRoutePattern(initRouters[idx]); router.finish(); allNetStatus[netsToRoute[idx]] = router.status; }); } printlog("finish pattern route"); } void Router::sortNets(vector& netsToRoute) { sort(netsToRoute.begin(), netsToRoute.end(), [&](int id1, int id2) { return grDatabase.nets[id1].boundingBox.hp() < grDatabase.nets[id2].boundingBox.hp(); }); } vector Router::getNetsToRoute() { vector netsToRoute; if (iter == 0) { for (auto& net : grDatabase.nets) netsToRoute.push_back(net.dbNet.idx); } else { for (auto& net : grDatabase.nets) if (grDatabase.hasVio(net)) netsToRoute.push_back(net.dbNet.idx); } return netsToRoute; } void Router::printStat() { log() << std::endl; log() << "----------------------------------------------------------------" << std::endl; db::routeStat.print(); grDatabase.printAllUsageAndVio(); log() << "----------------------------------------------------------------" << std::endl; log() << std::endl; } ================================================ FILE: src/multi_net/Router.h ================================================ #pragma once #include "db/Database.h" #include "gr_db/GrDatabase.h" #include "single_net/SingleNetRouter.h" #include "CongestionMap.h" class Router { public: Router(); void run(); private: int iter; vector allNetStatus; CongestionMap congMap; int cellWidth = 5, cellHeight = 5; vector getNetsToRoute(); void sortNets(vector& netsToRoute); vector> getBatches(vector& routers, const vector& netsToRoute, bool seqEq); void routeApprx(const vector& netsToRoute); void fluteAllAndRoute(const vector& netsToRoute); void ripup(const vector& netsToRoute); void updateCost(); void printStat(); }; ================================================ FILE: src/multi_net/Scheduler.cpp ================================================ #include "Scheduler.h" vector> &Scheduler::schedule() { // vector estimatedNumOfVertices(routers.size(), 0); for (int id = 0; id < routers.size(); ++id) for (auto &guide : routers[id].guides) estimatedNumOfVertices[id] += (guide[X].range() + 1) * (guide[Y].range() + 1); // init assigned table vector assigned(routers.size(), false); // sort by sizes vector routerIds; for (int id = 0; id < routers.size(); ++id) routerIds.push_back(id); if (db::setting.multiNetScheduleSortAll) { std::sort(routerIds.begin(), routerIds.end(), [&](int lhs, int rhs) { return estimatedNumOfVertices[lhs] > estimatedNumOfVertices[rhs]; }); } if (db::setting.numThreads == 0) { // simple case for (int routerId : routerIds) batches.push_back({routerId}); } else { // normal case int lastUnroute = 0; while (lastUnroute < routerIds.size()) { // create a new batch from a seed batches.emplace_back(); initSet({}); vector &batch = batches.back(); for (int i = lastUnroute; i < routerIds.size(); ++i) { int routerId = routerIds[i]; if (!assigned[routerId] && !hasConflict(routerId)) { batch.push_back(routerId); assigned[routerId] = true; updateSet(routerId); } } // find the next seed while (lastUnroute < routerIds.size() && assigned[routerIds[lastUnroute]]) { ++lastUnroute; } } // sort within batches by NumOfVertices if (db::setting.multiNetScheduleSort) { for (auto &batch : batches) { std::sort(batch.begin(), batch.end(), [&](int lhs, int rhs) { return estimatedNumOfVertices[lhs] > estimatedNumOfVertices[rhs]; }); } } } if (db::setting.multiNetScheduleReverse) { reverse(batches.begin(), batches.end()); } return batches; } vector> &Scheduler::scheduleOrderEq() { vector routerIds; for (int id = 0; id < routers.size(); ++id) routerIds.push_back(id); if (db::setting.numThreads == 0) { // simple case for (int routerId : routerIds) batches.push_back({routerId}); } else { // normal case vector assigned(routers.size(), false); int lastUnroute = 0; while (lastUnroute < routerIds.size()) { // create a new batch from a seed batches.emplace_back(); initSet({}); vector &batch = batches.back(); int lastMetric = INT_MAX; // Note: need to be change if sort metric changes for (int i = lastUnroute; i < routerIds.size(); i++) { int routerId = routerIds[i]; if (assigned[routerId]) continue; int metric = routers[routerId].grNet.boundingBox.hp(); if (metric > lastMetric) break; if (hasConflict(routerId)) { lastMetric = metric; } else { batch.push_back(routerId); assigned[routerId] = true; updateSet(routerId); } } // find the next seed while (lastUnroute < routerIds.size() && assigned[routerIds[lastUnroute]]) { ++lastUnroute; } } } return batches; } void Scheduler::initSet(vector jobIdxes) { rtrees = RTrees(database.getLayerNum()); for (int jobIdx : jobIdxes) { updateSet(jobIdx); } } void Scheduler::updateSet(int jobIdx) { for (const auto &guide : routers[jobIdx].guides) { boostBox box(boostPoint(guide[X].low, guide[Y].low), boostPoint(guide[X].high, guide[Y].high)); rtrees[guide.layerIdx].insert({box, jobIdx}); } } bool Scheduler::hasConflict(int jobIdx) { for (const auto &guide : routers[jobIdx].guides) { boostBox box(boostPoint(guide[X].low, guide[Y].low), boostPoint(guide[X].high, guide[Y].high)); std::vector> results; rtrees[guide.layerIdx].query(bgi::intersects(box), std::back_inserter(results)); for (const auto &result : results) { if (result.second != jobIdx) { return true; } } } return false; } ================================================ FILE: src/multi_net/Scheduler.h ================================================ #pragma once #include "single_net/SingleNetRouter.h" class Scheduler { public: Scheduler(const vector& routersToExec) : routers(routersToExec){}; vector>& schedule(); vector>& scheduleOrderEq(); private: const vector& routers; vector> batches; // for conflict detect RTrees rtrees; void initSet(vector jobIdxes); void updateSet(int jobIdx); bool hasConflict(int jobIdx); }; ================================================ FILE: src/single_net/GenGuide.cpp ================================================ #include "GenGuide.h" GuideGeneratorStat guideGenStat; void GuideGenerator::sliceGuides(vector &guides, bool mergeAdj) { vector> tmpGuides(database.getLayerNum()); // route guides on different layers for (auto &guide : guides) { tmpGuides[guide.layerIdx].push_back(guide); } guides.clear(); for (int layerIdx = 0; layerIdx < database.getLayerNum(); ++layerIdx) { gr::GrBoxOnLayer::sliceGrPolygons(tmpGuides[layerIdx], mergeAdj); for (auto &guide : tmpGuides[layerIdx]) guides.push_back(guide); } } void GuideGenerator::genConnGuides() { // keep connectivity for (auto &point : grNet.ovlpPoints) { grNet.viaRouteGuides.emplace_back( point.layerIdx, utils::IntervalT(point[X], point[X]), utils::IntervalT(point[Y], point[Y])); if (point.layerIdx + 1 < database.getLayerNum()) grNet.viaRouteGuides.emplace_back(point.layerIdx + 1, utils::IntervalT(point[X], point[X]), utils::IntervalT(point[Y], point[Y])); if (point.layerIdx - 1 >= 0) grNet.viaRouteGuides.emplace_back(point.layerIdx - 1, utils::IntervalT(point[X], point[X]), utils::IntervalT(point[Y], point[Y])); } } void GuideGenerator::patchPinRegions() { double patchThresh = 2.0; // check if the region allows patching auto needPatch = [&](gr::GrPoint point) { return grDatabase.getCellUsage(point) < patchThresh; }; // get surrounding gcells of a point (normally 3 x 3, but will be different at boudary) auto getSurrounding = [&](gr::GrPoint point) { gr::GrBoxOnLayer box; box.layerIdx = point.layerIdx; box.x.low = max(point.x - 1, 0); box.y.low = max(point.y - 1, 0); box.x.high = min(point.x + 1, grDatabase.getNumGrPoint(X) - 1); box.y.high = min(point.y + 1, grDatabase.getNumGrPoint(Y) - 1); return box; }; for (auto &pbxs : grNet.pinAccessBoxes) { for (auto &pbx : pbxs) { bool patched = false; // patch upper two layers if (pbx.layerIdx < database.getLayerNum() - 2) { guideGenStat.pinRegionPatchCand++; auto bxPlus1 = gr::GrPoint(pbx.layerIdx + 1, pbx.x, pbx.y); auto bxPlus2 = gr::GrPoint(pbx.layerIdx + 2, pbx.x, pbx.y); if (needPatch(bxPlus1) || needPatch(bxPlus2)) { patched = true; guideGenStat.pinRegionPatchNum++; grNet.patchRouteGuides.emplace_back(getSurrounding(bxPlus1)); grNet.patchRouteGuides.emplace_back(getSurrounding(bxPlus2)); } else { grNet.patchRouteGuides.emplace_back(gr::GrBoxOnLayer(bxPlus1.layerIdx, {pbx.x}, {pbx.y})); grNet.patchRouteGuides.emplace_back(gr::GrBoxOnLayer(bxPlus2.layerIdx, {pbx.x}, {pbx.y})); } } // patch lower two layers if (pbx.layerIdx > 1) { guideGenStat.pinRegionPatchCand++; auto bxMinus1 = gr::GrPoint(pbx.layerIdx - 1, pbx.x, pbx.y); auto bxMinus2 = gr::GrPoint(pbx.layerIdx - 2, pbx.x, pbx.y); if (needPatch(bxMinus1) || needPatch(bxMinus2)) { patched = true; guideGenStat.pinRegionPatchNum++; grNet.patchRouteGuides.emplace_back(getSurrounding(bxMinus1)); grNet.patchRouteGuides.emplace_back(getSurrounding(bxMinus2)); } else { grNet.patchRouteGuides.emplace_back(gr::GrBoxOnLayer(bxMinus1.layerIdx, {pbx.x}, {pbx.y})); grNet.patchRouteGuides.emplace_back(gr::GrBoxOnLayer(bxMinus2.layerIdx, {pbx.x}, {pbx.y})); } } // patch original layer if (patched) { grNet.patchRouteGuides.emplace_back(getSurrounding(pbx)); } else { grNet.patchRouteGuides.emplace_back(gr::GrBoxOnLayer(pbx.layerIdx, {pbx.x}, {pbx.y})); } } } } void GuideGenerator::patchLongSegments() { // Note: assuming all guides are single width const int patchIntvl = 5; // min patch interval const double patchThresh = 1.0; for (const auto &guide : grNet.wireRouteGuides) { int layerIdx = guide.layerIdx; auto dir = database.getLayerDir(layerIdx); int offset = grNet.dbNet.idx % patchIntvl; for (int cp = guide[1 - dir].low + offset; cp <= guide[1 - dir].high;) { int x = dir == X ? guide[dir].low : cp; int y = dir == X ? cp : guide[dir].low; if (grDatabase.getCellUsage({layerIdx, x, y}) < patchThresh) { bool patched = false; for (int layer_delta = -1; layer_delta <= 1; layer_delta += 2) { int layer = layerIdx + layer_delta; if (layer < 1 || layer >= database.getLayerNum()) continue; if (grDatabase.getCellUsage({layer, x, y}) > patchThresh) { grNet.patchRouteGuides.emplace_back(gr::GrBoxOnLayer(layer, {x}, {y})); guideGenStat.longSegmentPatchNum++; patched = true; } } if (patched) { cp += patchIntvl; } else { cp++; } } else { cp++; } } } } void GuideGenerator::patchVioCells() { // Note: assuming all guides are single width const int queryWidth = 1; for (const auto &guide : grNet.wireRouteGuides) { int layerIdx = guide.layerIdx; auto dir = database.getLayerDir(layerIdx); int gridline = guide[dir].low; for (int cp = guide[1 - dir].low; cp <= guide[1 - dir].high; cp++) { int x = dir == X ? gridline : cp; int y = dir == X ? cp : gridline; double cellUsage = grDatabase.getCellUsage({layerIdx, x, y}); if (cellUsage <= 0) { guideGenStat.vioCellNum++; gr::GrBoxOnLayer patch(layerIdx, utils::IntervalT(x), utils::IntervalT(y)); for (int g = gridline - queryWidth; g <= gridline + queryWidth; g++) { if (g < 0 || g >= grDatabase.getNumGrPoint(dir)) continue; double curCellUsage = dir == X ? grDatabase.getCellUsage({layerIdx, g, y}) : grDatabase.getCellUsage({layerIdx, x, g}); if (curCellUsage <= 0) continue; cellUsage += curCellUsage; patch[dir].Update(g); } if (cellUsage > 0) { const vector layers = {layerIdx + 1, layerIdx - 1}; for (auto l : layers) { if (l >= database.getLayerNum() || l <= 1) continue; bool vioFree = true; for (int x = patch.lx(); x <= patch.hx() && vioFree; x++) for (int y = patch.ly(); y <= patch.hy() && vioFree; y++) if (grDatabase.getCellUsage({l, x, y}) <= 0) vioFree = false; if (vioFree) { grNet.patchRouteGuides.push_back(patch); grNet.patchRouteGuides.emplace_back(l, patch[X], patch[Y]); guideGenStat.vioCellPatchNum++; break; } } } } } } } void GuideGenerator::genPatchGuides() { grNet.patchRouteGuides.clear(); patchPinRegions(); patchLongSegments(); patchVioCells(); } void GuideGenerator::genTopoGuides() { grNet.wireRouteGuides.clear(); grNet.viaRouteGuides.clear(); genConnGuides(); // Note: generate guides by topology grNet.postOrderVisitGridTopo([&](std::shared_ptr node) { auto parent = node; for (auto child : parent->children) { if (parent->layerIdx == child->layerIdx) { std::shared_ptr lower, upper; if ((*parent)[X] < (*child)[X] || (*parent)[Y] < (*child)[Y]) { lower = parent; upper = child; } else { lower = child; upper = parent; } grNet.wireRouteGuides.emplace_back(lower->layerIdx, utils::IntervalT((*lower)[X], (*upper)[X]), utils::IntervalT((*lower)[Y], (*upper)[Y])); } else { grNet.viaRouteGuides.emplace_back(parent->layerIdx, utils::IntervalT((*parent)[X], (*parent)[X]), utils::IntervalT((*parent)[Y], (*parent)[Y])); grNet.viaRouteGuides.emplace_back(child->layerIdx, utils::IntervalT((*child)[X], (*child)[X]), utils::IntervalT((*child)[Y], (*child)[Y])); } } }); sliceGuides(grNet.wireRouteGuides); sliceGuides(grNet.viaRouteGuides); } ================================================ FILE: src/single_net/GenGuide.h ================================================ #pragma once #include "gr_db/GrDatabase.h" class GuideGenerator { public: GuideGenerator(gr::GrNet& grNetData) : grNet(grNetData) {} void genTopoGuides(); void genPatchGuides(); static void sliceGuides(vector& guides, bool mergeAdj = false); private: gr::GrNet& grNet; void genConnGuides(); void patchPinRegions(); void patchLongSegments(); void patchVioCells(); }; class GuideGeneratorStat { public: int longSegmentPatchNum; int vioCellNum; int vioCellPatchNum; int pinRegionPatchCand; int pinRegionPatchNum; void reset() { longSegmentPatchNum = 0; vioCellNum = 0; vioCellPatchNum = 0; } void print() { log() << "Add pin region patches. Totally " << pinRegionPatchNum << "/" << pinRegionPatchCand << " patches are added." << std::endl; log() << "Add long segment patches. Totally " << longSegmentPatchNum << " patches are added." << std::endl; printflog("Add cong cell patches. Totally %d/%d patches are added\n", vioCellPatchNum, vioCellNum); } }; extern GuideGeneratorStat guideGenStat; ================================================ FILE: src/single_net/GridGraph.cpp ================================================ #include "GridGraph.h" #include "global.h" #include "GenGuide.h" void GridGraph::init(int nNodes) { conn.resize(nNodes, {-1, -1, -1, -1}); edgeCost.resize(nNodes, {-1, -1, -1, -1}); edgeCount = 0; } void GridGraph::addEdge(int u, int v, EdgeDirection dir, db::CostT w) { if (hasEdge(u, dir)) return; edgeCost[u][dir] = edgeCost[v][getOppDir(dir)] = w; conn[u][dir] = v; conn[v][oppDirections[dir]] = u; edgeCount++; } void GridGraph::writeDebugFile(const std::string &fn) const { std::ofstream debugFile(fn); for (int i = 0; i < conn.size(); ++i) { debugFile << i << " " << vertexToPoint[i] << " edgeC=" << edgeCost[i] << " conn=" << conn[i] << std::endl; } } bool GridGraph::checkConn() const { auto BFS = [&](int s, vector &visited) { std::queue q; visited[s] = true; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); for (auto v : conn[u]) { if (v != -1 && !visited[v]) { visited[v] = true; q.push(v); } } } }; vector visited(conn.size(), false); BFS(0, visited); for (int i = 0; i < visited.size(); i++) if (!visited[i]) return false; return true; } bool switchLayer(EdgeDirection direction) { return direction == UP || direction == DOWN; } EdgeDirection getOppDir(EdgeDirection direction) { return oppDirections[direction]; } void CoarseGridGraphBuilder::run(const vector> &mergedPinAccessBoxes) { numPointsX = ceil(grDatabase.getNumGrPoint(X) / (double)cellWidth); numPointsY = ceil(grDatabase.getNumGrPoint(Y) / (double)cellHeight); int numPoints = numPointsX * numPointsY * database.getLayerNum(); // 1. Give each grid point an index graph.vertexToPoint.reserve(numPoints); for (int l = 0; l < database.getLayerNum(); l++) for (int x = 0; x < numPointsX; x++) for (int y = 0; y < numPointsY; y++) graph.vertexToPoint.emplace_back(l, x, y); // 2. Add vertex-pin connection graph.pinToVertex.resize(mergedPinAccessBoxes.size()); for (unsigned p = 0; p < mergedPinAccessBoxes.size(); p++) { for (const auto &point : mergedPinAccessBoxes[p]) { int u = pointToVertex(point); graph.pinToVertex[p].push_back(u); graph.vertexToPin[u] = p; } } graph.init(numPoints); // 3. Add inter-layer connection for (int l = 0; l < database.getLayerNum() - 1; l++) { int lowerBias = numPointsX * numPointsY * l; int upperBias = numPointsX * numPointsY * (l + 1); for (int x = 0; x < numPointsX; x++) { int bias = numPointsY * x; for (int y = 0; y < numPointsY; y++) { int u = lowerBias + bias + y; int v = upperBias + bias + y; graph.addEdge(u, v, UP, congMap.getCrsnViaCost({l, x, y})); } } } // 4. add intra-layer connection for (int l = 0; l < database.getLayerNum(); l++) { int layerBias = numPointsX * numPointsY * l; if (database.getLayerDir(l) == X) { for (int x = 0; x < numPointsX; x++) { int bias = numPointsY * x; for (int y = 0; y < numPointsY - 1; y++) { int u = layerBias + bias + y; int v = layerBias + bias + y + 1; graph.addEdge(u, v, FORWARD, congMap.getCrsnEdgeCost({l, x, y}, {l, x, y + 1})); } } } else { for (int x = 0; x < numPointsX - 1; x++) { int bias = numPointsY * x; for (int y = 0; y < numPointsY; y++) { int u = layerBias + bias + y; int v = layerBias + bias + y + numPointsY; graph.addEdge(u, v, FORWARD, congMap.getCrsnEdgeCost({l, x, y}, {l, x + 1, y})); } } } } } int CoarseGridGraphBuilder::pointToVertex(const gr::PointOnLayer &point) const { return numPointsX * numPointsY * point.layerIdx + numPointsY * point[X] + point[Y]; } gr::PointOnLayer CoarseGridGraphBuilder::grPointToPoint(const gr::GrPoint &point) const { return congMap.grPointToPoint(point); } double CoarseGridGraphBuilder::getCost(int u, int v) { return 0; } void GuideGridGraphBuilder::run(const vector> &mergedPinAccessBoxes) { // 0. slice guides by their prefer direction GuideGenerator::sliceGuides(guides); // 1. Give each grid point an index for (auto &box : guides) { int begin = intervals.empty() ? 0 : intervals.back().second; int end = begin + (box[X].range() + 1) * (box[Y].range() + 1); intervals.emplace_back(begin, end); } graph.vertexToPoint.reserve(intervals.back().second); for (auto &box : guides) { auto dir = database.getLayerDir(box.layerIdx); for (int gridline = box[dir].low; gridline <= box[dir].high; gridline++) { for (int cp = box[1 - dir].low; cp <= box[1 - dir].high; cp++) { if (dir == X) graph.vertexToPoint.emplace_back(box.layerIdx, gridline, cp); else graph.vertexToPoint.emplace_back(box.layerIdx, cp, gridline); } } } // 2. Add guide-pin connection graph.pinToVertex.resize(mergedPinAccessBoxes.size()); for (unsigned p = 0; p < mergedPinAccessBoxes.size(); p++) { for (const auto &point : mergedPinAccessBoxes[p]) { auto dir = database.getLayerDir(point.layerIdx); for (unsigned g = 0; g < guides.size(); g++) { if (guides[g].includePoint({point.layerIdx, point[X], point[Y]})) { int u = guideToVertex(g, point[dir], point[1 - dir]); graph.pinToVertex[p].push_back(u); graph.vertexToPin[u] = p; } } } } graph.init(intervals.back().second); // 3. Add inter-guide connection for (unsigned b1 = 0; b1 < guides.size(); b1++) { for (unsigned b2 = b1 + 1; b2 < guides.size(); b2++) if (guides[b1][X].HasIntersectWith(guides[b2][X]) && guides[b1][Y].HasIntersectWith(guides[b2][Y]) && abs(guides[b1].layerIdx - guides[b2].layerIdx) <= 1) connectTwoGuides(b1, b2); } // 4. add intra-guide connection for (unsigned b = 0; b < guides.size(); b++) connectGuide(b); } void GuideGridGraphBuilder::connectGuide(int guideIdx) { const auto &box = guides[guideIdx]; int layerIdx = box.layerIdx; auto dir = database.getLayerDir(layerIdx); const auto &gridlineRange = box[dir]; const auto &cpRange = box[1 - dir]; int netIdx = grNet.dbNet.idx; auto setEdgeCost = [&](int gridline, int beginCP, int endCP) { if (beginCP == endCP) return; int u = guideToVertex(guideIdx, gridline, beginCP); int v = guideToVertex(guideIdx, gridline, endCP); gr::GrPoint point1(layerIdx, dir == X ? gridline : beginCP, dir == X ? beginCP : gridline); gr::GrPoint point2(layerIdx, dir == X ? gridline : endCP, dir == X ? endCP : gridline); db::CostT cost = grDatabase.getWireCost({point1, point2}); graph.addEdge(u, v, FORWARD, cost); }; auto canRemove = [&](int gridline, int cp) { int vertexIdx = guideToVertex(guideIdx, gridline, cp); return !graph.hasEdge(vertexIdx, UP) && !graph.hasEdge(vertexIdx, DOWN) && graph.getPinIdx(vertexIdx) == -1 && cp != cpRange.low && cp != cpRange.high; }; if (cpRange.range() == 0) return; for (int g = gridlineRange.low; g <= gridlineRange.high; g++) { // get the directIntervals vector> directIntervals; int begin = -1, end = -1; for (int c = cpRange.low; c <= cpRange.high; c++) { if (begin == -1) { if (canRemove(g, c)) begin = c - 1; } else { if (!canRemove(g, c)) { end = c; directIntervals.emplace_back(begin, end); begin = -1; end = -1; } } } // get the indirectIntervals vector> indirectIntervals; if (directIntervals.empty()) { indirectIntervals.push_back(cpRange); } else { indirectIntervals.emplace_back(cpRange.low, directIntervals.begin()->low); for (int i = 0; i + 1 < directIntervals.size(); i++) { indirectIntervals.emplace_back(directIntervals[i].high, directIntervals[i + 1].low); } indirectIntervals.emplace_back(directIntervals.rbegin()->high, cpRange.high); } // connect the intervals for (auto &interval : directIntervals) setEdgeCost(g, interval.low, interval.high); for (auto &interval : indirectIntervals) for (int c = interval.low; c + 1 <= interval.high; c++) setEdgeCost(g, c, c + 1); } } void GuideGridGraphBuilder::connectTwoGuides(int guideIdx1, int guideIdx2) { const auto &box1 = guides[guideIdx1]; const auto &box2 = guides[guideIdx2]; int upperIdx = box1.layerIdx > box2.layerIdx ? guideIdx1 : guideIdx2; int lowerIdx = box1.layerIdx < box2.layerIdx ? guideIdx1 : guideIdx2; auto lowerDir = database.getLayerDir(guides[lowerIdx].layerIdx); auto lowerGridLineIntvl = guides[lowerIdx][lowerDir].IntersectWith(guides[upperIdx][lowerDir]); auto lowerCPIntvl = guides[lowerIdx][1 - lowerDir].IntersectWith(guides[upperIdx][1 - lowerDir]); for (int lowerGridLine = lowerGridLineIntvl.low; lowerGridLine <= lowerGridLineIntvl.high; lowerGridLine++) { for (int lowerCPIdx = lowerCPIntvl.low; lowerCPIdx <= lowerCPIntvl.high; lowerCPIdx++) { int u = guideToVertex(upperIdx, lowerCPIdx, lowerGridLine); int v = guideToVertex(lowerIdx, lowerGridLine, lowerCPIdx); db::CostT cost = grDatabase.getViaCost({guides[lowerIdx].layerIdx, lowerDir == X ? lowerGridLine : lowerCPIdx, lowerDir == X ? lowerCPIdx : lowerGridLine}); graph.addEdge(u, v, DOWN, cost); } } } int GuideGridGraphBuilder::guideToVertex(int gIdx, int gridline, int cp) const { const auto &box = guides[gIdx]; int pointBias = intervals[gIdx].first; return boxToVertex(box, pointBias, gridline, cp); } int GuideGridGraphBuilder::boxToVertex(const gr::GrBoxOnLayer &box, int pointBias, int gridline, int cp) const { auto dir = database.getLayerDir(box.layerIdx); return pointBias + (gridline - box[dir].low) * (box[1 - dir].range() + 1) + (cp - box[1 - dir].low); } ================================================ FILE: src/single_net/GridGraph.h ================================================ #pragma once #include "global.h" #include "db/Database.h" #include "gr_db/GrDatabase.h" #include "multi_net/CongestionMap.h" enum EdgeDirection { BACKWARD = 0, FORWARD = 1, UP = 2, DOWN = 3 }; const vector directions = {BACKWARD, FORWARD, UP, DOWN}; const vector oppDirections = {FORWARD, BACKWARD, DOWN, UP}; bool switchLayer(EdgeDirection direction); EdgeDirection getOppDir(EdgeDirection direction); class GuideGridGraphBuilder; class CoarseGridGraphBuilder; // Note: GridGraph will be across both GridGraphBuilder & MazeRoute class GridGraph { public: friend GuideGridGraphBuilder; friend CoarseGridGraphBuilder; // getters bool hasEdge(int u, EdgeDirection dir) const { return conn[u][dir] != -1; } int getEdgeEndPoint(int u, EdgeDirection dir) const { return conn[u][dir]; } db::CostT getEdgeCost(int u, EdgeDirection dir) const { return edgeCost[u][dir]; } gr::PointOnLayer& getPoint(int u) { return vertexToPoint[u]; } int getEdgeNum() const { return edgeCount; } int getNodeNum() const { return conn.size(); } int getPinIdx(int u) const { auto it = vertexToPin.find(u); return (it != vertexToPin.end()) ? it->second : -1; } vector& getVertices(int pinIdx) { return pinToVertex[pinIdx]; } void writeDebugFile(const std::string& fn) const; bool checkConn() const; private: int edgeCount; // vertex properties std::unordered_map vertexToPin; // vertexIdx to pinIdx vector> pinToVertex; vector vertexToPoint; // adj lists vector> conn; vector> edgeCost; // setters void init(int nNodes); void addEdge(int u, int v, EdgeDirection dir, db::CostT w); }; class GridGraphBuilderBase { public: GridGraphBuilderBase(gr::GrNet& grNetData, GridGraph& graphData) : grNet(grNetData), graph(graphData){}; virtual void run(const vector>& mergedPinAccessBoxes) = 0; protected: gr::GrNet& grNet; GridGraph& graph; }; class GuideGridGraphBuilder : public GridGraphBuilderBase { public: GuideGridGraphBuilder(gr::GrNet& grNetData, GridGraph& graphData, const vector& guidesData) : GridGraphBuilderBase(grNetData, graphData), guides(guidesData) {} virtual void run(const vector>& mergedPinAccessBoxes); private: vector guides; vector> intervals; void connectGuide(int guideIdx); void connectTwoGuides(int guideIdx1, int guideIdx2); int guideToVertex(int gIdx, int x, int y) const; int boxToVertex(const gr::GrBoxOnLayer& box, int pointBias, int x, int y) const; }; class CoarseGridGraphBuilder : public GridGraphBuilderBase { public: CoarseGridGraphBuilder(gr::GrNet& grNetData, GridGraph& graphData, const CongestionMap& congMapData) : GridGraphBuilderBase(grNetData, graphData), congMap(congMapData), cellWidth(congMap.getCellWidth()), cellHeight(congMap.getCellHeight()) {} virtual void run(const vector>& mergedPinAccessBoxes); gr::PointOnLayer grPointToPoint(const gr::GrPoint& point) const; private: const CongestionMap& congMap; int cellWidth; int cellHeight; int numPointsX; int numPointsY; int pointToVertex(const gr::PointOnLayer& point) const; double getCost(int u, int v); }; ================================================ FILE: src/single_net/InitRoute.cpp ================================================ #include "InitRoute.h" using namespace std; mutex fluteMutex; struct hash_tuple { // hash binary tuple template size_t operator()(const tuple& tup) const { auto hash1 = hash{}(get<0>(tup)); auto hash2 = hash{}(get<1>(tup)); return hash1 ^ hash2; } }; void InitRoute::runFlute() { // get net center // float net_ctrz = 0; float net_ctrx = 0; float net_ctry = 0; for (auto& pinBoxes : grNet.pinAccessBoxes) { // float pin_ctrz = 0; float pin_ctrx = 0; float pin_ctry = 0; for (auto& pinBox : pinBoxes) { pin_ctrx += pinBox.x; pin_ctry += pinBox.y; } pin_ctrx /= pinBoxes.size(); pin_ctry /= pinBoxes.size(); net_ctrx += pin_ctrx; net_ctry += pin_ctry; } net_ctrx /= grNet.pinAccessBoxes.size(); net_ctry /= grNet.pinAccessBoxes.size(); // get pin center vector> pinCenters; for (auto& pinBoxes : grNet.pinAccessBoxes) { float xCenter = 0; float yCenter = 0; for (auto& pinBox : pinBoxes) { xCenter += pinBox.x; yCenter += pinBox.y; } xCenter /= pinBoxes.size(); yCenter /= pinBoxes.size(); // 3 kinds of accessibility (0) totally vio-free (1) one side vio-free (2) no side vio-free float min_dist[3]; min_dist[0] = min_dist[1] = min_dist[2] = numeric_limits::max(); int best_box[3] = {-1, -1, -1}; for (int pb = 0; pb < pinBoxes.size(); pb++) { // check pin box's accessibility auto& pb_x = pinBoxes[pb].x; auto& pb_y = pinBoxes[pb].y; int layer_idx = pinBoxes[pb].layerIdx; int is_x = database.getLayerDir(layer_idx) == X ? 1 : 0; auto low_edge = gr::GrEdge({layer_idx, max(pb_x - (1 - is_x), 0), max(pb_y - is_x, 0)}, {layer_idx, pb_x, pb_y}); auto high_edge = gr::GrEdge({layer_idx, pb_x, pb_y}, {layer_idx, min(pb_x + (1 - is_x), grDatabase.getNumGrPoint(X) - 1), min(pb_y + is_x, grDatabase.getNumGrPoint(Y) - 1)}); int pb_access = 0; pb_access += int(grDatabase.hasVio(low_edge, false)); pb_access += int(grDatabase.hasVio(high_edge, false)); float dist = abs(pinBoxes[pb].x - net_ctrx) + abs(pinBoxes[pb].y - net_ctrx); if (dist < min_dist[pb_access]) { min_dist[pb_access] = dist; best_box[pb_access] = pb; } } for (int ac = 0; ac < 3; ac++) { if (best_box[ac] != -1) { pinCenters.emplace_back(make_tuple(pinBoxes[best_box[ac]].x, pinBoxes[best_box[ac]].y)); break; } } } // location to pins unordered_map, vector, hash_tuple> loc2Pins; for (int i = 0; i < pinCenters.size(); i++) { loc2Pins[pinCenters[i]].emplace_back(i); } // flute int degree = loc2Pins.size(); int xs[100 * degree]; int ys[100 * degree]; int pt_cnt = 0; int node_cnt = 0; // if (loc2Pins.size() > MAX_DEGREE) { // log() << "Warning: Net degree larger than MAXD(flute)" << endl; // } for (auto& loc2pin : loc2Pins) { const tuple& loc = loc2pin.first; xs[pt_cnt] = get<0>(loc); ys[pt_cnt] = get<1>(loc); pt_cnt++; } if (degree >= 2) { fluteMutex.lock(); Tree flutetree = flute(degree, xs, ys, ACCURACY); fluteMutex.unlock(); unordered_map, int, hash_tuple> loc2Node; // location -> RouteNode index for (int i = 0; i < degree * 2 - 2; i++) { Branch& branch1 = flutetree.branch[i]; Branch& branch2 = flutetree.branch[branch1.n]; tuple fluteEdge[2]; fluteEdge[0] = make_tuple(branch1.x, branch1.y); fluteEdge[1] = make_tuple(branch2.x, branch2.y); // create route nodes for (int j = 0; j < 2; j++) { tuple& nodeLoc = fluteEdge[j]; if (loc2Node.find(nodeLoc) == loc2Node.end()) { RouteNode node(fluteEdge[j]); // pin info if (loc2Pins.find(nodeLoc) != loc2Pins.end()) { node.pinIdxs = loc2Pins[nodeLoc]; for (int pIdx : node.pinIdxs) { int layerIdx = grNet.pinAccessBoxes[pIdx][0].layerIdx; node.pinLayers.emplace_back(layerIdx); // for (auto& box: grNet.pinAccessBoxes[pIdx]) { // if (box.layerIdx != layerIdx) { // log() << "Error: Pin across layers spotted" << endl; // } // } } } node.idx = node_cnt; routeNodes[node_cnt++] = node; loc2Node[nodeLoc] = routeNodes.size() - 1; } } // add connectivity info if (fluteEdge[0] != fluteEdge[1]) { int nodeIdx1 = loc2Node[fluteEdge[0]]; int nodeIdx2 = loc2Node[fluteEdge[1]]; routeNodes[nodeIdx1].toConnect.insert(nodeIdx2); routeNodes[nodeIdx2].toConnect.insert(nodeIdx1); } } } else if (degree == 1) { auto nodeLoc = make_tuple(xs[0], ys[0]); RouteNode node(nodeLoc); if (loc2Pins.find(nodeLoc) != loc2Pins.end()) { node.pinIdxs = loc2Pins[nodeLoc]; for (int pIdx : node.pinIdxs) { int layerIdx = grNet.pinAccessBoxes[pIdx][0].layerIdx; node.pinLayers.emplace_back(layerIdx); } } else { log() << "Error: loc2Pins is empty." << std::endl; } node.idx = node_cnt; routeNodes[node_cnt++] = node; return; } else { log() << "Error: degree = 0." << std::endl; } } void InitRoute::patternRoute() { int layer_cnt = database.getLayerNum(); for (auto& edge : routeEdges) { auto& fromNode = routeNodes[edge.from]; auto& toNode = routeNodes[edge.to]; // Initialize fromNode's exitCosts fromNode.exitCosts.resize(layer_cnt, numeric_limits::max()); int lowest_pin = layer_cnt; int highest_pin = -1; for (int pin_layer : fromNode.pinLayers) { lowest_pin = min(lowest_pin, pin_layer); highest_pin = max(highest_pin, pin_layer); } if (fromNode.childIdxs.size() == 0) { // no children nodes, only via costs for (int layer_idx = 0; layer_idx < layer_cnt; layer_idx++) { int lowest_layer = min(lowest_pin, layer_idx); int highest_layer = max(highest_pin, layer_idx); db::CostT exit_cost = grDatabase.getStackViaCost(gr::GrPoint(lowest_layer, fromNode.x, fromNode.y), highest_layer - lowest_layer); fromNode.exitCosts[layer_idx] = exit_cost; } } else { // initialize exitEnterLayers map for (int child_idx : fromNode.childIdxs) { fromNode.exitEnterLayers[child_idx] = vector(layer_cnt, -1); } // enumerate all children layer combinations int num_children = fromNode.childIdxs.size(); for (int enum_idx = 0; enum_idx < pow(layer_cnt, num_children); enum_idx++) { vector enum_vec; int e_idx = enum_idx; for (int en = 0; en < num_children; en++) { enum_vec.emplace_back(e_idx % layer_cnt); e_idx /= layer_cnt; } db::CostT prev_cost = 0; for (int c = 0; c < num_children; c++) { int child_idx = fromNode.childIdxs[c]; prev_cost += fromNode.enterCosts[child_idx][enum_vec[c]]; } int highest_layer = highest_pin; int lowest_layer = lowest_pin; for (int e_layer : enum_vec) { highest_layer = max(highest_layer, e_layer); lowest_layer = min(lowest_layer, e_layer); } for (int layer_idx = 0; layer_idx < layer_cnt; layer_idx++) { int via_bottom = min(lowest_layer, layer_idx); int via_height = max(highest_layer, layer_idx) - via_bottom; db::CostT via_cost = grDatabase.getStackViaCost(gr::GrPoint(via_bottom, fromNode.x, fromNode.y), via_height); db::CostT cost = prev_cost + via_cost; if (cost < fromNode.exitCosts[layer_idx]) { fromNode.exitCosts[layer_idx] = cost; for (int c = 0; c < num_children; c++) { fromNode.exitEnterLayers[fromNode.childIdxs[c]][layer_idx] = enum_vec[c]; } } } } } // Patterns LShape(edge); } } db::CostT InitRoute::getBufferedWireCost(gr::GrEdge edge) { if (wireCostBuffer.find(edge) != wireCostBuffer.end()) { return wireCostBuffer[edge]; } else { auto wireCost = grDatabase.getWireCost(edge); wireCostBuffer[edge] = wireCost; return wireCost; } } void InitRoute::LShape(const RouteEdge& edge) { int layer_cnt = database.getLayerNum(); auto& fromNode = routeNodes[edge.from]; auto& toNode = routeNodes[edge.to]; vector enter_cost(layer_cnt, numeric_limits::max()); vector> enter_edges(layer_cnt); if (fromNode.x == toNode.x || fromNode.y == toNode.y) { // has no bending point bool dir = (fromNode.x == toNode.x ? X : Y); for (int layer = 0; layer < layer_cnt; layer++) { if (database.getLayerDir(layer) != dir) continue; gr::GrEdge gr_edge(gr::GrPoint(layer, fromNode.x, fromNode.y), gr::GrPoint(layer, toNode.x, toNode.y)); db::CostT edge_cost = grDatabase.getWireCost(gr_edge); db::CostT cost = fromNode.exitCosts[layer] + edge_cost; if (cost < enter_cost[layer]) { enter_cost[layer] = cost; vector edge_vec; edge_vec.emplace_back(gr::GrPoint(layer, fromNode.x, fromNode.y)); // edge_vec.emplace_back(gr::GrPoint(layer+1, fromNode.x, fromNode.y)); // additional // edge_vec.emplace_back(gr::GrPoint(layer, fromNode.x, fromNode.y)); // additional edge_vec.emplace_back(gr::GrPoint(layer, toNode.x, toNode.y)); // edge_vec.emplace_back(gr::GrPoint(layer, toNode.x, toNode.y)); // additional // edge_vec.emplace_back(gr::GrPoint(layer, toNode.x, toNode.y)); // additional enter_edges[layer] = move(edge_vec); } } } else { // has a bending point for (int to_layer = 0; to_layer < layer_cnt; to_layer++) { Dimension to_dir = database.getLayerDir(to_layer); int bend_x = -1; // bending point int bend_y = -1; if (to_dir == Y) { bend_x = fromNode.x; bend_y = toNode.y; } else { bend_x = toNode.x; bend_y = fromNode.y; } // to_layer edge cost gr::GrEdge to_gr_edge(gr::GrPoint(to_layer, bend_x, bend_y), gr::GrPoint(to_layer, toNode.x, toNode.y)); db::CostT to_edge_cost = grDatabase.getWireCost(to_gr_edge); db::CostT min_cost = numeric_limits::max(); int best_from_layer = -1; for (int from_layer = 0; from_layer < layer_cnt; from_layer++) { if (database.getLayerDir(from_layer) == to_dir) continue; // same routing direction // from_layer edge cost gr::GrEdge from_gr_edge(gr::GrPoint(from_layer, fromNode.x, fromNode.y), gr::GrPoint(from_layer, bend_x, bend_y)); db::CostT from_edge_cost = getBufferedWireCost(from_gr_edge); db::CostT bend_via_cost = grDatabase.getStackViaCost( gr::GrPoint(min(from_layer, to_layer), bend_x, bend_y), abs(to_layer - from_layer)); db::CostT cost = fromNode.exitCosts[from_layer] + from_edge_cost + bend_via_cost + to_edge_cost; if (cost < min_cost) { min_cost = cost; best_from_layer = from_layer; } } enter_cost[to_layer] = min_cost; vector edge_vec; edge_vec.emplace_back(gr::GrPoint(best_from_layer, fromNode.x, fromNode.y)); bool go_up = (best_from_layer < to_layer); for (int cur_layer = best_from_layer;;) { edge_vec.emplace_back(gr::GrPoint(cur_layer, bend_x, bend_y)); if (cur_layer == to_layer) break; cur_layer += (go_up ? 1 : -1); } // edge_vec.emplace_back(gr::GrPoint(best_from_layer, bend_x, bend_y)); // edge_vec.emplace_back(gr::GrPoint(to_layer, bend_x, bend_y)); edge_vec.emplace_back(gr::GrPoint(to_layer, toNode.x, toNode.y)); enter_edges[to_layer] = move(edge_vec); } } toNode.enterCosts[edge.from] = move(enter_cost); toNode.enterEdges[edge.from] = move(enter_edges); } void InitRoute::buildTopo() { int layer_cnt = database.getLayerNum(); int rootIdx = -1; int root_enter_layer = -1; // build topo tree if (routeEdges.size() > 0) { rootIdx = routeEdges[routeEdges.size() - 1].to; RouteNode& rootNode = routeNodes[rootIdx]; int highest_layer = -1; int lowest_layer = layer_cnt; for (int pin_layer : rootNode.pinLayers) { lowest_layer = min(lowest_layer, pin_layer); highest_layer = max(highest_layer, pin_layer); } // find min cost enter layer assert(rootNode.enterCosts.size() == 1); auto& enterCosts = rootNode.enterCosts.begin()->second; db::CostT min_cost = numeric_limits::max(); for (int layer_idx = 0; layer_idx < layer_cnt; layer_idx++) { db::CostT cost = enterCosts[layer_idx]; int via_bottom = min(lowest_layer, layer_idx); int via_height = max(highest_layer, layer_idx) - via_bottom; db::CostT via_cost = grDatabase.getStackViaCost(gr::GrPoint(via_bottom, rootNode.x, rootNode.y), via_height); cost += via_cost; // via cost if (cost < min_cost) { min_cost = cost; root_enter_layer = layer_idx; } } } else { // local net rootIdx = 0; root_enter_layer = routeNodes[rootIdx].pinLayers[0]; } // log() << "cost " << min_cost << endl; function(int, int)> buildTopo = [&](int root_idx, int exit_layer) { RouteNode& rNode = routeNodes[root_idx]; shared_ptr topo_root = make_shared(gr::GrPoint(exit_layer, rNode.x, rNode.y), -1); // build layer topo int low_layer = exit_layer; int high_layer = exit_layer; for (int child_idx : rNode.childIdxs) { int child_enter_layer = exit_layer; // root has no exit, thus no exitEnterLayers map, we use exit layer to // indicate its child's enter layer if (rNode.exitEnterLayers.size() > 0) { child_enter_layer = rNode.exitEnterLayers[child_idx][exit_layer]; } low_layer = min(low_layer, child_enter_layer); high_layer = max(high_layer, child_enter_layer); } for (int pin_layer : rNode.pinLayers) { if (pin_layer != exit_layer) { low_layer = min(low_layer, pin_layer); high_layer = max(high_layer, pin_layer); } } unordered_map> layer2layerTopo; layer2layerTopo[exit_layer] = topo_root; for (int cur_layer = exit_layer + 1; cur_layer <= high_layer; cur_layer++) { layer2layerTopo[cur_layer] = make_shared(gr::GrPoint(cur_layer, rNode.x, rNode.y), -1); gr::GrSteiner::setParent(layer2layerTopo[cur_layer], layer2layerTopo[cur_layer - 1]); } for (int cur_layer = exit_layer - 1; cur_layer >= low_layer; cur_layer--) { layer2layerTopo[cur_layer] = make_shared(gr::GrPoint(cur_layer, rNode.x, rNode.y), -1); gr::GrSteiner::setParent(layer2layerTopo[cur_layer], layer2layerTopo[cur_layer + 1]); } for (int child_idx : rNode.childIdxs) { // build branches int child_enter_layer = exit_layer; if (rNode.exitEnterLayers.size() > 0) { child_enter_layer = rNode.exitEnterLayers[child_idx][exit_layer]; } auto& enter_edge = rNode.enterEdges[child_idx][child_enter_layer]; if (enter_edge.size() == 0) { log() << "Error: Enter edge missing" << endl; } int child_exit_layer = enter_edge[0].layerIdx; shared_ptr child_topo = buildTopo(child_idx, child_exit_layer); for (auto& point : enter_edge) { shared_ptr steiner = make_shared(point, -1); gr::GrSteiner::setParent(child_topo, steiner); child_topo = steiner; } // if (gr::GrPoint(*child_topo) != gr::GrPoint(*topo_root)) { gr::GrSteiner::setParent(child_topo, layer2layerTopo[child_enter_layer]); // } else { // gr::GrSteiner::setParent(child_topo->children[0], topo_root); // } } return topo_root; }; // dumpTo grNet grNet.gridTopo.emplace_back(buildTopo(rootIdx, root_enter_layer)); gr::GrSteiner::removeRedundancy(grNet.gridTopo[0]); vector pin_locs; for (auto& kv : routeNodes) { auto& node = kv.second; for (int pin_layer : node.pinLayers) { // cout << "(" << pin_layer << "," << node.x << "," << node.y << ") "; pin_locs.emplace_back(gr::GrPoint(pin_layer, node.x, node.y)); } } // debug // cout << endl; // log() << endl; // grNet.preOrderVisitGridTopo([&](std::shared_ptr topo) { // if (topo->children.size() == 0) return; // log() << gr::GrPoint(*topo) << "->"; // for(auto& child: topo->children) { // cout << gr::GrPoint(*child) << " "; // } // cout << endl; // }); // log() << "cost " << min_cost << endl; // log() << endl << "+ + + + + + + + + + + + + + + + + + + + + +" << endl; // Check Connectivity and Mark Pins (0: no pin; 1: has pin) if (!gr::GrSteiner::checkConnectivity(grNet.gridTopo[0], pin_locs)) { log() << "Error: Connectivity check failed" << endl; } } void InitRoute::plan_fluteOnly() { runFlute(); int s = routeNodes.begin()->first; queue tmp_q; tmp_q.push(s); set vis; while (tmp_q.empty() == false) { int u = tmp_q.front(); tmp_q.pop(); vis.insert(u); RouteNode& node = routeNodes[u]; for (int nIdx : node.toConnect) { if (vis.find(nIdx) != vis.end()) continue; addUsage2D(node, routeNodes[nIdx], 1); // update the usage tmp_q.push(nIdx); } } } void InitRoute::edge_shift2d(std::map& cur_routeNodes) { if (cur_routeNodes.size() == 1) return; vector edgeset; map, set> loc_nodes; // will be used to merge overlapping nodes int s = cur_routeNodes.begin()->first; queue tmp_q; tmp_q.push(s); set vis; while (tmp_q.empty() == false) { int u = tmp_q.front(); tmp_q.pop(); vis.insert(u); RouteNode& node = cur_routeNodes[u]; loc_nodes[make_pair(node.x, node.y)].insert(u); for (int nIdx : node.toConnect) { if (vis.find(nIdx) != vis.end()) continue; RouteEdge edge; edge.from = nIdx; edge.to = u; edgeset.emplace_back(edge); removeUsage2D(node, cur_routeNodes[nIdx], 1); // Remove this net tmp_q.push(nIdx); } } auto getStraightCost = [&](int dir, int gridline, utils::IntervalT range) { double cost = 0; for (int cp = range.low; cp < range.high; cp++) { cost += grDatabase.getCost2D(dir, gridline, cp); } return cost; }; std::function getCost = [&](int x1, int y1, int x2, int y2) { // GR point (x1,y1) -> (x2,y2) double ret = 0; int layer_dir_count = 0; if (x1 == x2 || y1 == y2) { // straight line int dir = (x1 == x2 ? X : Y); if (dir == X) { utils::IntervalT Range(min(y1, y2), max(y1, y2)); ret = getStraightCost(X, x1, Range); } else { utils::IntervalT Range(min(x1, x2), max(x1, x2)); ret = getStraightCost(Y, y1, Range); } } else { // choose the L with lower cost int x3 = x1; int y3 = y2; int x4 = x2; int y4 = y1; ret = min(getCost(x1, y1, x3, y3) + getCost(x2, y2, x3, y3), getCost(x1, y1, x4, y4) + getCost(x2, y2, x4, y4)); } return ret; }; auto shiftEdge = [&](bool& shifted) { int find_edge = -1; int dir = -1; bool extendSafeRange = false; for (int i = 0; i < edgeset.size(); i++) { auto& edge = edgeset[i]; auto& fromNode = cur_routeNodes[edge.from]; auto& toNode = cur_routeNodes[edge.to]; if (fromNode.pinIdxs.size() == 0 && toNode.pinIdxs.size() == 0 && fromNode.degree() == 3 && toNode.degree() == 3) { // two steiner points encountered,require the degree to be 3 if (fromNode.x == toNode.x || fromNode.y == toNode.y) { // vertical or horizontal dir = (fromNode.x == toNode.x ? X : Y); vector fromNeighbor; // the two neighbors of fromNode vector toNeighbor; // the two neighbors of toNode for (auto& nei : fromNode.toConnect) { if (nei != edge.to) { fromNeighbor.push_back(nei); } } for (auto& nei : toNode.toConnect) { if (nei != edge.from) { toNeighbor.push_back(nei); } } assert(fromNeighbor.size() == 2); assert(toNeighbor.size() == 2); if (dir == X) { // vertical edge if (cur_routeNodes[fromNeighbor[0]].x > cur_routeNodes[fromNeighbor[1]].x) { swap(fromNeighbor[0], fromNeighbor[1]); } if (cur_routeNodes[toNeighbor[0]].x > cur_routeNodes[toNeighbor[1]].x) { swap(toNeighbor[0], toNeighbor[1]); } utils::IntervalT r1(cur_routeNodes[fromNeighbor[0]].x, cur_routeNodes[fromNeighbor[1]].x); utils::IntervalT r2(cur_routeNodes[toNeighbor[0]].x, cur_routeNodes[toNeighbor[1]].x); utils::IntervalT safeRange = r1.IntersectWith(r2); if (!safeRange.IsStrictValid()) { continue; } utils::IntervalT yRange(min(fromNode.y, toNode.y), max(fromNode.y, toNode.y)); int best_x = -1; double best_cost = std::numeric_limits::infinity(); for (int cur_x = safeRange.low; cur_x <= safeRange.high; cur_x++) { // try each candidate and choose the one with smallest cost double cur_cost = getStraightCost(X, cur_x, yRange); cur_cost += getCost(cur_x, fromNode.y, cur_routeNodes[fromNeighbor[0]].x, cur_routeNodes[fromNeighbor[0]].y) + getCost(cur_x, fromNode.y, cur_routeNodes[fromNeighbor[1]].x, cur_routeNodes[fromNeighbor[1]].y); cur_cost += getCost( cur_x, toNode.y, cur_routeNodes[toNeighbor[0]].x, cur_routeNodes[toNeighbor[0]].y) + getCost( cur_x, toNode.y, cur_routeNodes[toNeighbor[1]].x, cur_routeNodes[toNeighbor[1]].y); if (cur_cost < best_cost) { best_cost = cur_cost; best_x = cur_x; } } if (best_x != -1 && fromNode.x != best_x) { // need to move, update the topology and locations loc_nodes[make_pair(fromNode.x, fromNode.y)].erase(fromNode.idx); loc_nodes[make_pair(toNode.x, toNode.y)].erase(toNode.idx); fromNode.x = best_x; toNode.x = best_x; loc_nodes[make_pair(fromNode.x, fromNode.y)].insert(fromNode.idx); loc_nodes[make_pair(toNode.x, toNode.y)].insert(toNode.idx); shifted = true; break; } else { // check next candidate continue; } } else { if (cur_routeNodes[fromNeighbor[0]].y > cur_routeNodes[fromNeighbor[1]].y) { swap(fromNeighbor[0], fromNeighbor[1]); } if (cur_routeNodes[toNeighbor[0]].y > cur_routeNodes[toNeighbor[1]].y) { swap(toNeighbor[0], toNeighbor[1]); } utils::IntervalT r1(cur_routeNodes[fromNeighbor[0]].y, cur_routeNodes[fromNeighbor[1]].y); utils::IntervalT r2(cur_routeNodes[toNeighbor[0]].y, cur_routeNodes[toNeighbor[1]].y); utils::IntervalT safeRange = r1.IntersectWith(r2); if (!safeRange.IsStrictValid()) { continue; } utils::IntervalT xRange(min(fromNode.x, toNode.x), max(fromNode.x, toNode.x)); int best_y = -1; double best_cost = std::numeric_limits::infinity(); for (int cur_y = safeRange.low; cur_y <= safeRange.high; cur_y++) { // try each candidate and choose the one with smallest cost double cur_cost = getStraightCost(Y, cur_y, xRange); cur_cost += getCost(fromNode.x, cur_y, cur_routeNodes[fromNeighbor[0]].x, cur_routeNodes[fromNeighbor[0]].y) + getCost(fromNode.x, cur_y, cur_routeNodes[fromNeighbor[1]].x, cur_routeNodes[fromNeighbor[1]].y); cur_cost += getCost( toNode.x, cur_y, cur_routeNodes[toNeighbor[0]].x, cur_routeNodes[toNeighbor[0]].y) + getCost( toNode.x, cur_y, cur_routeNodes[toNeighbor[1]].x, cur_routeNodes[toNeighbor[1]].y); if (cur_cost < best_cost) { best_cost = cur_cost; best_y = cur_y; } } if (best_y != -1 && fromNode.y != best_y) { // need to move, update the topology and locations loc_nodes[make_pair(fromNode.x, fromNode.y)].erase(fromNode.idx); loc_nodes[make_pair(toNode.x, toNode.y)].erase(toNode.idx); fromNode.y = best_y; toNode.y = best_y; loc_nodes[make_pair(fromNode.x, fromNode.y)].insert(fromNode.idx); loc_nodes[make_pair(toNode.x, toNode.y)].insert(toNode.idx); shifted = true; break; } else { // check next candidate continue; } } } } } }; auto mergeNode = [&]() { while (1) { bool found_to_merge = false; pair merge_loc; for (auto it = loc_nodes.begin(); it != loc_nodes.end(); it++) { if (it->second.size() > 1) { found_to_merge = true; merge_loc = it->first; break; } } if (found_to_merge) { set& nodeset = loc_nodes[merge_loc]; int to_idx = -1; int from_idx = -1; assert(nodeset.size() == 2); // only possibility: 1 steiner point + (another steiner point/pin point) int two_steiner = -1; for (auto idx : nodeset) { assert(idx != -1); if (cur_routeNodes[idx].pinIdxs.size() > 0) { two_steiner = idx; } } if (two_steiner != -1) { to_idx = two_steiner; } else { to_idx = *nodeset.begin(); } for (auto idx : nodeset) { if (idx != to_idx) { from_idx = idx; break; } } assert(to_idx != -1); assert(from_idx != -1); nodeset.erase(from_idx); auto& fromNode = cur_routeNodes[from_idx]; auto& toNode = cur_routeNodes[to_idx]; if (toNode.toConnect.find(from_idx) != toNode.toConnect.end()) { // two nodes are connected int del_edge = -1; for (int i = 0; i < edgeset.size(); i++) { if (edgeset[i].from == from_idx || edgeset[i].from == to_idx) { if (edgeset[i].to == from_idx || edgeset[i].to == to_idx) { del_edge = i; break; } } } edgeset.erase(edgeset.begin() + del_edge); toNode.toConnect.erase(from_idx); } for (int j = 0; j < edgeset.size(); j++) { if (edgeset[j].from == from_idx) { edgeset[j].from = to_idx; cur_routeNodes[edgeset[j].to].toConnect.erase(from_idx); cur_routeNodes[edgeset[j].to].toConnect.insert(to_idx); toNode.toConnect.insert(edgeset[j].to); } else if (edgeset[j].to == from_idx) { edgeset[j].to = to_idx; cur_routeNodes[edgeset[j].from].toConnect.erase(from_idx); cur_routeNodes[edgeset[j].from].toConnect.insert(to_idx); toNode.toConnect.insert(edgeset[j].from); } } cur_routeNodes.erase(from_idx); // remove node // remove redundant edge set toDelete; for (int i = 0; i < edgeset.size(); i++) { for (int j = i + 1; j < edgeset.size(); j++) { if (edgeset[i].from == edgeset[j].from || edgeset[i].from == edgeset[j].to) { if (edgeset[i].to == edgeset[j].from || edgeset[i].to == edgeset[j].to) toDelete.insert(i); } } } for (auto idx : toDelete) { edgeset.erase(edgeset.begin() + idx); } } else { break; } } }; grDatabase.tot_edge += edgeset.size(); int while_limit = 10000; // prevent possible(nearly impossible) infinite loop int tmp_cnt = 0; while (tmp_cnt < while_limit) { bool edgeshift = false; shiftEdge(edgeshift); if (edgeshift == false) break; mergeNode(); tmp_cnt += 1; } if (tmp_cnt == while_limit) log() << "More Shifting is actually needed" << std::endl; grDatabase.edge_shifted += tmp_cnt; s = cur_routeNodes.begin()->first; queue tmp_q_add; tmp_q_add.push(s); vis.clear(); while (tmp_q_add.empty() == false) { int u = tmp_q_add.front(); tmp_q_add.pop(); vis.insert(u); RouteNode& node = cur_routeNodes[u]; for (int nIdx : node.toConnect) { if (vis.find(nIdx) != vis.end()) continue; addUsage2D(node, cur_routeNodes[nIdx], 1); // update the usage tmp_q_add.push(nIdx); } } } void InitRoute::getRoutingOrder() { // local net in one gcell if (routeNodes.size() == 1) return; // pick a degree 1 node as root int root = -1; for (auto it = routeNodes.begin(); it != routeNodes.end(); it++) { if (it->second.degree() == 1) { root = it->first; break; } } // dfs to decide routing order set visited; function dfs = [&](int nodeIdx) { visited.insert(nodeIdx); RouteNode& node = routeNodes[nodeIdx]; for (int nIdx : node.toConnect) { if (visited.find(nIdx) != visited.end()) continue; RouteEdge edge; edge.from = nIdx; edge.to = nodeIdx; routeEdges.emplace_back(edge); routeNodes[edge.to].childIdxs.emplace_back(edge.from); dfs(nIdx); } }; if (root != -1) { dfs(root); reverse(routeEdges.begin(), routeEdges.end()); } else { log() << "Error: Can't find a degree one node (2)" << endl; } } void InitRoute::addUsage2D(RouteNode& u, RouteNode& v, double usage) { if (u.x == v.x) { // straight edge dir = X int gridline = u.x; utils::IntervalT Range(min(u.y, v.y), max(u.y, v.y)); for (int cp = Range.low; cp < Range.high; cp++) { grDatabase.useWire2D(X, gridline, cp, usage); } } else if (u.y == v.y) { int gridline = u.y; utils::IntervalT Range(min(u.x, v.x), max(u.x, v.x)); for (int cp = Range.low; cp < Range.high; cp++) { grDatabase.useWire2D(Y, gridline, cp, usage); } } else { // diagnal edge RouteNode new1(u.x, v.y), new2(v.x, u.y); addUsage2D(new1, u, usage / 2); addUsage2D(new1, v, usage / 2); addUsage2D(new2, u, usage / 2); addUsage2D(new2, v, usage / 2); } } void InitRoute::removeUsage2D(RouteNode& u, RouteNode& v, double usage) { if (u.x == v.x) { // straight edge dir = Y int gridline = u.x; utils::IntervalT Range(min(u.y, v.y), max(u.y, v.y)); for (int cp = Range.low; cp < Range.high; cp++) { grDatabase.removeUsage2D(X, gridline, cp, usage); } } else if (u.y == v.y) { int gridline = u.y; utils::IntervalT Range(min(u.x, v.x), max(u.x, v.x)); for (int cp = Range.low; cp < Range.high; cp++) { grDatabase.removeUsage2D(Y, gridline, cp, usage); } } else { // diagnal edge RouteNode new1(u.x, v.y), new2(v.x, u.y); removeUsage2D(new1, u, usage / 2); removeUsage2D(new1, v, usage / 2); removeUsage2D(new2, u, usage / 2); removeUsage2D(new2, v, usage / 2); } } std::map& InitRoute::getRouteNodes() { return routeNodes; } ================================================ FILE: src/single_net/InitRoute.h ================================================ #pragma once #include "global.h" #include "flute/flute.h" #include "gr_db/GrDatabase.h" #include "GenGuide.h" #include extern "C" { Tree flute(int d, DTYPE x[], DTYPE y[], int acc); } class RouteNode { public: int x; int y; int idx; vector pinLayers; // pins' layers within the node vector pinIdxs; // pins' indexes within the node std::set toConnect; // nodes connecting to this one vector childIdxs; // PatternRoute vector exitCosts; // cost exiting the node from different layers // cost of entering the node on different layers from different children std::unordered_map> enterCosts; // (childIdx->layerIdx->cost) // topo of entering the node on different layers from different children std::unordered_map>> enterEdges; // (childIdx->layerIdx->edge) // which layer should a child edge enter if exiting from a specific layer std::unordered_map> exitEnterLayers; // (childIdx->exit layer-> enter layer) int degree() { return toConnect.size(); } std::string str() { // return string description return std::to_string(idx) + "(" + std::to_string(x) + ", " + std::to_string(y) + ")" + (pinIdxs.size() == 0 ? "Steiner" : " "); } RouteNode() : x(-1), y(-1) {} RouteNode(int nx, int ny) : x(nx), y(ny) {} RouteNode(std::tuple loc) : x(std::get<0>(loc)), y(std::get<1>(loc)) {} }; struct RouteEdge { int from; int to; }; class InitRoute { public: InitRoute(gr::GrNet &grNetData) : grNet(grNetData), guideGen(grNet), status(db::RouteStatus::SUCC_NORMAL) { grNet.gridTopo.clear(); } void patternRoute(); // pattern routing void buildTopo(); void plan_fluteOnly(); void edge_shift2d(std::map &routeNodes); void getRoutingOrder(); void addUsage2D(RouteNode &u, RouteNode &v, double usage = 1); void removeUsage2D(RouteNode &u, RouteNode &v, double usage = 1); std::map &getRouteNodes(); db::RouteStatus status; gr::GrNet &grNet; private: GuideGenerator guideGen; std::map routeNodes; vector routeEdges; db::CostT getBufferedWireCost(gr::GrEdge edge); std::unordered_map wireCostBuffer; void LShape(const RouteEdge &edge); void runFlute(); }; ================================================ FILE: src/single_net/MazeRoute.cpp ================================================ #include "MazeRoute.h" ostream &operator<<(ostream &os, const Solution &sol) { os << "cost=" << sol.cost << ", vertex=" << sol.vertex << ", prev=" << (sol.prev ? sol.prev->vertex : -1); return os; } void MazeRoute::constructGridGraph(const vector &guides) { GuideGridGraphBuilder graphBuilder(grNet, graph, guides); mergedPinAccessBoxes = grNet.getMergedPinAccessBoxes( [](const gr::GrPoint &point) { return gr::PointOnLayer(point.layerIdx, point[X], point[Y]); }); graphBuilder.run(mergedPinAccessBoxes); } void MazeRoute::constructGridGraph(const CongestionMap &congMap) { CoarseGridGraphBuilder graphBuilder(grNet, graph, congMap); mergedPinAccessBoxes = grNet.getMergedPinAccessBoxes([&](const gr::GrPoint &point) { return graphBuilder.grPointToPoint(point); }); graphBuilder.run(mergedPinAccessBoxes); } db::RouteStatus MazeRoute::run() { vertexCosts.assign(graph.getNodeNum(), std::numeric_limits::max()); pinSols.assign(mergedPinAccessBoxes.size(), nullptr); const int startPin = 0; auto status = route(startPin); if (!db::isSucc(status)) { return status; } getResult(); return status; } db::RouteStatus MazeRoute::route(int startPin) { // define std::priority_queue auto solComp = [](const std::shared_ptr &lhs, const std::shared_ptr &rhs) { return rhs->cost < lhs->cost; }; std::priority_queue, vector>, decltype(solComp)> solQueue( solComp); auto updateSol = [&](const std::shared_ptr &sol) { solQueue.push(sol); if (sol->cost < vertexCosts[sol->vertex]) vertexCosts[sol->vertex] = sol->cost; }; // init from startPin for (auto vertex : graph.getVertices(startPin)) updateSol(std::make_shared(0, vertex, nullptr)); std::unordered_set visitedPin = {startPin}; int nPinToConnect = mergedPinAccessBoxes.size() - 1; while (nPinToConnect != 0) { std::shared_ptr dstVertex; int dstPinIdx = -1; // Dijkstra while (!solQueue.empty()) { auto newSol = solQueue.top(); int u = newSol->vertex; solQueue.pop(); // reach a pin? dstPinIdx = graph.getPinIdx(u); if (dstPinIdx != -1 && visitedPin.find(dstPinIdx) == visitedPin.end()) { dstVertex = newSol; break; } // pruning by upper bound if (vertexCosts[u] < newSol->cost) continue; const db::MetalLayer &uLayer = database.getLayer(graph.getPoint(u).layerIdx); for (auto direction : directions) { if (!graph.hasEdge(u, direction) || (newSol->prev && graph.getEdgeEndPoint(u, direction) == newSol->prev->vertex)) continue; // from u to v int v = graph.getEdgeEndPoint(u, direction); // edge cost db::CostT w = graph.getEdgeCost(u, direction); db::CostT newCost = w + newSol->cost; if (newCost < vertexCosts[v]) updateSol(std::make_shared(newCost, v, newSol)); } } if (!dstVertex) { printWarnMsg(db::RouteStatus::FAIL_DISCONNECTED_GRID_GRAPH, grNet.dbNet); printlog(visitedPin, nPinToConnect, mergedPinAccessBoxes.size(), mergedPinAccessBoxes); printlog(graph.checkConn()); graph.writeDebugFile(grNet.getName() + ".graph"); getchar(); return db::RouteStatus::FAIL_DISCONNECTED_GRID_GRAPH; } // update pinSols pinSols[dstPinIdx] = dstVertex; // mark the path to be zero auto tmp = dstVertex; while (tmp && tmp->cost != 0) { updateSol(std::make_shared(0, tmp->vertex, tmp->prev)); tmp = tmp->prev; } // mark all the accessbox of the pin to be almost zero for (auto vertex : graph.getVertices(dstPinIdx)) { if (vertex == dstVertex->vertex) continue; updateSol(std::make_shared(0, vertex, nullptr)); } visitedPin.insert(dstPinIdx); nPinToConnect--; } return db::RouteStatus::SUCC_NORMAL; } void MazeRoute::getResult() { grNet.gridTopo.clear(); std::unordered_map> visited; // back track from pin to source for (unsigned p = 0; p < mergedPinAccessBoxes.size(); p++) { std::unordered_map> curVisited; auto cur = pinSols[p]; std::shared_ptr prevS; while (cur) { auto it = visited.find(cur->vertex); if (it != visited.end()) { // graft to an existing node if (prevS) { gr::GrSteiner::setParent(prevS, it->second); } break; } else { // get curS auto point = graph.getPoint(cur->vertex); auto curS = std::make_shared(gr::GrPoint(point.layerIdx, point[X], point[Y]), graph.getPinIdx(cur->vertex)); if (prevS) { gr::GrSteiner::setParent(prevS, curS); } if (curVisited.find(cur->vertex) != curVisited.end()) { printlog("Warning: self loop found in a path for net", grNet.getName(), "for pin", p); } curVisited.emplace(cur->vertex, curS); // store tree root if (!(cur->prev)) { grNet.gridTopo.push_back(curS); break; } // prep for the next loop prevS = curS; cur = cur->prev; } } for (const auto &v : curVisited) visited.insert(v); } // remove redundant Steiner nodes for (auto &tree : grNet.gridTopo) { gr::GrSteiner::mergeNodes(tree); } } ================================================ FILE: src/single_net/MazeRoute.h ================================================ #pragma once #include "GridGraph.h" #include "multi_net/CongestionMap.h" class Solution { public: db::CostT cost; int vertex; std::shared_ptr prev; Solution(db::CostT c, int v, const std::shared_ptr &p) : cost(c), vertex(v), prev(p) {} friend ostream &operator<<(ostream &os, const Solution &sol); }; class MazeRoute { public: MazeRoute(gr::GrNet &grNetData) : grNet(grNetData) {} void constructGridGraph(const vector &guides); void constructGridGraph(const CongestionMap& congMap); db::RouteStatus run(); private: gr::GrNet &grNet; GridGraph graph; vector vertexCosts; // min cost upper bound for each vertex vector> pinSols; // best solution for each pin vector> mergedPinAccessBoxes; db::RouteStatus route(int startPin); void getResult(); }; ================================================ FILE: src/single_net/SingleNetRouter.cpp ================================================ #include "SingleNetRouter.h" #include "InitRoute.h" #include "MazeRoute.h" SingleNetRouter::SingleNetRouter(gr::GrNet& grDatabaseNet) : grNet(grDatabaseNet), guideGen(grNet), status(db::RouteStatus::SUCC_NORMAL) { grDatabase.removeNet(grNet); grNet.gridTopo.clear(); } void SingleNetRouter::finish() { guideGen.genTopoGuides(); grDatabase.useNet(grNet); } void SingleNetRouter::mazeRoute() { if (!grNet.needToRoute()) { status = db::RouteStatus::SUCC_ONE_PIN; } else { MazeRoute mazeRouter(grNet); mazeRouter.constructGridGraph(guides); status = mazeRouter.run(); } db::routeStat.increment(db::RouteStage::MAZE, status); } void SingleNetRouter::initRoutePattern(InitRoute& initRouter) { if (!grNet.needToRoute()) { status = db::RouteStatus::SUCC_ONE_PIN; } else { initRouter.patternRoute(); initRouter.buildTopo(); status = db::RouteStatus::SUCC_NORMAL; } db::routeStat.increment(db::RouteStage::INIT, status); } void SingleNetRouter::planMazeRoute(const CongestionMap& congMap) { // run mazeroute on coarse grid const int cellWidth = congMap.getCellWidth(); const int cellHeight = congMap.getCellHeight(); gr::GrNet tmpNet = grNet; MazeRoute mazeRouter(tmpNet); mazeRouter.constructGridGraph(congMap); status = mazeRouter.run(); // generate guides auto getLower = [&](int coor, Dimension dir) { if (dir == X) return coor * cellWidth; else return coor * cellHeight; }; auto getUpper = [&](int coor, Dimension dir) { if (dir == X) return min((coor + 1) * cellWidth, grDatabase.getNumGrPoint(X)) - 1; else return min((coor + 1) * cellHeight, grDatabase.getNumGrPoint(Y)) - 1; }; guides.clear(); tmpNet.postOrderVisitGridTopo([&](std::shared_ptr node) { auto parent = node; for (auto child : parent->children) { // if (tmpNet.getName() == "net6700") printlog(*parent, *child); if (parent->layerIdx == child->layerIdx) { std::shared_ptr lower, upper; if ((*parent)[X] < (*child)[X] || (*parent)[Y] < (*child)[Y]) { lower = parent; upper = child; } else { lower = child; upper = parent; } guides.emplace_back(lower->layerIdx, utils::IntervalT(getLower((*lower)[X], X), getUpper((*upper)[X], X)), utils::IntervalT(getLower((*lower)[Y], Y), getUpper((*upper)[Y], Y))); } else { guides.emplace_back(parent->layerIdx, utils::IntervalT(getLower((*parent)[X], X), getUpper((*parent)[X], X)), utils::IntervalT(getLower((*parent)[Y], Y), getUpper((*parent)[Y], Y))); guides.emplace_back(child->layerIdx, utils::IntervalT(getLower((*child)[X], X), getUpper((*child)[X], X)), utils::IntervalT(getLower((*child)[Y], Y), getUpper((*child)[Y], Y))); } } }); // maintain connectivity auto mergedPinAccessBoxes = grNet.getMergedPinAccessBoxes([&](const gr::GrPoint& point) { return gr::PointOnLayer(point.layerIdx, point[X] / cellWidth, point[Y] / cellHeight); }); const int neighLayers = 2; for (auto& points : mergedPinAccessBoxes) { for (auto& point : points) { for (int l = point.layerIdx - neighLayers; l <= point.layerIdx + neighLayers; l++) { if (l < database.getLayerNum() && l >= 0) guides.emplace_back(l, utils::IntervalT(getLower(point[X], X), getUpper(point[X], X)), utils::IntervalT(getLower(point[Y], Y), getUpper(point[Y], Y))); } } } } ================================================ FILE: src/single_net/SingleNetRouter.h ================================================ #pragma once #include "db/Database.h" #include "gr_db/GrDatabase.h" #include "multi_net/CongestionMap.h" #include "GenGuide.h" class InitRoute; class SingleNetRouter { public: gr::GrNet& grNet; db::RouteStatus status; SingleNetRouter(gr::GrNet& grNet); void planMazeRoute(const CongestionMap& congMap); void mazeRoute(); void initRoutePattern(InitRoute& initRouter); void finish(); vector guides; private: GuideGenerator guideGen; }; ================================================ FILE: src/utils/enum.h ================================================ // This file is part of Better Enums, released under the BSD 2-clause license. // See doc/LICENSE for details, or visit http://github.com/aantron/better-enums. #pragma once #ifndef BETTER_ENUMS_ENUM_H #define BETTER_ENUMS_ENUM_H #include #include #include #include // Feature detection. #ifdef __GNUC__ # ifdef __clang__ # if __has_feature(cxx_constexpr) # define BETTER_ENUMS_HAVE_CONSTEXPR # endif # if !defined(__EXCEPTIONS) || !__has_feature(cxx_exceptions) # define BETTER_ENUMS_NO_EXCEPTIONS # endif # else # if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) # define BETTER_ENUMS_HAVE_CONSTEXPR # endif # endif # ifndef __EXCEPTIONS # define BETTER_ENUMS_NO_EXCEPTIONS # endif # endif #endif #ifdef _MSC_VER # if _MSC_VER >= 1911 # define BETTER_ENUMS_HAVE_CONSTEXPR # endif # ifdef __clang__ # if __has_feature(cxx_constexpr) # define BETTER_ENUMS_HAVE_CONSTEXPR # endif # endif # ifndef _CPPUNWIND # define BETTER_ENUMS_NO_EXCEPTIONS # endif # if _MSC_VER < 1600 # define BETTER_ENUMS_VC2008_WORKAROUNDS # endif #endif #ifdef BETTER_ENUMS_CONSTEXPR # define BETTER_ENUMS_HAVE_CONSTEXPR #endif #ifdef BETTER_ENUMS_NO_CONSTEXPR # ifdef BETTER_ENUMS_HAVE_CONSTEXPR # undef BETTER_ENUMS_HAVE_CONSTEXPR # endif #endif // GCC (and maybe clang) can be made to warn about using 0 or NULL when nullptr // is available, so Better Enums tries to use nullptr. This passage uses // availability of constexpr as a proxy for availability of nullptr, i.e. it // assumes that nullptr is available when compiling on the right versions of gcc // and clang with the right -std flag. This is actually slightly wrong, because // nullptr is also available in Visual C++, but constexpr isn't. This // imprecision doesn't matter, however, because VC++ doesn't have the warnings // that make using nullptr necessary. #ifdef BETTER_ENUMS_HAVE_CONSTEXPR # define BETTER_ENUMS_CONSTEXPR_ constexpr # define BETTER_ENUMS_NULLPTR nullptr #else # define BETTER_ENUMS_CONSTEXPR_ # define BETTER_ENUMS_NULLPTR NULL #endif #ifndef BETTER_ENUMS_NO_EXCEPTIONS # define BETTER_ENUMS_IF_EXCEPTIONS(x) x #else # define BETTER_ENUMS_IF_EXCEPTIONS(x) #endif #ifdef __GNUC__ # define BETTER_ENUMS_UNUSED __attribute__((__unused__)) #else # define BETTER_ENUMS_UNUSED #endif // Higher-order preprocessor macros. #ifdef BETTER_ENUMS_MACRO_FILE # include BETTER_ENUMS_MACRO_FILE #else #define BETTER_ENUMS_PP_MAP(macro, data, ...) \ BETTER_ENUMS_ID( \ BETTER_ENUMS_APPLY( \ BETTER_ENUMS_PP_MAP_VAR_COUNT, \ BETTER_ENUMS_PP_COUNT(__VA_ARGS__)) \ (macro, data, __VA_ARGS__)) #define BETTER_ENUMS_PP_MAP_VAR_COUNT(count) BETTER_ENUMS_M ## count #define BETTER_ENUMS_APPLY(macro, ...) BETTER_ENUMS_ID(macro(__VA_ARGS__)) #define BETTER_ENUMS_ID(x) x #define BETTER_ENUMS_M1(m, d, x) m(d,0,x) #define BETTER_ENUMS_M2(m,d,x,...) m(d,1,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M1(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M3(m,d,x,...) m(d,2,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M2(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M4(m,d,x,...) m(d,3,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M3(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M5(m,d,x,...) m(d,4,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M4(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M6(m,d,x,...) m(d,5,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M5(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M7(m,d,x,...) m(d,6,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M6(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M8(m,d,x,...) m(d,7,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M7(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M9(m,d,x,...) m(d,8,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M8(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M10(m,d,x,...) m(d,9,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M9(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M11(m,d,x,...) m(d,10,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M10(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M12(m,d,x,...) m(d,11,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M11(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M13(m,d,x,...) m(d,12,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M12(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M14(m,d,x,...) m(d,13,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M13(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M15(m,d,x,...) m(d,14,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M14(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M16(m,d,x,...) m(d,15,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M15(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M17(m,d,x,...) m(d,16,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M16(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M18(m,d,x,...) m(d,17,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M17(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M19(m,d,x,...) m(d,18,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M18(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M20(m,d,x,...) m(d,19,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M19(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M21(m,d,x,...) m(d,20,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M20(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M22(m,d,x,...) m(d,21,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M21(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M23(m,d,x,...) m(d,22,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M22(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M24(m,d,x,...) m(d,23,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M23(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M25(m,d,x,...) m(d,24,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M24(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M26(m,d,x,...) m(d,25,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M25(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M27(m,d,x,...) m(d,26,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M26(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M28(m,d,x,...) m(d,27,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M27(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M29(m,d,x,...) m(d,28,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M28(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M30(m,d,x,...) m(d,29,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M29(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M31(m,d,x,...) m(d,30,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M30(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M32(m,d,x,...) m(d,31,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M31(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M33(m,d,x,...) m(d,32,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M32(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M34(m,d,x,...) m(d,33,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M33(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M35(m,d,x,...) m(d,34,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M34(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M36(m,d,x,...) m(d,35,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M35(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M37(m,d,x,...) m(d,36,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M36(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M38(m,d,x,...) m(d,37,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M37(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M39(m,d,x,...) m(d,38,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M38(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M40(m,d,x,...) m(d,39,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M39(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M41(m,d,x,...) m(d,40,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M40(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M42(m,d,x,...) m(d,41,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M41(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M43(m,d,x,...) m(d,42,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M42(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M44(m,d,x,...) m(d,43,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M43(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M45(m,d,x,...) m(d,44,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M44(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M46(m,d,x,...) m(d,45,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M45(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M47(m,d,x,...) m(d,46,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M46(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M48(m,d,x,...) m(d,47,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M47(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M49(m,d,x,...) m(d,48,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M48(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M50(m,d,x,...) m(d,49,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M49(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M51(m,d,x,...) m(d,50,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M50(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M52(m,d,x,...) m(d,51,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M51(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M53(m,d,x,...) m(d,52,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M52(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M54(m,d,x,...) m(d,53,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M53(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M55(m,d,x,...) m(d,54,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M54(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M56(m,d,x,...) m(d,55,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M55(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M57(m,d,x,...) m(d,56,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M56(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M58(m,d,x,...) m(d,57,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M57(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M59(m,d,x,...) m(d,58,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M58(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M60(m,d,x,...) m(d,59,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M59(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M61(m,d,x,...) m(d,60,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M60(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M62(m,d,x,...) m(d,61,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M61(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M63(m,d,x,...) m(d,62,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M62(m,d,__VA_ARGS__)) #define BETTER_ENUMS_M64(m,d,x,...) m(d,63,x) \ BETTER_ENUMS_ID(BETTER_ENUMS_M63(m,d,__VA_ARGS__)) #define BETTER_ENUMS_PP_COUNT_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, \ _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, \ _56, _57, _58, _59, _60, _61, _62, _63, _64, count, ...) count #define BETTER_ENUMS_PP_COUNT(...) \ BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(__VA_ARGS__, 64, 63, 62, 61, 60,\ 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42,\ 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24,\ 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, \ 4, 3, 2, 1)) #define BETTER_ENUMS_ITERATE(X, f, l) X(f, l, 0) X(f, l, 1) X(f, l, 2) \ X(f, l, 3) X(f, l, 4) X(f, l, 5) X(f, l, 6) X(f, l, 7) X(f, l, 8) \ X(f, l, 9) X(f, l, 10) X(f, l, 11) X(f, l, 12) X(f, l, 13) X(f, l, 14) \ X(f, l, 15) X(f, l, 16) X(f, l, 17) X(f, l, 18) X(f, l, 19) X(f, l, 20) \ X(f, l, 21) X(f, l, 22) X(f, l, 23) #endif // #ifdef BETTER_ENUMS_MACRO_FILE else case namespace better_enums { // Optional type. template BETTER_ENUMS_CONSTEXPR_ inline T _default() { return static_cast(0); } template <> BETTER_ENUMS_CONSTEXPR_ inline const char* _default() { return BETTER_ENUMS_NULLPTR; } template <> BETTER_ENUMS_CONSTEXPR_ inline std::size_t _default() { return 0; } template struct optional { BETTER_ENUMS_CONSTEXPR_ optional() : _valid(false), _value(_default()) { } BETTER_ENUMS_CONSTEXPR_ optional(T v) : _valid(true), _value(v) { } BETTER_ENUMS_CONSTEXPR_ const T& operator *() const { return _value; } BETTER_ENUMS_CONSTEXPR_ const T* operator ->() const { return &_value; } BETTER_ENUMS_CONSTEXPR_ operator bool() const { return _valid; } BETTER_ENUMS_CONSTEXPR_ const T& value() const { return _value; } private: bool _valid; T _value; }; template BETTER_ENUMS_CONSTEXPR_ static optional _map_index(const Element *array, optional index) { return index ? static_cast(array[*index]) : optional(); } #ifdef BETTER_ENUMS_VC2008_WORKAROUNDS #define BETTER_ENUMS_OR_THROW \ if (!maybe) \ throw std::runtime_error(message); \ \ return *maybe; #else #define BETTER_ENUMS_OR_THROW \ return maybe ? *maybe : throw std::runtime_error(message); #endif BETTER_ENUMS_IF_EXCEPTIONS( template BETTER_ENUMS_CONSTEXPR_ static T _or_throw(optional maybe, const char *message) { BETTER_ENUMS_OR_THROW } ) template BETTER_ENUMS_CONSTEXPR_ static T* _or_null(optional maybe) { return maybe ? *maybe : BETTER_ENUMS_NULLPTR; } // Functional sequencing. This is essentially a comma operator wrapped in a // constexpr function. g++ 4.7 doesn't "accept" integral constants in the second // position for the comma operator, and emits an external symbol, which then // causes a linking error. template BETTER_ENUMS_CONSTEXPR_ U continue_with(T, U value) { return value; } // Values array declaration helper. template struct _eat_assign { explicit BETTER_ENUMS_CONSTEXPR_ _eat_assign(EnumType value) : _value(value) { } template BETTER_ENUMS_CONSTEXPR_ const _eat_assign& operator =(Any) const { return *this; } BETTER_ENUMS_CONSTEXPR_ operator EnumType () const { return _value; } private: EnumType _value; }; // Iterables. template struct _Iterable { typedef const Element* iterator; BETTER_ENUMS_CONSTEXPR_ iterator begin() const { return iterator(_array); } BETTER_ENUMS_CONSTEXPR_ iterator end() const { return iterator(_array + _size); } BETTER_ENUMS_CONSTEXPR_ std::size_t size() const { return _size; } BETTER_ENUMS_CONSTEXPR_ const Element& operator [](std::size_t index) const { return _array[index]; } BETTER_ENUMS_CONSTEXPR_ _Iterable(const Element *array, std::size_t s) : _array(array), _size(s) { } private: const Element * const _array; const std::size_t _size; }; // String routines. BETTER_ENUMS_CONSTEXPR_ static const char *_name_enders = "= \t\n"; BETTER_ENUMS_CONSTEXPR_ inline bool _ends_name(char c, std::size_t index = 0) { return c == _name_enders[index] ? true : _name_enders[index] == '\0' ? false : _ends_name(c, index + 1); } BETTER_ENUMS_CONSTEXPR_ inline bool _has_initializer(const char *s, std::size_t index = 0) { return s[index] == '\0' ? false : s[index] == '=' ? true : _has_initializer(s, index + 1); } BETTER_ENUMS_CONSTEXPR_ inline std::size_t _constant_length(const char *s, std::size_t index = 0) { return _ends_name(s[index]) ? index : _constant_length(s, index + 1); } BETTER_ENUMS_CONSTEXPR_ inline char _select(const char *from, std::size_t from_length, std::size_t index) { return index >= from_length ? '\0' : from[index]; } BETTER_ENUMS_CONSTEXPR_ inline char _to_lower_ascii(char c) { return c >= 0x41 && c <= 0x5A ? static_cast(c + 0x20) : c; } BETTER_ENUMS_CONSTEXPR_ inline bool _names_match(const char *stringizedName, const char *referenceName, std::size_t index = 0) { return _ends_name(stringizedName[index]) ? referenceName[index] == '\0' : referenceName[index] == '\0' ? false : stringizedName[index] != referenceName[index] ? false : _names_match(stringizedName, referenceName, index + 1); } BETTER_ENUMS_CONSTEXPR_ inline bool _names_match_nocase(const char *stringizedName, const char *referenceName, std::size_t index = 0) { return _ends_name(stringizedName[index]) ? referenceName[index] == '\0' : referenceName[index] == '\0' ? false : _to_lower_ascii(stringizedName[index]) != _to_lower_ascii(referenceName[index]) ? false : _names_match_nocase(stringizedName, referenceName, index + 1); } inline void _trim_names(const char * const *raw_names, const char **trimmed_names, char *storage, std::size_t count) { std::size_t offset = 0; for (std::size_t index = 0; index < count; ++index) { trimmed_names[index] = storage + offset; std::size_t trimmed_length = std::strcspn(raw_names[index], _name_enders); storage[offset + trimmed_length] = '\0'; std::size_t raw_length = std::strlen(raw_names[index]); offset += raw_length + 1; } } // Eager initialization. template struct _initialize_at_program_start { _initialize_at_program_start() { Enum::initialize(); } }; } // namespace better_enums // Array generation macros. #define BETTER_ENUMS_EAT_ASSIGN_SINGLE(EnumType, index, expression) \ ((::better_enums::_eat_assign)EnumType::expression), #define BETTER_ENUMS_EAT_ASSIGN(EnumType, ...) \ BETTER_ENUMS_ID( \ BETTER_ENUMS_PP_MAP( \ BETTER_ENUMS_EAT_ASSIGN_SINGLE, EnumType, __VA_ARGS__)) #ifdef BETTER_ENUMS_HAVE_CONSTEXPR #define BETTER_ENUMS_SELECT_SINGLE_CHARACTER(from, from_length, index) \ ::better_enums::_select(from, from_length, index), #define BETTER_ENUMS_SELECT_CHARACTERS(from, from_length) \ BETTER_ENUMS_ITERATE( \ BETTER_ENUMS_SELECT_SINGLE_CHARACTER, from, from_length) #define BETTER_ENUMS_TRIM_SINGLE_STRING(ignored, index, expression) \ constexpr std::size_t _length_ ## index = \ ::better_enums::_constant_length(#expression); \ constexpr const char _trimmed_ ## index [] = \ { BETTER_ENUMS_SELECT_CHARACTERS(#expression, _length_ ## index) }; \ constexpr const char *_final_ ## index = \ ::better_enums::_has_initializer(#expression) ? \ _trimmed_ ## index : #expression; #define BETTER_ENUMS_TRIM_STRINGS(...) \ BETTER_ENUMS_ID( \ BETTER_ENUMS_PP_MAP( \ BETTER_ENUMS_TRIM_SINGLE_STRING, ignored, __VA_ARGS__)) #define BETTER_ENUMS_REFER_TO_SINGLE_STRING(ignored, index, expression) \ _final_ ## index, #define BETTER_ENUMS_REFER_TO_STRINGS(...) \ BETTER_ENUMS_ID( \ BETTER_ENUMS_PP_MAP( \ BETTER_ENUMS_REFER_TO_SINGLE_STRING, ignored, __VA_ARGS__)) #endif // #ifdef BETTER_ENUMS_HAVE_CONSTEXPR #define BETTER_ENUMS_STRINGIZE_SINGLE(ignored, index, expression) #expression, #define BETTER_ENUMS_STRINGIZE(...) \ BETTER_ENUMS_ID( \ BETTER_ENUMS_PP_MAP( \ BETTER_ENUMS_STRINGIZE_SINGLE, ignored, __VA_ARGS__)) #define BETTER_ENUMS_RESERVE_STORAGE_SINGLE(ignored, index, expression) \ #expression "," #define BETTER_ENUMS_RESERVE_STORAGE(...) \ BETTER_ENUMS_ID( \ BETTER_ENUMS_PP_MAP( \ BETTER_ENUMS_RESERVE_STORAGE_SINGLE, ignored, __VA_ARGS__)) // The enums proper. #define BETTER_ENUMS_NS(EnumType) better_enums_data_ ## EnumType #ifdef BETTER_ENUMS_VC2008_WORKAROUNDS #define BETTER_ENUMS_COPY_CONSTRUCTOR(Enum) \ BETTER_ENUMS_CONSTEXPR_ Enum(const Enum &other) : \ _value(other._value) { } #else #define BETTER_ENUMS_COPY_CONSTRUCTOR(Enum) #endif #define BETTER_ENUMS_TYPE(SetUnderlyingType, SwitchType, GenerateSwitchType, \ GenerateStrings, ToStringConstexpr, \ DeclareInitialize, DefineInitialize, CallInitialize, \ Enum, Underlying, ...) \ \ namespace better_enums_data_ ## Enum { \ \ BETTER_ENUMS_ID(GenerateSwitchType(Underlying, __VA_ARGS__)) \ \ } \ \ class Enum { \ private: \ typedef ::better_enums::optional _optional; \ typedef ::better_enums::optional _optional_index; \ \ public: \ typedef Underlying _integral; \ \ enum _enumerated SetUnderlyingType(Underlying) { __VA_ARGS__ }; \ \ BETTER_ENUMS_CONSTEXPR_ Enum(_enumerated value) : _value(value) { } \ \ BETTER_ENUMS_COPY_CONSTRUCTOR(Enum) \ \ BETTER_ENUMS_CONSTEXPR_ operator SwitchType(Enum)() const \ { \ return SwitchType(Enum)(_value); \ } \ \ BETTER_ENUMS_CONSTEXPR_ _integral _to_integral() const; \ BETTER_ENUMS_IF_EXCEPTIONS( \ BETTER_ENUMS_CONSTEXPR_ static Enum _from_integral(_integral value); \ ) \ BETTER_ENUMS_CONSTEXPR_ static Enum \ _from_integral_unchecked(_integral value); \ BETTER_ENUMS_CONSTEXPR_ static _optional \ _from_integral_nothrow(_integral value); \ \ ToStringConstexpr const char* _to_string() const; \ BETTER_ENUMS_IF_EXCEPTIONS( \ BETTER_ENUMS_CONSTEXPR_ static Enum _from_string(const char *name); \ ) \ BETTER_ENUMS_CONSTEXPR_ static _optional \ _from_string_nothrow(const char *name); \ \ BETTER_ENUMS_IF_EXCEPTIONS( \ BETTER_ENUMS_CONSTEXPR_ static Enum _from_string_nocase(const char *name); \ ) \ BETTER_ENUMS_CONSTEXPR_ static _optional \ _from_string_nocase_nothrow(const char *name); \ \ BETTER_ENUMS_CONSTEXPR_ static bool _is_valid(_integral value); \ BETTER_ENUMS_CONSTEXPR_ static bool _is_valid(const char *name); \ BETTER_ENUMS_CONSTEXPR_ static bool _is_valid_nocase(const char *name); \ \ typedef ::better_enums::_Iterable _value_iterable; \ typedef ::better_enums::_Iterable _name_iterable; \ \ typedef _value_iterable::iterator _value_iterator; \ typedef _name_iterable::iterator _name_iterator; \ \ BETTER_ENUMS_CONSTEXPR_ static const std::size_t _size_constant = \ BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT(__VA_ARGS__)); \ BETTER_ENUMS_CONSTEXPR_ static std::size_t _size() \ { return _size_constant; } \ \ BETTER_ENUMS_CONSTEXPR_ static const char* _name(); \ BETTER_ENUMS_CONSTEXPR_ static _value_iterable _values(); \ ToStringConstexpr static _name_iterable _names(); \ \ _integral _value; \ \ BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum) \ \ private: \ explicit BETTER_ENUMS_CONSTEXPR_ Enum(const _integral &value) : \ _value(value) { } \ \ DeclareInitialize \ \ BETTER_ENUMS_CONSTEXPR_ static _optional_index \ _from_value_loop(_integral value, std::size_t index = 0); \ BETTER_ENUMS_CONSTEXPR_ static _optional_index \ _from_string_loop(const char *name, std::size_t index = 0); \ BETTER_ENUMS_CONSTEXPR_ static _optional_index \ _from_string_nocase_loop(const char *name, std::size_t index = 0); \ \ friend struct ::better_enums::_initialize_at_program_start; \ }; \ \ namespace better_enums_data_ ## Enum { \ \ static ::better_enums::_initialize_at_program_start \ _force_initialization; \ \ enum _PutNamesInThisScopeAlso { __VA_ARGS__ }; \ \ BETTER_ENUMS_CONSTEXPR_ const Enum _value_array[] = \ { BETTER_ENUMS_ID(BETTER_ENUMS_EAT_ASSIGN(Enum, __VA_ARGS__)) }; \ \ BETTER_ENUMS_ID(GenerateStrings(Enum, __VA_ARGS__)) \ \ } \ \ BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \ inline const Enum \ operator +(Enum::_enumerated enumerated) \ { \ return static_cast(enumerated); \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \ Enum::_from_value_loop(Enum::_integral value, std::size_t index) \ { \ return \ index == _size() ? \ _optional_index() : \ BETTER_ENUMS_NS(Enum)::_value_array[index]._value == value ? \ _optional_index(index) : \ _from_value_loop(value, index + 1); \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \ Enum::_from_string_loop(const char *name, std::size_t index) \ { \ return \ index == _size() ? _optional_index() : \ ::better_enums::_names_match( \ BETTER_ENUMS_NS(Enum)::_raw_names()[index], name) ? \ _optional_index(index) : \ _from_string_loop(name, index + 1); \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \ Enum::_from_string_nocase_loop(const char *name, std::size_t index) \ { \ return \ index == _size() ? _optional_index() : \ ::better_enums::_names_match_nocase( \ BETTER_ENUMS_NS(Enum)::_raw_names()[index], name) ? \ _optional_index(index) : \ _from_string_nocase_loop(name, index + 1); \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline Enum::_integral Enum::_to_integral() const \ { \ return _integral(_value); \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline Enum \ Enum::_from_integral_unchecked(_integral value) \ { \ return static_cast<_enumerated>(value); \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \ Enum::_from_integral_nothrow(_integral value) \ { \ return \ ::better_enums::_map_index(BETTER_ENUMS_NS(Enum)::_value_array, \ _from_value_loop(value)); \ } \ \ BETTER_ENUMS_IF_EXCEPTIONS( \ BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_integral(_integral value) \ { \ return \ ::better_enums::_or_throw(_from_integral_nothrow(value), \ #Enum "::_from_integral: invalid argument"); \ } \ ) \ \ ToStringConstexpr inline const char* Enum::_to_string() const \ { \ return \ ::better_enums::_or_null( \ ::better_enums::_map_index( \ BETTER_ENUMS_NS(Enum)::_name_array(), \ _from_value_loop(CallInitialize(_value)))); \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \ Enum::_from_string_nothrow(const char *name) \ { \ return \ ::better_enums::_map_index( \ BETTER_ENUMS_NS(Enum)::_value_array, _from_string_loop(name)); \ } \ \ BETTER_ENUMS_IF_EXCEPTIONS( \ BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_string(const char *name) \ { \ return \ ::better_enums::_or_throw(_from_string_nothrow(name), \ #Enum "::_from_string: invalid argument"); \ } \ ) \ \ BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \ Enum::_from_string_nocase_nothrow(const char *name) \ { \ return \ ::better_enums::_map_index(BETTER_ENUMS_NS(Enum)::_value_array, \ _from_string_nocase_loop(name)); \ } \ \ BETTER_ENUMS_IF_EXCEPTIONS( \ BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_string_nocase(const char *name)\ { \ return \ ::better_enums::_or_throw( \ _from_string_nocase_nothrow(name), \ #Enum "::_from_string_nocase: invalid argument"); \ } \ ) \ \ BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid(_integral value) \ { \ return _from_value_loop(value); \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid(const char *name) \ { \ return _from_string_loop(name); \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid_nocase(const char *name) \ { \ return _from_string_nocase_loop(name); \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline const char* Enum::_name() \ { \ return #Enum; \ } \ \ BETTER_ENUMS_CONSTEXPR_ inline Enum::_value_iterable Enum::_values() \ { \ return _value_iterable(BETTER_ENUMS_NS(Enum)::_value_array, _size()); \ } \ \ ToStringConstexpr inline Enum::_name_iterable Enum::_names() \ { \ return \ _name_iterable(BETTER_ENUMS_NS(Enum)::_name_array(), \ CallInitialize(_size())); \ } \ \ DefineInitialize(Enum) \ \ BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \ inline bool operator ==(const Enum &a, const Enum &b) \ { return a._to_integral() == b._to_integral(); } \ \ BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \ inline bool operator !=(const Enum &a, const Enum &b) \ { return a._to_integral() != b._to_integral(); } \ \ BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \ inline bool operator <(const Enum &a, const Enum &b) \ { return a._to_integral() < b._to_integral(); } \ \ BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \ inline bool operator <=(const Enum &a, const Enum &b) \ { return a._to_integral() <= b._to_integral(); } \ \ BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \ inline bool operator >(const Enum &a, const Enum &b) \ { return a._to_integral() > b._to_integral(); } \ \ BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \ inline bool operator >=(const Enum &a, const Enum &b) \ { return a._to_integral() >= b._to_integral(); } \ \ \ template \ std::basic_ostream& \ operator <<(std::basic_ostream& stream, const Enum &value) \ { \ return stream << value._to_string(); \ } \ \ template \ std::basic_istream& \ operator >>(std::basic_istream& stream, Enum &value) \ { \ std::basic_string buffer; \ \ stream >> buffer; \ ::better_enums::optional converted = \ Enum::_from_string_nothrow(buffer.c_str()); \ \ if (converted) \ value = *converted; \ else \ stream.setstate(std::basic_istream::failbit); \ \ return stream; \ } // Enum feature options. // C++98, C++11 #define BETTER_ENUMS_CXX98_UNDERLYING_TYPE(Underlying) // C++11 #define BETTER_ENUMS_CXX11_UNDERLYING_TYPE(Underlying) \ : Underlying #if defined(_MSC_VER) && _MSC_VER >= 1700 // VS 2012 and above fully support strongly typed enums and will warn about // incorrect usage. # define BETTER_ENUMS_LEGACY_UNDERLYING_TYPE(Underlying) BETTER_ENUMS_CXX11_UNDERLYING_TYPE(Underlying) #else # define BETTER_ENUMS_LEGACY_UNDERLYING_TYPE(Underlying) BETTER_ENUMS_CXX98_UNDERLYING_TYPE(Underlying) #endif // C++98, C++11 #define BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE(Type) \ _enumerated // C++11 #define BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE(Type) \ BETTER_ENUMS_NS(Type)::_EnumClassForSwitchStatements // C++98, C++11 #define BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE_GENERATE(Underlying, ...) // C++11 #define BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE_GENERATE(Underlying, ...) \ enum class _EnumClassForSwitchStatements : Underlying { __VA_ARGS__ }; // C++98 #define BETTER_ENUMS_CXX98_TRIM_STRINGS_ARRAYS(Enum, ...) \ inline const char** _raw_names() \ { \ static const char *value[] = \ { BETTER_ENUMS_ID(BETTER_ENUMS_STRINGIZE(__VA_ARGS__)) }; \ return value; \ } \ \ inline char* _name_storage() \ { \ static char storage[] = \ BETTER_ENUMS_ID(BETTER_ENUMS_RESERVE_STORAGE(__VA_ARGS__)); \ return storage; \ } \ \ inline const char** _name_array() \ { \ static const char *value[Enum::_size_constant]; \ return value; \ } \ \ inline bool& _initialized() \ { \ static bool value = false; \ return value; \ } // C++11 fast version #define BETTER_ENUMS_CXX11_PARTIAL_CONSTEXPR_TRIM_STRINGS_ARRAYS(Enum, ...) \ constexpr const char *_the_raw_names[] = \ { BETTER_ENUMS_ID(BETTER_ENUMS_STRINGIZE(__VA_ARGS__)) }; \ \ constexpr const char * const * _raw_names() \ { \ return _the_raw_names; \ } \ \ inline char* _name_storage() \ { \ static char storage[] = \ BETTER_ENUMS_ID(BETTER_ENUMS_RESERVE_STORAGE(__VA_ARGS__)); \ return storage; \ } \ \ inline const char** _name_array() \ { \ static const char *value[Enum::_size_constant]; \ return value; \ } \ \ inline bool& _initialized() \ { \ static bool value = false; \ return value; \ } // C++11 slow all-constexpr version #define BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS(Enum, ...) \ BETTER_ENUMS_ID(BETTER_ENUMS_TRIM_STRINGS(__VA_ARGS__)) \ \ constexpr const char * const _the_name_array[] = \ { BETTER_ENUMS_ID(BETTER_ENUMS_REFER_TO_STRINGS(__VA_ARGS__)) }; \ \ constexpr const char * const * _name_array() \ { \ return _the_name_array; \ } \ \ constexpr const char * const * _raw_names() \ { \ return _the_name_array; \ } // C++98, C++11 fast version #define BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD // C++11 slow all-constexpr version #define BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD \ constexpr // C++98, C++11 fast version #define BETTER_ENUMS_DO_DECLARE_INITIALIZE \ static int initialize(); // C++11 slow all-constexpr version #define BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE \ static int initialize() { return 0; } // C++98, C++11 fast version #define BETTER_ENUMS_DO_DEFINE_INITIALIZE(Enum) \ inline int Enum::initialize() \ { \ if (BETTER_ENUMS_NS(Enum)::_initialized()) \ return 0; \ \ ::better_enums::_trim_names(BETTER_ENUMS_NS(Enum)::_raw_names(), \ BETTER_ENUMS_NS(Enum)::_name_array(), \ BETTER_ENUMS_NS(Enum)::_name_storage(), \ _size()); \ \ BETTER_ENUMS_NS(Enum)::_initialized() = true; \ \ return 0; \ } // C++11 slow all-constexpr version #define BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE(Enum) // C++98, C++11 fast version #define BETTER_ENUMS_DO_CALL_INITIALIZE(value) \ ::better_enums::continue_with(initialize(), value) // C++11 slow all-constexpr version #define BETTER_ENUMS_DO_NOT_CALL_INITIALIZE(value) \ value // User feature selection. #ifdef BETTER_ENUMS_STRICT_CONVERSION # define BETTER_ENUMS_DEFAULT_SWITCH_TYPE \ BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE # define BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE \ BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE_GENERATE #else # define BETTER_ENUMS_DEFAULT_SWITCH_TYPE \ BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE # define BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE \ BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE_GENERATE #endif #ifndef BETTER_ENUMS_DEFAULT_CONSTRUCTOR # define BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum) \ private: \ Enum() : _value(0) { } #endif #ifdef BETTER_ENUMS_HAVE_CONSTEXPR #ifdef BETTER_ENUMS_CONSTEXPR_TO_STRING # define BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS \ BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS # define BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD \ BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD # define BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE \ BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE # define BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE \ BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE # define BETTER_ENUMS_DEFAULT_CALL_INITIALIZE \ BETTER_ENUMS_DO_NOT_CALL_INITIALIZE #else # define BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS \ BETTER_ENUMS_CXX11_PARTIAL_CONSTEXPR_TRIM_STRINGS_ARRAYS # define BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD \ BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD # define BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE \ BETTER_ENUMS_DO_DECLARE_INITIALIZE # define BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE \ BETTER_ENUMS_DO_DEFINE_INITIALIZE # define BETTER_ENUMS_DEFAULT_CALL_INITIALIZE \ BETTER_ENUMS_DO_CALL_INITIALIZE #endif // Top-level macros. #define BETTER_ENUM(Enum, Underlying, ...) \ BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \ BETTER_ENUMS_CXX11_UNDERLYING_TYPE, \ BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \ BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, \ BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS, \ BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD, \ BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE, \ BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE, \ BETTER_ENUMS_DEFAULT_CALL_INITIALIZE, \ Enum, Underlying, __VA_ARGS__)) #define SLOW_ENUM(Enum, Underlying, ...) \ BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \ BETTER_ENUMS_CXX11_UNDERLYING_TYPE, \ BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \ BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, \ BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS, \ BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD, \ BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE, \ BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE, \ BETTER_ENUMS_DO_NOT_CALL_INITIALIZE, \ Enum, Underlying, __VA_ARGS__)) #else #define BETTER_ENUM(Enum, Underlying, ...) \ BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \ BETTER_ENUMS_LEGACY_UNDERLYING_TYPE, \ BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \ BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, \ BETTER_ENUMS_CXX98_TRIM_STRINGS_ARRAYS, \ BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD, \ BETTER_ENUMS_DO_DECLARE_INITIALIZE, \ BETTER_ENUMS_DO_DEFINE_INITIALIZE, \ BETTER_ENUMS_DO_CALL_INITIALIZE, \ Enum, Underlying, __VA_ARGS__)) #endif namespace better_enums { // Maps. template struct map_compare { BETTER_ENUMS_CONSTEXPR_ static bool less(const T& a, const T& b) { return a < b; } }; template <> struct map_compare { BETTER_ENUMS_CONSTEXPR_ static bool less(const char *a, const char *b) { return less_loop(a, b); } private: BETTER_ENUMS_CONSTEXPR_ static bool less_loop(const char *a, const char *b, size_t index = 0) { return a[index] != b[index] ? a[index] < b[index] : a[index] == '\0' ? false : less_loop(a, b, index + 1); } }; // chenyao add template <> struct map_compare { BETTER_ENUMS_CONSTEXPR_ static bool less(const wchar_t *a, const wchar_t *b) { return less_loop(a, b); } private: BETTER_ENUMS_CONSTEXPR_ static bool less_loop(const wchar_t *a, const wchar_t *b, size_t index = 0) { return a[index] != b[index] ? a[index] < b[index] : a[index] == L'\0' ? false : less_loop(a, b, index + 1); } }; template > struct map { typedef T (*function)(Enum); BETTER_ENUMS_CONSTEXPR_ explicit map(function f) : _f(f) { } BETTER_ENUMS_CONSTEXPR_ T from_enum(Enum value) const { return _f(value); } BETTER_ENUMS_CONSTEXPR_ T operator [](Enum value) const { return _f(value); } BETTER_ENUMS_CONSTEXPR_ Enum to_enum(T value) const { return _or_throw(to_enum_nothrow(value), "map::to_enum: invalid argument"); } BETTER_ENUMS_CONSTEXPR_ optional to_enum_nothrow(T value, size_t index = 0) const { return index >= Enum::_size() ? optional() : Compare::less(_f(Enum::_values()[index]), value) || Compare::less(value, _f(Enum::_values()[index])) ? to_enum_nothrow(value, index + 1) : Enum::_values()[index]; } private: const function _f; }; template BETTER_ENUMS_CONSTEXPR_ map make_map(T (*f)(Enum)) { return map(f); } } #endif // #ifndef BETTER_ENUMS_ENUM_H ================================================ FILE: src/utils/geo.h ================================================ // // Some class templates for geometry primitives (point, interval, box) // #pragma once #include #include #include #include #include #include namespace utils { // Point template template class PointT { public: T x, y; PointT(T xx = std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : std::numeric_limits::max(), T yy = std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : std::numeric_limits::max()) : x(xx), y(yy) {} bool IsValid() { return *this != PointT(); } // Operators const T& operator[](const unsigned d) const { assert(d == 0 || d == 1); return (d == 0 ? x : y); } T& operator[](const unsigned d) { assert(d == 0 || d == 1); return (d == 0 ? x : y); } PointT operator+(const PointT& rhs) { return PointT(x + rhs.x, y + rhs.y); } PointT operator/(T divisor) { return PointT(x / divisor, y / divisor); } PointT& operator+=(const PointT& rhs) { x += rhs.x; y += rhs.y; return *this; } PointT& operator-=(const PointT& rhs) { x -= rhs.x; y -= rhs.y; return *this; } bool operator==(const PointT& rhs) const { return x == rhs.x && y == rhs.y; } bool operator!=(const PointT& rhs) const { return !(*this == rhs); } friend inline std::ostream& operator<<(std::ostream& os, const PointT& pt) { os << "(" << pt.x << ", " << pt.y << ")"; return os; } }; // L-1 (Manhattan) distance between points template inline T Dist(const PointT& pt1, const PointT& pt2) { return std::abs(pt1.x - pt2.x) + std::abs(pt1.y - pt2.y); } // L-2 (Euclidean) distance between points template inline double L2Dist(const PointT& pt1, const PointT& pt2) { return std::sqrt(std::pow(pt1.x - pt2.x, 2) + std::pow(pt1.y - pt2.y, 2)); } // L-inf distance between points template inline T LInfDist(const PointT& pt1, const PointT& pt2) { return std::max(std::abs(pt1.x - pt2.x), std::abs(pt1.y - pt2.y)); } // Interval template template class IntervalT { public: T low, high; template IntervalT(Args... params) { Set(params...); } // Setters void Set() { low = std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : std::numeric_limits::max(); high = std::numeric_limits::has_infinity ? -std::numeric_limits::infinity() : std::numeric_limits::lowest(); } void Set(T val) { low = val; high = val; } void Set(T lo, T hi) { low = lo; high = hi; } // Getters T center() const { return (high + low) / 2; } T range() const { return high - low; } // Update // Update() is always safe, FastUpdate() assumes existing values void Update(T newVal) { if (newVal < low) low = newVal; if (newVal > high) high = newVal; } void FastUpdate(T newVal) { if (newVal < low) low = newVal; else if (newVal > high) high = newVal; } // Two types of intervals: 1. normal, 2. degenerated (i.e., point) // is valid interval (i.e., valid closed interval) bool IsValid() const { return low <= high; } // is strictly valid interval (excluding degenerated ones, i.e., valid open interval) bool IsStrictValid() const { return low < high; } // Geometric Query/Update // interval/range of union (not union of intervals) IntervalT UnionWith(const IntervalT& rhs) const { if (!IsValid()) return rhs; else if (!rhs.IsValid()) return *this; else return IntervalT(std::min(low, rhs.low), std::max(high, rhs.high)); } // may return an invalid interval (as empty intersection) IntervalT IntersectWith(const IntervalT& rhs) const { return IntervalT(std::max(low, rhs.low), std::min(high, rhs.high)); } bool HasIntersectWith(const IntervalT& rhs) const { return IntersectWith(rhs).IsValid(); } bool HasStrictIntersectWith(const IntervalT& rhs) const { return IntersectWith(rhs).IsStrictValid(); } // Parallel run length between intervals T ParaRunLength(const IntervalT& rhs) const { return IntersectWith(rhs).range(); } // contain a val bool Contain(int val) const { return val >= low && val <= high; } bool StrictlyContain(int val) const { return val > low && val < high; } // get nearest point(s) to val (assume valid intervals) T GetNearestPointTo(T val) const { if (val <= low) { return low; } else if (val >= high) { return high; } else { return val; } } IntervalT GetNearestPointsTo(IntervalT val) const { if (val.high <= low) { return {low}; } else if (val.low >= high) { return {high}; } else { return IntersectWith(val); } } void ShiftBy(const T& rhs) { low += rhs; high += rhs; } // Operators bool operator==(const IntervalT& rhs) const { return (!IsValid() && !rhs.IsValid()) || (low == rhs.low && high == rhs.high); } bool operator!=(const IntervalT& rhs) const { return !(*this == rhs); } friend inline std::ostream& operator<<(std::ostream& os, const IntervalT& interval) { os << "(" << interval.low << ", " << interval.high << ")"; return os; } }; // Distance between intervals/points (assume valid intervals) template inline T Dist(const IntervalT& intvl, const T val) { return std::abs(intvl.GetNearestPointTo(val) - val); } template inline T Dist(const IntervalT& int1, const IntervalT& int2) { if (int1.high <= int2.low) { return int2.low - int1.high; } else if (int1.low >= int2.high) { return int1.low - int2.high; } else { return 0; } } // Box template template class BoxT { public: IntervalT x, y; template BoxT(Args... params) { Set(params...); } // Setters T& lx() { return x.low; } T& ly() { return y.low; } T& hy() { return y.high; } T& hx() { return x.high; } IntervalT& operator[](unsigned i) { assert(i == 0 || i == 1); return (i == 0) ? x : y; } void Set() { x.Set(); y.Set(); } void Set(T xVal, T yVal) { x.Set(xVal); y.Set(yVal); } void Set(const PointT& pt) { Set(pt.x, pt.y); } void Set(T lx, T ly, T hx, T hy) { x.Set(lx, hx); y.Set(ly, hy); } void Set(const IntervalT& xRange, const IntervalT& yRange) { x = xRange; y = yRange; } void Set(const PointT& low, const PointT& high) { Set(low.x, low.y, high.x, high.y); } void Set(const BoxT& box) { Set(box.x, box.y); } // Two types of boxes: normal & degenerated (line or point) // is valid box bool IsValid() const { return x.IsValid() && y.IsValid(); } // is strictly valid box (excluding degenerated ones) bool IsStrictValid() const { return x.IsStrictValid() && y.IsStrictValid(); } // tighter // Getters T lx() const { return x.low; } T ly() const { return y.low; } T hy() const { return y.high; } T hx() const { return x.high; } T cx() const { return x.center(); } T cy() const { return y.center(); } T width() const { return x.range(); } T height() const { return y.range(); } T hp() const { return width() + height(); } // half perimeter T area() const { return width() * height(); } const IntervalT& operator[](unsigned i) const { assert(i == 0 || i == 1); return (i == 0) ? x : y; } // Update() is always safe, FastUpdate() assumes existing values void Update(T xVal, T yVal) { x.Update(xVal); y.Update(yVal); } void FastUpdate(T xVal, T yVal) { x.FastUpdate(xVal); y.FastUpdate(yVal); } void Update(const PointT& pt) { Update(pt.x, pt.y); } void FastUpdate(const PointT& pt) { FastUpdate(pt.x, pt.y); } // Geometric Query/Update BoxT UnionWith(const BoxT& rhs) const { return {x.UnionWith(rhs.x), y.UnionWith(rhs.y)}; } BoxT IntersectWith(const BoxT& rhs) const { return {x.IntersectWith(rhs.x), y.IntersectWith(rhs.y)}; } bool HasIntersectWith(const BoxT& rhs) const { return IntersectWith(rhs).IsValid(); } bool HasStrictIntersectWith(const BoxT& rhs) const { return IntersectWith(rhs).IsStrictValid(); } // tighter bool Contain(const PointT& pt) const { return x.Contain(pt.x) && y.Contain(pt.y); } bool StrictlyContain(const PointT& pt) const { return x.StrictlyContain(pt.x) && y.StrictlyContain(pt.y); } PointT GetNearestPointTo(const PointT& pt) { return {x.GetNearestPointTo(pt.x), y.GetNearestPointTo(pt.y)}; } BoxT GetNearestPointsTo(BoxT val) const { return {x.GetNearestPointsTo(val.x), y.GetNearestPointsTo(val.y)}; } void ShiftBy(const PointT& rhs) { x.ShiftBy(rhs.x); y.ShiftBy(rhs.y); } bool operator==(const BoxT& rhs) const { return (x == rhs.x) && (y == rhs.y); } bool operator!=(const BoxT& rhs) const { return !(*this == rhs); } friend inline std::ostream& operator<<(std::ostream& os, const BoxT& box) { os << "[x: " << box.x << ", y: " << box.y << "]"; return os; } }; // L-1 (Manhattan) distance between boxes/points (assume valid boxes) template inline T Dist(const BoxT& box, const PointT& point) { return Dist(box.x, point.x) + Dist(box.y, point.y); } template inline T Dist(const BoxT& box1, const BoxT& box2) { return Dist(box1.x, box2.x) + Dist(box1.y, box2.y); } // L-2 (Euclidean) distance between boxes template inline double L2Dist(const BoxT& box1, const BoxT& box2) { return std::sqrt(std::pow(Dist(box1.x, box2.x), 2) + std::pow(Dist(box1.y, box2.y), 2)); } // L-Inf (max) distance between boxes template inline T LInfDist(const BoxT& box1, const BoxT& box2) { return std::max(Dist(box1.x, box2.x), Dist(box1.y, box2.y)); } // Parallel run length between boxes template inline T ParaRunLength(const BoxT& box1, const BoxT& box2) { return std::max(box1.x.ParaRunLength(box2.x), box1.y.ParaRunLength(box2.y)); } // Merge/stitch overlapped rectangles along mergeDir // mergeDir: 0 for x/vertical, 1 for y/horizontal // use BoxT instead of T & BoxT to make it more general template void MergeRects(std::vector& boxes, int mergeDir) { int boundaryDir = 1 - mergeDir; std::sort(boxes.begin(), boxes.end(), [&](const BoxT& lhs, const BoxT& rhs) { return lhs[boundaryDir].low < rhs[boundaryDir].low || (lhs[boundaryDir].low == rhs[boundaryDir].low && lhs[mergeDir].low < rhs[mergeDir].low); }); std::vector mergedBoxes; mergedBoxes.push_back(boxes.front()); for (int i = 1; i < boxes.size(); ++i) { auto& lastBox = mergedBoxes.back(); auto& slicedBox = boxes[i]; if (slicedBox[boundaryDir] == lastBox[boundaryDir] && slicedBox[mergeDir].low <= lastBox[mergeDir].high) { // aligned and intersected lastBox[mergeDir] = lastBox[mergeDir].UnionWith(slicedBox[mergeDir]); } else { // neither misaligned not seperated mergedBoxes.push_back(slicedBox); } } boxes = move(mergedBoxes); } // Slice polygons along sliceDir // sliceDir: 0 for x/vertical, 1 for y/horizontal // assume no degenerated case template void SlicePolygons(std::vector>& boxes, int sliceDir) { // Line sweep in sweepDir = 1 - sliceDir // Suppose sliceDir = y and sweepDir = x (sweep from left to right) // Not scalable impl (brute force interval query) but fast for small case if (boxes.size() <= 1) return; // sort slice lines in sweepDir int sweepDir = 1 - sliceDir; std::vector locs; for (const auto& box : boxes) { locs.push_back(box[sweepDir].low); locs.push_back(box[sweepDir].high); } std::sort(locs.begin(), locs.end()); locs.erase(std::unique(locs.begin(), locs.end()), locs.end()); // slice each box std::vector> slicedBoxes; for (const auto& box : boxes) { BoxT slicedBox = box; auto itLoc = std::lower_bound(locs.begin(), locs.end(), box[sweepDir].low); auto itEnd = std::upper_bound(itLoc, locs.end(), box[sweepDir].high); while ((itLoc + 1) != itEnd) { slicedBox[sweepDir].Set(*itLoc, *(itLoc + 1)); slicedBoxes.push_back(slicedBox); ++itLoc; } } boxes = move(slicedBoxes); // merge overlapped boxes along slice dir MergeRects(boxes, sliceDir); // stitch boxes along sweep dir MergeRects(boxes, sweepDir); } template class SegmentT : public BoxT { public: using BoxT::BoxT; T length() const { return BoxT::hp(); } bool IsRectilinear() const { return BoxT::x() == 0 || BoxT::y() == 0; } }; } // namespace utils ================================================ FILE: src/utils/log.cpp ================================================ #include "log.h" #include #include #if defined(__unix__) #include #include #elif defined(_WIN32) #include #include #endif namespace utils { timer::timer() { start(); } void timer::start() { _start = clock::now(); } double timer::elapsed() const { return std::chrono::duration(clock::now() - _start).count(); } timer tstamp; std::ostream& operator<<(std::ostream& os, const timer& t) { std::ostringstream oss; // seperate the impact of format oss << "[" << std::setprecision(3) << std::setw(8) << std::fixed << t.elapsed() << "] "; os << oss.str(); return os; } double mem_use::get_current() { #if defined(__unix__) long rss = 0L; FILE* fp = NULL; if ((fp = fopen("/proc/self/statm", "r")) == NULL) { return 0.0; /* Can't open? */ } if (fscanf(fp, "%*s%ld", &rss) != 1) { fclose(fp); return 0.0; /* Can't read? */ } fclose(fp); return rss * sysconf(_SC_PAGESIZE) / 1048576.0; #elif defined(_WIN32) PROCESS_MEMORY_COUNTERS info; GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); return info.WorkingSetSize / 1048576.0; #else return 0.0; // unknown #endif } double mem_use::get_peak() { #if defined(__unix__) struct rusage rusage; getrusage(RUSAGE_SELF, &rusage); return rusage.ru_maxrss / 1024.0; #elif defined(_WIN32) PROCESS_MEMORY_COUNTERS info; GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); return info.PeakWorkingSetSize / 1048576.0; #else return 0.0; // unknown #endif } std::ostream& log(std::ostream& os) { os << tstamp; return os; } } // namespace utils ================================================ FILE: src/utils/log.h ================================================ // // Some logging utilities // 1. "log() << ..." will show a time stamp first // 2. "print(a, b, c)" is python-like print for any a, b, c that has operator<< overloaded. For example, // int a = 10; // double b = 3.14; // std::string c = "Gengjie"; // print(a, b, c); // This code piece will show "10 3.14 Gengjie". // #pragma once #include #include #include namespace utils { // 1. Timer class timer { using clock = std::chrono::high_resolution_clock; private: clock::time_point _start; public: timer(); void start(); double elapsed() const; // seconds }; std::ostream& operator<<(std::ostream& os, const timer& t); // 2. Memory class mem_use { public: static double get_current(); // MB static double get_peak(); // MB }; // 3. Easy print // print(a, b, c) inline void print() { std::cout << std::endl; } template void print(const T& t, TAIL... tail) { std::cout << t << ' '; print(tail...); } // "log() << a << b << c" puts a time stamp in beginning std::ostream& log(std::ostream& os = std::cout); // "printlog(a, b, c)" puts a time stamp in beginning template void printlog(T... t) { log(); print(t...); } template void printflog(T... t) { log(); printf(t...); } } // namespace utils ================================================ FILE: src/utils/prettyprint.h ================================================ // // Pretty printing for C++ STL containers // // Usage: operator<< will "just work" for most STL containers, for example, // std::vector nums = {1, 2, 10}; // std::cout << nums << std::endl; // This code piece will show "1 2 10". // #pragma once #include #include #include #include namespace utils { // SFINAE has_begin_end template struct has_begin_end : std::false_type {}; template struct has_begin_end()), (void)std::end(std::declval()))> : std::true_type {}; // Holds the delimiter values for a specific character type template struct delimiters_values { using char_type = TChar; const char_type *prefix; const char_type *delimiter; const char_type *postfix; }; // Defines the delimiter values for a specific container and character type template struct delimiters { using type = delimiters_values; static const type values; }; // Functor to print containers. You can use this directly if you want // to specificy a non-default delimiters type. The printing logic can // be customized by specializing the nested template. template , typename TDelimiters = delimiters> struct print_container_helper { using delimiters_type = TDelimiters; using ostream_type = std::basic_ostream; template struct printer { static void print_body(const U &c, ostream_type &stream) { auto it = std::begin(c); const auto the_end = std::end(c); if (it != the_end) { for (;;) { stream << *it; if (++it == the_end) break; if (delimiters_type::values.delimiter != NULL) stream << delimiters_type::values.delimiter; } } } }; print_container_helper(const T &container) : container_(container) {} inline void operator()(ostream_type &stream) const { if (delimiters_type::values.prefix != NULL) stream << delimiters_type::values.prefix; printer::print_body(container_, stream); if (delimiters_type::values.postfix != NULL) stream << delimiters_type::values.postfix; } private: const T &container_; }; // Specialization for pairs template template struct print_container_helper::printer> { using ostream_type = typename print_container_helper::ostream_type; static void print_body(const std::pair &c, ostream_type &stream) { stream << c.first; if (print_container_helper::delimiters_type::values.delimiter != NULL) stream << print_container_helper::delimiters_type::values.delimiter; stream << c.second; } }; // Specialization for tuples template template struct print_container_helper::printer> { using ostream_type = typename print_container_helper::ostream_type; using element_type = std::tuple; template struct Int {}; static void print_body(const element_type &c, ostream_type &stream) { tuple_print(c, stream, Int<0>()); } static void tuple_print(const element_type &, ostream_type &, Int) {} static void tuple_print(const element_type &c, ostream_type &stream, typename std::conditional, std::nullptr_t>::type) { stream << std::get<0>(c); tuple_print(c, stream, Int<1>()); } template static void tuple_print(const element_type &c, ostream_type &stream, Int) { if (print_container_helper::delimiters_type::values.delimiter != NULL) stream << print_container_helper::delimiters_type::values.delimiter; stream << std::get(c); tuple_print(c, stream, Int()); } }; // Prints a print_container_helper to the specified stream. template inline std::basic_ostream &operator<<( std::basic_ostream &stream, const print_container_helper &helper) { helper(stream); return stream; } // Basic is_container template; specialize to derive from std::true_type for all desired container types template struct is_container : std::integral_constant::value> {}; template struct is_container> : std::true_type {}; template struct is_container> : std::true_type {}; // Default delimiters template struct delimiters { static constexpr delimiters_values values = {"[", ", ", "]"}; }; // Delimiters for (unordered_)(multi)set template struct delimiters> { static constexpr delimiters_values values = {"{", ", ", "}"}; }; template struct delimiters> { static constexpr delimiters_values values = {"{", ", ", "}"}; }; template struct delimiters> { static constexpr delimiters_values values = {"{", ", ", "}"}; }; template struct delimiters> { static constexpr delimiters_values values = {"{", ", ", "}"}; }; // Delimiters for pair and tuple template struct delimiters> { static constexpr delimiters_values values = {"(", ", ", ")"}; }; template struct delimiters> { static constexpr delimiters_values values = {"(", ", ", ")"}; }; // Type-erasing helper class for easy use of custom delimiters. // Requires TCharTraits = std::char_traits and TChar = char or wchar_t, and MyDelims needs to be defined for // TChar. Usage: "cout << pretty_print::custom_delims(x)". struct custom_delims_base { virtual ~custom_delims_base() {} virtual std::ostream &stream(std::ostream &) = 0; }; template struct custom_delims_wrapper : custom_delims_base { custom_delims_wrapper(const T &t_) : t(t_) {} std::ostream &stream(std::ostream &s) { return s << print_container_helper, Delims>(t); } private: const T &t; }; template struct custom_delims { template custom_delims(const Container &c) : base(new custom_delims_wrapper(c)) {} std::unique_ptr base; }; template inline std::basic_ostream &operator<<(std::basic_ostream &s, const custom_delims &p) { return p.base->stream(s); } } // namespace utils // Main magic entry point: An overload snuck into namespace std. // Can we do better? namespace std { // Prints a container to the stream using default delimiters template inline typename enable_if<::utils::is_container::value, basic_ostream &>::type operator<<( basic_ostream &stream, const T &container) { return stream << ::utils::print_container_helper(container); } template string to_string_with_precision(const T a_value, const int n = 6) { ostringstream out; out.precision(n); out << fixed << a_value; return out.str(); } } // namespace std ================================================ FILE: src/utils/utils.h ================================================ #pragma once #include "geo.h" #include "log.h" #include "prettyprint.h" #include "enum.h" ================================================ FILE: toys/iccad2019c/ispd18_sample/ispd18_sample.input.def ================================================ VERSION 5.8 ; DIVIDERCHAR "/" ; BUSBITCHARS "[]" ; DESIGN ispd18_sample ; UNITS DISTANCE MICRONS 2000 ; DIEAREA ( 83600 71820 ) ( 104400 91200 ) ; ROW CORE_ROW_0 CoreSite 83600 71820 N DO 52 BY 1 STEP 400 0 ; ROW CORE_ROW_1 CoreSite 83600 75240 FS DO 52 BY 1 STEP 400 0 ; ROW CORE_ROW_2 CoreSite 83600 78660 N DO 52 BY 1 STEP 400 0 ; ROW CORE_ROW_3 CoreSite 83600 82080 FS DO 52 BY 1 STEP 400 0 ; ROW CORE_ROW_4 CoreSite 83600 85500 N DO 52 BY 1 STEP 400 0 ; TRACKS X 83800 DO 52 STEP 400 LAYER Metal9 ; TRACKS Y 72770 DO 25 STEP 760 LAYER Metal9 ; TRACKS Y 72580 DO 33 STEP 570 LAYER Metal8 ; TRACKS X 83800 DO 52 STEP 400 LAYER Metal8 ; TRACKS X 83800 DO 52 STEP 400 LAYER Metal7 ; TRACKS Y 72580 DO 33 STEP 570 LAYER Metal7 ; TRACKS Y 72010 DO 51 STEP 380 LAYER Metal6 ; TRACKS X 83800 DO 52 STEP 400 LAYER Metal6 ; TRACKS X 83800 DO 52 STEP 400 LAYER Metal5 ; TRACKS Y 72010 DO 51 STEP 380 LAYER Metal5 ; TRACKS Y 72010 DO 51 STEP 380 LAYER Metal4 ; TRACKS X 83800 DO 52 STEP 400 LAYER Metal4 ; TRACKS X 83800 DO 52 STEP 400 LAYER Metal3 ; TRACKS Y 72010 DO 51 STEP 380 LAYER Metal3 ; TRACKS Y 72010 DO 51 STEP 380 LAYER Metal2 ; TRACKS X 83800 DO 52 STEP 400 LAYER Metal2 ; TRACKS X 83800 DO 52 STEP 400 LAYER Metal1 ; TRACKS Y 72010 DO 51 STEP 380 LAYER Metal1 ; COMPONENTS 22 ; - inst2015 NAND3X2 + PLACED ( 88000 78660 ) N ; - inst2591 NAND4X2 + PLACED ( 100000 71820 ) N ; - inst2908 OR4X1 + PLACED ( 85600 75240 ) FS ; - inst3428 BUFX3 + PLACED ( 86000 82080 ) FS ; - inst3502 NOR4X2 + PLACED ( 92800 75240 ) FS ; - inst3444 BUFX3 + PLACED ( 96800 82080 ) FS ; - inst4132 NAND4X1 + PLACED ( 102000 85500 ) N ; - inst4183 NOR4X4 + PLACED ( 96800 75240 ) FS ; - inst4062 AOI222X1 + PLACED ( 96000 85500 ) N ; - inst4678 NOR2X1 + PLACED ( 90800 82080 ) FS ; - inst4189 AOI22X2 + PLACED ( 85200 71820 ) N ; - inst4597 NAND4X1 + PLACED ( 94400 71820 ) N ; - inst4382 NAND4X1 + PLACED ( 84000 78660 ) N ; - inst5333 AOI221X1 + PLACED ( 89200 85500 ) N ; - inst5638 BUFX6 + PLACED ( 96000 78660 ) N ; - inst6286 AO22XL + PLACED ( 100000 78660 ) N ; - inst5275 AOI22X1 + PLACED ( 89600 75240 ) FS ; - inst5821 NAND3X1 + PLACED ( 84400 85500 ) N ; - inst6458 AOI221X2 + PLACED ( 99200 82080 ) FS ; - inst6050 NAND4X1 + PLACED ( 97200 71820 ) N ; - inst5195 AOI221X1 + PLACED ( 89600 71820 ) N ; - inst7234 AO22XL + PLACED ( 93200 82080 ) FS ; END COMPONENTS PINS 0 ; END PINS NETS 11 ; - net1237 ( inst5638 A ) ( inst4678 Y ) ; - net1240 ( inst3502 A ) ( inst2015 Y ) ; - net1233 ( inst6050 A ) ( inst4189 Y ) ; - net1236 ( inst2908 D ) ( inst2591 Y ) ; - net1234 ( inst6458 Y ) ( inst4597 B ) ; - net1232 ( inst4382 C ) ( inst4062 Y ) ; - net1231 ( inst5821 B ) ( inst5275 Y ) ; - net1239 ( inst6286 Y ) ( inst5333 C0 ) ; - net1235 ( inst4183 A ) ( inst4132 Y ) ; - net1238 ( inst3444 Y ) ( inst3428 A ) ; - net1230 ( inst7234 Y ) ( inst5195 C0 ) ; END NETS END DESIGN ================================================ FILE: toys/iccad2019c/ispd18_sample/ispd18_sample.input.lef ================================================ VERSION 5.8 ; BUSBITCHARS "[]" ; DIVIDERCHAR "/" ; UNITS DATABASE MICRONS 2000 ; END UNITS MANUFACTURINGGRID 0.000500 ; CLEARANCEMEASURE EUCLIDEAN ; USEMINSPACING OBS ON ; SITE CoreSite CLASS CORE ; SIZE 0.200000 BY 1.710000 ; END CoreSite LAYER Metal1 TYPE ROUTING ; DIRECTION HORIZONTAL ; MINWIDTH 0.060000 ; AREA 0.020000 ; WIDTH 0.060000 ; SPACING 0.060000 ; SPACING 0.090000 ENDOFLINE 0.090000 WITHIN 0.025000 ; SPACINGTABLE PARALLELRUNLENGTH 0.000000 WIDTH 0.000000 0.060000 WIDTH 0.100000 0.100000 WIDTH 0.750000 0.250000 WIDTH 1.500000 0.450000 ; PITCH 0.190000 0.190000 ; END Metal1 LAYER Via1 TYPE CUT ; SPACING 0.070000 ; WIDTH 0.06 ; END Via1 LAYER Metal2 TYPE ROUTING ; DIRECTION VERTICAL ; MINWIDTH 0.070000 ; AREA 0.020000 ; WIDTH 0.070000 ; SPACING 0.070000 ; SPACING 0.100000 ENDOFLINE 0.100000 WITHIN 0.035000 ; SPACINGTABLE PARALLELRUNLENGTH 0.000000 WIDTH 0.000000 0.070000 WIDTH 0.100000 0.150000 WIDTH 0.750000 0.250000 WIDTH 1.500000 0.450000 ; PITCH 0.200000 0.200000 ; END Metal2 LAYER Via2 TYPE CUT ; SPACING 0.070000 ; WIDTH 0.07 ; END Via2 LAYER Metal3 TYPE ROUTING ; DIRECTION HORIZONTAL ; MINWIDTH 0.070000 ; AREA 0.020000 ; WIDTH 0.070000 ; SPACING 0.070000 ; SPACING 0.100000 ENDOFLINE 0.100000 WITHIN 0.035000 ; SPACINGTABLE PARALLELRUNLENGTH 0.000000 WIDTH 0.000000 0.070000 WIDTH 0.100000 0.150000 WIDTH 0.750000 0.250000 WIDTH 1.500000 0.450000 ; PITCH 0.200000 0.200000 ; END Metal3 LAYER Via3 TYPE CUT ; SPACING 0.070000 ; WIDTH 0.07 ; END Via3 LAYER Metal4 TYPE ROUTING ; DIRECTION VERTICAL ; MINWIDTH 0.070000 ; AREA 0.020000 ; WIDTH 0.070000 ; SPACING 0.070000 ; SPACING 0.100000 ENDOFLINE 0.100000 WITHIN 0.035000 ; SPACINGTABLE PARALLELRUNLENGTH 0.000000 WIDTH 0.000000 0.070000 WIDTH 0.100000 0.150000 WIDTH 0.750000 0.250000 WIDTH 1.500000 0.450000 ; PITCH 0.200000 0.200000 ; END Metal4 LAYER Via4 TYPE CUT ; SPACING 0.070000 ; WIDTH 0.07 ; END Via4 LAYER Metal5 TYPE ROUTING ; DIRECTION HORIZONTAL ; MINWIDTH 0.070000 ; AREA 0.020000 ; WIDTH 0.070000 ; SPACING 0.070000 ; SPACING 0.100000 ENDOFLINE 0.100000 WITHIN 0.035000 ; SPACINGTABLE PARALLELRUNLENGTH 0.000000 WIDTH 0.000000 0.070000 WIDTH 0.100000 0.150000 WIDTH 0.750000 0.250000 WIDTH 1.500000 0.450000 ; PITCH 0.200000 0.200000 ; END Metal5 LAYER Via5 TYPE CUT ; SPACING 0.070000 ; WIDTH 0.07 ; END Via5 LAYER Metal6 TYPE ROUTING ; DIRECTION VERTICAL ; MINWIDTH 0.070000 ; AREA 0.020000 ; WIDTH 0.070000 ; SPACING 0.070000 ; SPACING 0.100000 ENDOFLINE 0.100000 WITHIN 0.035000 ; SPACINGTABLE PARALLELRUNLENGTH 0.000000 WIDTH 0.000000 0.070000 WIDTH 0.100000 0.150000 WIDTH 0.750000 0.250000 WIDTH 1.500000 0.450000 ; PITCH 0.200000 0.200000 ; END Metal6 LAYER Via6 TYPE CUT ; SPACING 0.070000 ; WIDTH 0.07 ; END Via6 LAYER Metal7 TYPE ROUTING ; DIRECTION HORIZONTAL ; MINWIDTH 0.070000 ; AREA 0.020000 ; WIDTH 0.070000 ; SPACING 0.070000 ; SPACING 0.100000 ENDOFLINE 0.100000 WITHIN 0.035000 ; SPACINGTABLE PARALLELRUNLENGTH 0.000000 WIDTH 0.000000 0.070000 WIDTH 0.100000 0.150000 WIDTH 0.750000 0.250000 WIDTH 1.500000 0.450000 ; PITCH 0.200000 0.200000 ; END Metal7 LAYER Via7 TYPE CUT ; SPACING 0.070000 ; WIDTH 0.07 ; END Via7 LAYER Metal8 TYPE ROUTING ; DIRECTION VERTICAL ; MINWIDTH 0.070000 ; AREA 0.020000 ; WIDTH 0.070000 ; SPACING 0.070000 ; SPACING 0.100000 ENDOFLINE 0.100000 WITHIN 0.035000 ; SPACINGTABLE PARALLELRUNLENGTH 0.000000 WIDTH 0.000000 0.070000 WIDTH 0.100000 0.150000 WIDTH 0.750000 0.250000 WIDTH 1.500000 0.450000 ; PITCH 0.200000 0.200000 ; END Metal8 LAYER Via8 TYPE CUT ; SPACING 0.070000 ; WIDTH 0.07 ; END Via8 LAYER Metal9 TYPE ROUTING ; DIRECTION HORIZONTAL ; MINWIDTH 0.070000 ; AREA 0.020000 ; WIDTH 0.070000 ; SPACING 0.070000 ; SPACING 0.100000 ENDOFLINE 0.100000 WITHIN 0.035000 ; SPACINGTABLE PARALLELRUNLENGTH 0.000000 WIDTH 0.000000 0.070000 WIDTH 0.100000 0.150000 WIDTH 0.750000 0.250000 WIDTH 1.500000 0.450000 ; PITCH 0.330000 0.330000 ; END Metal9 LAYER OVERLAP TYPE OVERLAP ; END OVERLAP VIA VIA12_1C DEFAULT LAYER Metal1 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; LAYER Via1 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal2 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; END VIA12_1C VIA VIA12_1C_H DEFAULT LAYER Metal1 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; LAYER Via1 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal2 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA12_1C_H VIA VIA12_1C_V DEFAULT LAYER Metal1 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; LAYER Via1 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal2 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; END VIA12_1C_V VIA VIA23_1C DEFAULT LAYER Metal2 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; LAYER Via2 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal3 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA23_1C VIA VIA23_1C_H DEFAULT LAYER Metal2 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; LAYER Via2 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal3 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA23_1C_H VIA VIA23_1C_V DEFAULT LAYER Metal2 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; LAYER Via2 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal3 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; END VIA23_1C_V VIA VIA23_1ST_N DEFAULT LAYER Metal2 ; RECT -0.035000 -0.065000 0.035000 0.325000 ; LAYER Via2 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal3 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA23_1ST_N VIA VIA23_1ST_S DEFAULT LAYER Metal2 ; RECT -0.035000 -0.325000 0.035000 0.065000 ; LAYER Via2 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal3 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA23_1ST_S VIA VIA34_1C DEFAULT LAYER Metal3 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; LAYER Via3 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal4 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; END VIA34_1C VIA VIA34_1C_H DEFAULT LAYER Metal3 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; LAYER Via3 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal4 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA34_1C_H VIA VIA34_1C_V DEFAULT LAYER Metal3 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; LAYER Via3 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal4 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; END VIA34_1C_V VIA VIA34_1ST_E DEFAULT LAYER Metal3 ; RECT -0.065000 -0.035000 0.325000 0.035000 ; LAYER Via3 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal4 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; END VIA34_1ST_E VIA VIA34_1ST_W DEFAULT LAYER Metal3 ; RECT -0.325000 -0.035000 0.065000 0.035000 ; LAYER Via3 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal4 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; END VIA34_1ST_W VIA VIA45_1C DEFAULT LAYER Metal4 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; LAYER Via4 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal5 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA45_1C VIA VIA45_1C_H DEFAULT LAYER Metal4 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; LAYER Via4 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal5 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA45_1C_H VIA VIA45_1C_V DEFAULT LAYER Metal4 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; LAYER Via4 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal5 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; END VIA45_1C_V VIA VIA45_1ST_N DEFAULT LAYER Metal4 ; RECT -0.035000 -0.065000 0.035000 0.325000 ; LAYER Via4 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal5 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA45_1ST_N VIA VIA45_1ST_S DEFAULT LAYER Metal4 ; RECT -0.035000 -0.325000 0.035000 0.065000 ; LAYER Via4 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal5 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA45_1ST_S VIA VIA5_0_VH DEFAULT LAYER Metal5 ; RECT -0.035000 -0.065000 0.035000 0.065000 ; LAYER Via5 ; RECT -0.035000 -0.035000 0.035000 0.035000 ; LAYER Metal6 ; RECT -0.065000 -0.035000 0.065000 0.035000 ; END VIA5_0_VH VIA VIA6_0_HV DEFAULT LAYER Metal6 ; RECT -0.260000 -0.200000 0.260000 0.200000 ; LAYER Via6 ; RECT -0.180000 -0.180000 0.180000 0.180000 ; LAYER Metal7 ; RECT -0.200000 -0.260000 0.200000 0.260000 ; END VIA6_0_HV VIA VIA7_0_VH DEFAULT LAYER Metal7 ; RECT -0.200000 -0.260000 0.200000 0.260000 ; LAYER Via7 ; RECT -0.180000 -0.180000 0.180000 0.180000 ; LAYER Metal8 ; RECT -0.260000 -0.200000 0.260000 0.200000 ; END VIA7_0_VH VIA VIA8_0_VH DEFAULT LAYER Metal8 ; RECT -0.200000 -0.260000 0.200000 0.260000 ; LAYER Via8 ; RECT -0.180000 -0.180000 0.180000 0.180000 ; LAYER Metal9 ; RECT -0.260000 -0.200000 0.260000 0.200000 ; END VIA8_0_VH MACRO AOI221X2 CLASS CORE ; FOREIGN AOI221X2 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 2.600000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.235000 0.625000 0.365000 0.715000 ; RECT 0.285000 0.610000 0.960000 0.690000 ; RECT 0.285000 0.610000 0.365000 0.715000 ; RECT 0.235000 0.625000 0.960000 0.690000 ; END END A0 PIN A1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.660000 0.765000 0.740000 1.065000 ; END END A1 PIN B0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.635000 0.625000 1.765000 0.715000 ; RECT 1.240000 0.635000 1.935000 0.715000 ; END END B0 PIN B1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.435000 0.815000 1.935000 0.895000 ; END END B1 PIN C0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 2.065000 0.815000 2.565000 0.895000 ; END END C0 PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 2.600000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 2.600000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.060000 0.790000 1.140000 0.920000 ; RECT 2.220000 0.995000 2.280000 1.135000 ; RECT 1.080000 0.995000 2.280000 1.055000 ; RECT 1.080000 0.450000 1.140000 1.055000 ; RECT 0.605000 0.450000 2.170000 0.510000 ; END END Y END AOI221X2 MACRO NAND3X2 CLASS CORE ; FOREIGN NAND3X2 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 1.600000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.260000 0.600000 0.370000 0.735000 ; RECT 1.240000 0.495000 1.300000 0.735000 ; RECT 0.310000 0.495000 1.300000 0.555000 ; RECT 0.310000 0.495000 0.370000 0.735000 ; END END A PIN B DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.060000 0.655000 1.140000 0.920000 ; RECT 0.470000 0.655000 1.140000 0.715000 ; END END B PIN C DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.520000 0.815000 0.765000 0.955000 ; RECT 0.520000 0.815000 0.960000 0.895000 ; END END C PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 1.600000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 1.600000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.435000 1.005000 1.565000 1.115000 ; RECT 0.360000 1.055000 0.430000 1.335000 ; RECT 1.505000 0.335000 1.565000 1.115000 ; RECT 1.190000 1.055000 1.250000 1.335000 ; RECT 0.795000 0.335000 1.565000 0.395000 ; RECT 0.780000 1.055000 0.840000 1.335000 ; RECT 0.360000 1.055000 1.565000 1.115000 ; END END Y END NAND3X2 MACRO AOI222X1 CLASS CORE ; FOREIGN AOI222X1 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 1.800000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.260000 0.490000 0.340000 0.990000 ; END END A0 PIN A1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.460000 0.220000 0.545000 0.715000 ; END END A1 PIN B0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.880000 0.860000 1.095000 1.100000 ; RECT 0.860000 0.755000 0.940000 0.920000 ; RECT 0.880000 0.755000 0.940000 1.100000 ; RECT 0.860000 0.860000 1.095000 0.920000 ; END END B0 PIN B1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.660000 0.620000 0.760000 0.920000 ; RECT 0.680000 0.620000 0.760000 1.100000 ; END END B1 PIN C0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.195000 0.790000 1.340000 0.920000 ; RECT 1.195000 0.790000 1.275000 1.225000 ; END END C0 PIN C1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.440000 0.620000 1.540000 1.100000 ; END END C1 PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 1.800000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 1.800000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.450000 0.410000 1.720000 0.520000 ; RECT 1.660000 0.980000 1.740000 1.260000 ; RECT 1.660000 0.410000 1.720000 1.260000 ; RECT 1.375000 1.200000 1.740000 1.260000 ; RECT 1.375000 1.200000 1.435000 1.320000 ; RECT 0.760000 0.460000 1.720000 0.520000 ; RECT 0.760000 0.380000 0.820000 0.520000 ; END END Y END AOI222X1 MACRO NOR4X4 CLASS CORE ; FOREIGN NOR4X4 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 3.800000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.860000 0.755000 0.940000 0.950000 ; RECT 0.350000 0.870000 0.940000 0.950000 ; END END A PIN B DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.725000 0.755000 1.805000 0.895000 ; RECT 1.240000 0.815000 1.805000 0.895000 ; END END B PIN C DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 2.435000 0.775000 2.570000 0.895000 ; RECT 2.110000 0.815000 2.570000 0.895000 ; END END C PIN D DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 3.105000 0.775000 3.185000 0.895000 ; RECT 2.835000 0.815000 3.420000 0.895000 ; END END D PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 3.800000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 3.800000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.060000 0.790000 1.140000 0.920000 ; RECT 3.460000 0.515000 3.520000 0.655000 ; RECT 3.405000 0.995000 3.465000 1.135000 ; RECT 3.050000 0.515000 3.110000 0.655000 ; RECT 2.995000 0.995000 3.055000 1.135000 ; RECT 2.640000 0.515000 2.700000 0.655000 ; RECT 2.230000 0.515000 2.290000 0.655000 ; RECT 1.820000 0.515000 1.880000 0.655000 ; RECT 1.410000 0.515000 1.470000 0.655000 ; RECT 1.080000 0.995000 3.465000 1.055000 ; RECT 1.080000 0.595000 1.140000 1.055000 ; RECT 1.000000 0.515000 1.060000 0.655000 ; RECT 0.590000 0.595000 3.520000 0.655000 ; RECT 0.590000 0.515000 0.650000 0.655000 ; END END Y END NOR4X4 MACRO NOR4X2 CLASS CORE ; FOREIGN NOR4X2 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 2.000000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.660000 0.980000 1.740000 1.185000 ; RECT 1.680000 0.820000 1.740000 1.185000 ; RECT 0.260000 1.125000 1.740000 1.185000 ; RECT 0.260000 0.820000 0.320000 1.185000 ; END END A PIN B DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.460000 0.790000 0.540000 0.920000 ; RECT 1.435000 0.845000 1.495000 1.025000 ; RECT 0.480000 0.965000 1.495000 1.025000 ; RECT 0.480000 0.790000 0.540000 1.025000 ; RECT 0.420000 0.835000 0.540000 0.895000 ; END END B PIN C DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.275000 0.625000 1.565000 0.705000 ; RECT 1.275000 0.625000 1.335000 0.865000 ; RECT 0.640000 0.805000 1.335000 0.865000 ; END END C PIN D DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.640000 0.625000 1.140000 0.705000 ; END END D PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 2.000000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 2.000000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.860000 1.170000 1.940000 1.345000 ; RECT 1.595000 0.445000 1.715000 0.525000 ; RECT 1.155000 0.445000 1.275000 0.525000 ; RECT 0.715000 0.445000 0.835000 0.525000 ; RECT 1.880000 0.465000 1.940000 1.345000 ; RECT 1.010000 1.285000 1.940000 1.345000 ; RECT 0.345000 0.465000 1.940000 0.525000 ; RECT 0.275000 0.445000 0.395000 0.505000 ; END END Y END NOR4X2 MACRO NAND4X2 CLASS CORE ; FOREIGN NAND4X2 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 2.200000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.860000 0.820000 1.940000 1.185000 ; RECT 0.260000 1.125000 1.940000 1.185000 ; RECT 0.260000 0.820000 0.320000 1.185000 ; END END A PIN B DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.460000 0.790000 0.540000 0.920000 ; RECT 1.600000 0.845000 1.660000 1.025000 ; RECT 0.480000 0.965000 1.660000 1.025000 ; RECT 0.480000 0.790000 0.540000 1.025000 ; RECT 0.420000 0.835000 0.540000 0.895000 ; END END B PIN C DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.235000 0.625000 1.395000 0.705000 ; RECT 1.335000 0.625000 1.395000 0.865000 ; RECT 0.685000 0.805000 1.395000 0.865000 ; END END C PIN D DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.860000 0.625000 1.135000 0.705000 ; RECT 0.860000 0.400000 0.940000 0.705000 ; END END D PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 2.200000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 2.200000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 2.060000 1.170000 2.140000 1.345000 ; RECT 2.060000 0.465000 2.120000 1.345000 ; RECT 1.730000 1.285000 1.790000 1.405000 ; RECT 1.260000 1.285000 1.320000 1.405000 ; RECT 1.185000 0.465000 2.120000 0.525000 ; RECT 1.070000 0.445000 1.235000 0.505000 ; RECT 0.790000 1.285000 0.850000 1.405000 ; RECT 0.320000 1.285000 2.140000 1.345000 ; RECT 0.320000 1.285000 0.380000 1.405000 ; END END Y END NAND4X2 MACRO BUFX3 CLASS CORE ; FOREIGN BUFX3 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 1.200000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.860000 0.720000 0.940000 1.220000 ; END END A PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 1.200000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 1.200000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.260000 0.980000 0.340000 1.110000 ; RECT 0.625000 1.050000 0.685000 1.440000 ; RECT 0.585000 0.345000 0.645000 0.465000 ; RECT 0.540000 0.405000 0.645000 0.465000 ; RECT 0.540000 0.405000 0.600000 0.620000 ; RECT 0.260000 0.560000 0.320000 1.110000 ; RECT 0.215000 1.050000 0.685000 1.110000 ; RECT 0.215000 1.050000 0.275000 1.440000 ; RECT 0.175000 0.560000 0.600000 0.620000 ; RECT 0.175000 0.480000 0.235000 0.620000 ; END END Y END BUFX3 MACRO AOI22X2 CLASS CORE ; FOREIGN AOI22X2 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 2.200000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.840000 0.635000 1.065000 0.715000 ; RECT 0.840000 0.575000 0.920000 0.715000 ; RECT 0.480000 0.575000 0.920000 0.655000 ; RECT 0.480000 0.575000 0.560000 0.705000 ; RECT 0.235000 0.625000 0.560000 0.705000 ; END END A0 PIN A1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.655000 0.715000 0.745000 0.960000 ; END END A1 PIN B0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.840000 0.580000 1.960000 0.895000 ; RECT 1.840000 0.815000 2.165000 0.895000 ; RECT 1.500000 0.580000 1.960000 0.640000 ; RECT 1.500000 0.580000 1.560000 0.715000 ; RECT 1.325000 0.655000 1.560000 0.715000 ; END END B0 PIN B1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.660000 0.740000 1.740000 1.030000 ; END END B1 PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 2.200000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 2.200000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.035000 0.815000 1.225000 0.895000 ; RECT 1.840000 0.995000 1.900000 1.165000 ; RECT 1.430000 1.105000 1.900000 1.165000 ; RECT 1.430000 0.835000 1.490000 1.165000 ; RECT 1.165000 0.415000 1.225000 0.895000 ; RECT 1.035000 0.835000 1.490000 0.895000 ; RECT 0.710000 0.415000 1.685000 0.475000 ; END END Y END AOI22X2 MACRO OR4X1 CLASS CORE ; FOREIGN OR4X1 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 1.400000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.060000 0.475000 1.140000 0.765000 ; RECT 0.850000 0.685000 1.140000 0.765000 ; END END A PIN B DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.460000 0.980000 0.590000 1.070000 ; RECT 0.510000 0.660000 0.590000 1.070000 ; RECT 0.460000 0.980000 0.540000 1.110000 ; END END B PIN C DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.330000 0.590000 0.410000 0.870000 ; RECT 0.260000 0.790000 0.410000 0.870000 ; RECT 0.260000 0.790000 0.340000 1.020000 ; END END C PIN D DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.060000 0.590000 0.160000 0.795000 ; RECT 0.030000 0.735000 0.120000 1.040000 ; RECT 0.060000 0.590000 0.120000 1.040000 ; RECT 0.030000 0.735000 0.160000 0.795000 ; END END D PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 1.400000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 1.400000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.240000 0.410000 1.340000 0.540000 ; RECT 1.240000 0.395000 1.300000 1.385000 ; END END Y END OR4X1 MACRO NAND3X1 CLASS CORE ; FOREIGN NAND3X1 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 1.000000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.260000 0.600000 0.340000 1.100000 ; END END A PIN B DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.480000 0.480000 0.560000 0.890000 ; RECT 0.460000 0.410000 0.540000 0.540000 ; RECT 0.480000 0.410000 0.540000 0.890000 ; RECT 0.460000 0.480000 0.560000 0.540000 ; END END B PIN C DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.660000 0.600000 0.740000 1.100000 ; END END C PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 1.000000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 1.000000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.860000 1.200000 0.940000 1.490000 ; RECT 0.860000 0.440000 0.920000 1.490000 ; RECT 0.745000 0.440000 0.920000 0.500000 ; RECT 0.745000 0.380000 0.805000 0.500000 ; RECT 0.425000 1.200000 0.940000 1.260000 ; RECT 0.425000 1.200000 0.485000 1.480000 ; END END Y END NAND3X1 MACRO NOR2X1 CLASS CORE ; FOREIGN NOR2X1 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 0.800000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.260000 0.570000 0.340000 1.070000 ; END END A PIN B DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.460000 0.980000 0.560000 1.085000 ; RECT 0.480000 0.730000 0.560000 1.085000 ; RECT 0.460000 0.980000 0.540000 1.210000 ; RECT 0.480000 0.730000 0.540000 1.210000 ; END END B PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 0.800000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 0.800000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.660000 0.600000 0.740000 0.730000 ; RECT 0.660000 0.570000 0.720000 1.290000 ; RECT 0.460000 0.570000 0.720000 0.630000 ; RECT 0.460000 0.490000 0.520000 0.630000 ; END END Y END NOR2X1 MACRO AOI221X1 CLASS CORE ; FOREIGN AOI221X1 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 1.800000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.260000 0.450000 0.340000 0.950000 ; END END A0 PIN A1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.460000 0.220000 0.540000 0.720000 ; END END A1 PIN B0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.060000 0.580000 1.140000 1.080000 ; END END B0 PIN B1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.860000 0.580000 0.940000 1.080000 ; END END B1 PIN C0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.260000 0.650000 1.380000 0.730000 ; RECT 1.260000 0.580000 1.340000 1.040000 ; END END C0 PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 1.800000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 1.800000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.460000 0.220000 1.540000 0.480000 ; RECT 1.480000 0.220000 1.540000 1.460000 ; RECT 0.870000 0.420000 1.540000 0.480000 ; RECT 0.800000 0.400000 0.920000 0.460000 ; END END Y END AOI221X1 MACRO NAND4X1 CLASS CORE ; FOREIGN NAND4X1 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 1.200000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.230000 0.650000 0.340000 0.920000 ; RECT 0.030000 0.840000 0.340000 0.920000 ; END END A PIN B DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.480000 0.460000 0.560000 0.890000 ; RECT 0.460000 0.460000 0.560000 0.540000 ; RECT 0.460000 0.410000 0.540000 0.540000 ; RECT 0.480000 0.410000 0.540000 0.890000 ; END END B PIN C DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.660000 0.220000 0.740000 0.830000 ; END END C PIN D DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.860000 0.410000 0.940000 0.910000 ; END END D PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 1.200000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 1.200000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.040000 0.790000 1.140000 1.080000 ; RECT 1.040000 0.540000 1.100000 1.080000 ; RECT 0.790000 1.020000 0.850000 1.300000 ; RECT 0.370000 1.020000 1.140000 1.080000 ; RECT 0.370000 1.020000 0.430000 1.300000 ; END END Y END NAND4X1 MACRO AOI22X1 CLASS CORE ; FOREIGN AOI22X1 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 1.400000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.260000 0.600000 0.340000 1.100000 ; END END A0 PIN A1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.480000 0.270000 0.560000 0.700000 ; RECT 0.460000 0.270000 0.560000 0.350000 ; RECT 0.460000 0.220000 0.540000 0.350000 ; RECT 0.480000 0.220000 0.540000 0.700000 ; END END A1 PIN B0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.060000 0.450000 1.140000 0.950000 ; END END B0 PIN B1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.860000 0.410000 0.940000 0.910000 ; END END B1 PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 1.400000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 1.400000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.660000 0.980000 0.740000 1.110000 ; RECT 0.935000 1.050000 0.995000 1.190000 ; RECT 0.680000 0.370000 0.740000 1.110000 ; RECT 0.660000 1.050000 0.995000 1.110000 ; END END Y END AOI22X1 MACRO BUFX6 CLASS CORE ; FOREIGN BUFX6 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 1.800000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.460000 0.570000 1.540000 1.070000 ; END END A PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 1.800000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 1.800000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.060000 0.790000 0.140000 0.975000 ; RECT 0.060000 0.350000 0.130000 1.370000 ; RECT 0.890000 0.915000 0.950000 1.370000 ; RECT 0.890000 0.350000 0.950000 0.655000 ; RECT 0.480000 0.915000 0.540000 1.370000 ; RECT 0.480000 0.350000 0.540000 0.655000 ; RECT 0.060000 0.915000 0.950000 0.975000 ; RECT 0.060000 0.595000 0.950000 0.655000 ; END END Y END BUFX6 MACRO AO22XL CLASS CORE ; FOREIGN AO22XL 0.000000 0.000000 ; ORIGIN 0.000000 0.000000 ; SIZE 1.600000 BY 1.710000 ; SYMMETRY X Y ; SITE CoreSite ; PIN A0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.260000 0.600000 0.340000 1.100000 ; END END A0 PIN A1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.460000 0.230000 0.540000 0.730000 ; END END A1 PIN B0 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.060000 0.790000 1.140000 1.230000 ; RECT 1.000000 0.790000 1.140000 0.870000 ; END END B0 PIN B1 DIRECTION INPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 0.660000 0.595000 0.740000 1.095000 ; END END B1 PIN VDD DIRECTION INOUT ; SHAPE ABUTMENT ; USE POWER ; PORT LAYER Metal1 ; RECT 0.000000 1.650000 1.600000 1.710000 ; END END VDD PIN VSS DIRECTION INOUT ; SHAPE ABUTMENT ; USE GROUND ; PORT LAYER Metal1 ; RECT 0.000000 0.000000 1.600000 0.060000 ; END END VSS PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER Metal1 ; RECT 1.260000 0.910000 1.510000 0.990000 ; RECT 1.260000 0.600000 1.340000 0.990000 ; RECT 1.250000 0.600000 1.340000 0.680000 ; RECT 1.250000 0.405000 1.330000 0.680000 ; RECT 1.260000 0.405000 1.330000 0.990000 ; END END Y END AO22XL END LIBRARY