├── .gitignore ├── src ├── global │ ├── constant.h │ ├── namespace.h │ ├── define.h │ ├── global.h │ ├── type.h │ └── parameter.h ├── main │ └── main.cpp ├── api │ ├── api.cpp │ └── IdeaPlaceExAPI.cpp ├── db │ ├── Parameters.cpp │ ├── Pin.h │ ├── Parameters.h │ ├── Constraints.h │ ├── Net.h │ └── Tech.h ├── util │ ├── StopWatch.cpp │ ├── Assert.h │ ├── MsgPrinter.h │ ├── linear_programming.h │ ├── GdsHelper.h │ ├── StopWatch.hpp │ ├── BasicTypeSelection.h │ ├── MsgPrinter.cpp │ ├── linear_programming_trait.h │ ├── Polygon2Rect.h │ ├── XY.h │ ├── XYZ.h │ ├── Vector2D.h │ └── lp_limbo.h ├── parser │ ├── ParserPin.h │ ├── ParserConnection.h │ ├── ParserSignalPath.h │ ├── ParserSymFile.h │ ├── ParserSymNet.h │ ├── ParserTechSimple.h │ ├── ParserSignalPath.cpp │ ├── ParserNetwgt.h │ ├── ParserGds.cpp │ ├── ParserSymFile.cpp │ ├── ParserSymNet.cpp │ ├── ParserPin.cpp │ ├── ProgArgs.cpp │ ├── ParserConnection.cpp │ ├── ProgArgs.h │ └── ParserGds.h ├── place │ ├── nlp │ │ ├── nlpTypes.hpp │ │ ├── nlpInitPlace.hpp │ │ ├── nlpOptmKernels.hpp │ │ └── nlpSecondOrderKernels.hpp │ ├── alignGrid.h │ ├── ProximityMgr.h │ ├── signalPathMgr.h │ ├── ProximityMgr.cpp │ ├── signalPathMgr.cpp │ ├── ConstraintGraph.h │ ├── constraintGraphGeneration.cpp │ └── constraintGraphGeneration.h ├── writer │ └── gdsii │ │ ├── WriteGds.cpp │ │ └── WriteGds.h └── pinassign │ └── VirtualPinAssigner.h ├── setup.py ├── README.md └── .ycm_extra_conf.py /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | bin 3 | docs 4 | bench 5 | -------------------------------------------------------------------------------- /src/global/constant.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file constant.h 3 | * @brief Define some constants 4 | * @author Keren Zhu 5 | * @date 09/30/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_CONSTANT_H_ 9 | #define IDEAPLACE_CONSTANT_H_ 10 | 11 | #include "type.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | PROJECT_NAMESPACE_END 16 | 17 | #endif // IDEAPLACE_CONSTANT_H_ 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/main/main.cpp: -------------------------------------------------------------------------------- 1 | #include "global/define.h" 2 | #include "main/IdeaPlaceEx.h" 3 | 4 | int main(int argc, char* argv[]) 5 | { 6 | using namespace PROJECT_NAMESPACE; 7 | // File-based flow 8 | IdeaPlaceEx _idea; 9 | 10 | // Parsing in input, arguments are from system arguments 11 | _idea.parseFileBased(argc, argv); 12 | _idea.solve(-1); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /src/global/namespace.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file namespace.h 3 | * @brief Define the namespaces 4 | * @author Keren Zhu 5 | * @date 09/30/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_NAMESPACE_H_ 9 | #define IDEAPLACE_NAMESPACE_H_ 10 | 11 | #include "define.h" 12 | 13 | // Namespace of the project 14 | #define PROJECT_NAMESPACE IDEAPLACE 15 | #define PROJECT_NAMESPACE_BEGIN namespace PROJECT_NAMESPACE{ 16 | #define PROJECT_NAMESPACE_END } 17 | 18 | #endif // IDEAPLACE_NAMESPACE_H_ 19 | -------------------------------------------------------------------------------- /src/api/api.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file api.cpp 3 | * @brief The top level cpp for initialize the pybind module 4 | * @author Keren Zhu 5 | * @date 12/16/2019 6 | */ 7 | 8 | #include 9 | #include 10 | #include "global/global.h" 11 | 12 | namespace py = pybind11; 13 | 14 | void initIdeaPlaceExAPI(py::module &); 15 | 16 | PYBIND11_MAKE_OPAQUE(std::vector); 17 | 18 | PYBIND11_MODULE(IdeaPlaceExPy, m) 19 | { 20 | initIdeaPlaceExAPI(m); 21 | } 22 | -------------------------------------------------------------------------------- /src/global/define.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file define.h 3 | * @brief Define the flags 4 | * @author Keren Zhu 5 | * @date 09/30/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_DEFINE_H_ 9 | #define IDEAPLACE_DEFINE_H_ 10 | 11 | //#define NODEBUG 12 | 13 | //#define DEBUG_DRAW 14 | //#define DEBUG_GR 15 | //#define DEBUG_LEGALIZE 16 | //#define DEBUG_PINASSIGN 17 | 18 | //#define MULTI_SYM_GROUP 19 | 20 | //#define NODEBUG 21 | 22 | #define PIN_ASSIGN_IN_GP 23 | #define PIN_ASSIGN_IN_LG 24 | 25 | #define DEBUG_SINGLE_THREAD_GP 26 | 27 | //#define IDEAPLACE_TASKFLOR_FOR_GRAD_OBJ_ 28 | 29 | #define IDEAPLACE_DEFAULT_MAX_NUM_CELLS 100 30 | 31 | #endif /// IDEAPLACE_DEFINE_H 32 | -------------------------------------------------------------------------------- /src/db/Parameters.cpp: -------------------------------------------------------------------------------- 1 | #include "Parameters.h" 2 | 3 | PROJECT_NAMESPACE_BEGIN 4 | Parameters::Parameters() 5 | { 6 | _ifUsePinAssignment = true; 7 | _numThreads = 10; 8 | _gridStep = -1; 9 | _virtualBoundaryExtension = 200; ///< The extension of current virtual boundary to the bounding box of placement 10 | _virtualPinInterval = 400; ///< The interval between each virtual pin 11 | _layoutOffset = 1000; ///< The default offset for the placement 12 | _defaultAspectRatio = 1.2; 13 | _maxWhiteSpace = 2; 14 | _defaultSignalFlowWeight = 10; 15 | _defaultCurrentFlowWeight = 0.5; 16 | _defaultRelativeRatioOfPowerNet = 0.2; 17 | } 18 | PROJECT_NAMESPACE_END 19 | -------------------------------------------------------------------------------- /src/util/StopWatch.cpp: -------------------------------------------------------------------------------- 1 | #include "StopWatch.hpp" 2 | 3 | namespace klib 4 | { 5 | std::vector StopWatchMgr::_us = std::vector(1, 0); 6 | std::unordered_map StopWatchMgr::_nameToIdxMap; 7 | StopWatch StopWatchMgr::_watch = StopWatch(0); 8 | 9 | std::unique_ptr StopWatchMgr::createNewStopWatch(std::string &&name) 10 | { 11 | auto idx = _us.size(); 12 | _us.emplace_back(0); 13 | _nameToIdxMap[std::move(name)] = idx; 14 | return std::make_unique(StopWatch(idx)); 15 | } 16 | void StopWatchMgr::quickStart() 17 | { 18 | _watch.clear(); 19 | _watch.start(); 20 | } 21 | std::uint64_t StopWatchMgr::quickEnd() 22 | { 23 | _watch.stop(); 24 | return _watch.record(); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/parser/ParserPin.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ParserPin.h 3 | * @brief Parser for .pin file 4 | * @author Keren Zhu 5 | * @date 10/03/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_PARSER_PIN_H_ 9 | #define IDEAPLACE_PARSER_PIN_H_ 10 | 11 | #include "db/Database.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | /// @class IDEAPLACE::ParserPin 16 | /// @brief Parsing in the .pin file 17 | class ParserPin 18 | { 19 | public: 20 | /// @brief constructor 21 | /// @param Reference to the placement engine database 22 | explicit ParserPin(Database &db) : _db(db) {} 23 | /// @brief parsing in the file 24 | /// @param input file name 25 | /// @return if the parsing is successful 26 | bool read(const std::string &filename); 27 | private: 28 | Database &_db; ///< The placement engine database 29 | }; 30 | 31 | PROJECT_NAMESPACE_END 32 | 33 | #endif ///IDEAPLACE_PARSER_PIN_H_ 34 | -------------------------------------------------------------------------------- /src/parser/ParserConnection.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ParserConnection.h 3 | * @brief Parser for .connection file 4 | * @author Keren Zhu 5 | * @date 10/04/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_PARSER_CONNECTION_H_ 9 | #define IDEAPLACE_PARSER_CONNECTION_H_ 10 | 11 | #include "db/Database.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | /// @class IDEAPLACE::PaserConnection 16 | /// @brief parsing in the .connection file 17 | class ParserConnection 18 | { 19 | public: 20 | /// @brief constructor 21 | /// @param Reference to the placement engine database 22 | explicit ParserConnection(Database &db) : _db(db) {} 23 | /// @brief parsing in the file 24 | /// @param input file name 25 | /// @return if the parsing is successful 26 | bool read(const std::string &filename); 27 | private: 28 | Database &_db; ///< The placement engine database 29 | }; 30 | 31 | PROJECT_NAMESPACE_END 32 | 33 | #endif ///IDEAPLACE_PARSER_CONNECTION_H_ 34 | -------------------------------------------------------------------------------- /src/parser/ParserSignalPath.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ParserSignalPath.h 3 | * @brief Parser for .sigpath file 4 | * @author Keren Zhu 5 | * @date 02/24/2020 6 | */ 7 | 8 | #ifndef IDEAPLACE_PARSER_SIGNAL_PATH_H_ 9 | #define IDEAPLACE_PARSER_SIGNAL_PATH_H_ 10 | 11 | #include "db/Database.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | 16 | /// @class IDEAPLACE::ParserSignalPath 17 | /// @brief Parsing in the .signalpath file 18 | class ParserSignalPath 19 | { 20 | public: 21 | /// @brief constructor 22 | /// @param Reference to the placement engine database 23 | explicit ParserSignalPath(Database &db) : _db(db) {} 24 | /// @brief parsing in the file 25 | /// @param input file name 26 | /// @return if the parsing is successful 27 | bool read(const std::string &filename); 28 | private: 29 | Database &_db; ///< The placement engine database 30 | }; 31 | 32 | PROJECT_NAMESPACE_END 33 | 34 | #endif //IDEAPLACE_PARSER_SIGNAL_PATH_H_ 35 | -------------------------------------------------------------------------------- /src/parser/ParserSymFile.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ParserSymFile.h 3 | * @brief Parser for .sym file 4 | * @author Keren Zhu 5 | * @date 12/16/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_PARSER_SYMFILE_H_ 9 | #define IDEAPLACE_PARSER_SYMFILE_H_ 10 | 11 | #include "db/Database.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | /// @class IDEAPLACE::PaserSymFile 16 | /// @brief parsing in the .sym file 17 | class ParserSymFile 18 | { 19 | public: 20 | /// @brief constructor 21 | /// @param Reference to the placement engine database 22 | explicit ParserSymFile(Database &db) : _db(db) {} 23 | /// @brief parsing in the file 24 | /// @param input file name 25 | /// @return if the parsing is successful 26 | bool read(const std::string &filename); 27 | private: 28 | /// @brief find cell index from name 29 | IndexType cellIdx(const std::string &cellName); 30 | private: 31 | Database &_db; ///< The placement engine database 32 | }; 33 | 34 | PROJECT_NAMESPACE_END 35 | 36 | #endif //IDEAPLACE_PARSER_SYMFILE_H_ 37 | -------------------------------------------------------------------------------- /src/global/global.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file global.h 3 | * @brief The header file intended to be included globally in the project 4 | * @author Keren Zhu 5 | * @date 09/30/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_GLOBAL_H_ 9 | #define IDEAPLACE_GLOBAL_H_ 10 | 11 | // Add all global/common header files here 12 | 13 | #include "type.h" 14 | #include "constant.h" 15 | #include "parameter.h" 16 | #include "util/MsgPrinter.h" 17 | #include "util/Assert.h" 18 | #include "util/kLibBase.h" 19 | #include "util/StopWatch.hpp" 20 | 21 | PROJECT_NAMESPACE_BEGIN 22 | 23 | // Function aliases 24 | static const auto &INF = MsgPrinter::inf; 25 | static const auto &WRN = MsgPrinter::wrn; 26 | static const auto &ERR = MsgPrinter::err; 27 | static const auto &DBG = MsgPrinter::dbg; 28 | static const auto &WATCH_QUICK_START = klib::StopWatchMgr::quickStart; 29 | static const auto &WATCH_QUICK_END = klib::StopWatchMgr::quickEnd; 30 | static const auto &WATCH_CREATE_NEW = klib::StopWatchMgr::createNewStopWatch;; 31 | static const auto &WATCH_LOOK_RECORD_TIME = klib::StopWatchMgr::time; 32 | 33 | PROJECT_NAMESPACE_END 34 | 35 | #endif // IDEAPLACE_GLOBAL_H_ 36 | -------------------------------------------------------------------------------- /src/place/nlp/nlpTypes.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file nlpOptmKernel.hpp 3 | * @brief The non-lnear programming for global plaement: basic type denifitions e 4 | * @author Keren Zhu 5 | * @date 04/05/2020 6 | */ 7 | 8 | #pragma once 9 | 10 | #include "global/global.h" 11 | 12 | PROJECT_NAMESPACE_BEGIN 13 | 14 | template 15 | class NlpGPlacerBase; 16 | 17 | template 18 | class NlpGPlacerFirstOrder; 19 | 20 | template 21 | class NlpGPlacerSecondOrder; 22 | 23 | namespace nlp 24 | { 25 | template 26 | struct is_first_order_diff : std::false_type {}; 27 | 28 | template 29 | struct is_first_order_diff> : std::true_type {}; 30 | 31 | template 32 | struct is_first_order_diff> : std::true_type {}; 33 | 34 | template 35 | struct is_second_order_diff : std::false_type {}; 36 | 37 | template 38 | struct is_second_order_diff> : std::true_type {}; 39 | } //namespace nlp 40 | 41 | PROJECT_NAMESPACE_END 42 | -------------------------------------------------------------------------------- /src/parser/ParserSymNet.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ParserSyNet.h 3 | * @brief Parser for .symnet file 4 | * @author Keren Zhu 5 | * @date 03/09/2020 6 | */ 7 | 8 | #ifndef IDEAPLACE_PARSER_SYMNET_H_ 9 | #define IDEAPLACE_PARSER_SYMNET_H_ 10 | 11 | #include "db/Database.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | 16 | /// @class IDEAPLACE::PaserSymNet 17 | /// @brief Parsing in the .symnet files. This file is simply the name of nets that are symmetric or self-symmetric 18 | class ParserSymNet 19 | { 20 | public: 21 | /// @brief constructor 22 | /// @param Reference to the placement engine database 23 | explicit ParserSymNet(Database &db) : _db(db) {} 24 | /// @brief parsing in the file 25 | /// @param input file name 26 | /// @return if the parsing is successful 27 | bool read(const std::string &filename); 28 | private: 29 | /// @brief process the pairs read from the file, and save the result in the database 30 | bool processNamePair(); 31 | private: 32 | Database &_db; ///< The placement engine database 33 | std::vector> _pairs; ///< The pairs for the input symmetric net 34 | std::vector _selfs; ///< The self symmetry pairs 35 | }; 36 | PROJECT_NAMESPACE_END 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/place/alignGrid.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file alignGrid.h 3 | * @brief The post processing step for aligning the placement to grid 4 | * @author Keren Zhu 5 | * @date 02/09/2020 6 | */ 7 | 8 | #ifndef IDEAPLACE_ALIGN_GRID_H_ 9 | #define IDEAPLACE_ALIGN_GRID_H_ 10 | 11 | #include "db/Database.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | /// @brief simple post processing to align the cells to some grid 16 | class GridAligner 17 | { 18 | public: 19 | /// @param the database for the placer 20 | explicit GridAligner(Database &db) 21 | : _db(db) {} 22 | /// @brief solve the alignment problem 23 | /// @param the grid step. Assume uniform in both x and y 24 | void align(LocType stepSize); 25 | LocType findCurrentSymAxis(); 26 | private: 27 | void naiveAlign(); 28 | void bettherThanNaiveAlign(); 29 | void adjustOffset(const XY &offset); 30 | void adjustSymPair(const SymPair &symPair, LocType symAxis); 31 | void adjustSelfSym(IndexType cellIdx, LocType symAxis); 32 | private: 33 | Database &_db; ///< The placement database 34 | LocType _stepSize = 1; ///< The grid step size 35 | XY _offset; ///< The grid offset 36 | }; 37 | 38 | PROJECT_NAMESPACE_END 39 | 40 | #endif //IDEAPLACE_ALIGN_GRID_H_ 41 | -------------------------------------------------------------------------------- /src/util/Assert.h: -------------------------------------------------------------------------------- 1 | #ifndef ZKUTIL_ASSERT_H_ 2 | #define ZKUTIL_ASSERT_H_ 3 | 4 | 5 | #ifndef NDEBUG 6 | 7 | #include 8 | #include 9 | #include "MsgPrinter.h" 10 | #include 11 | 12 | 13 | // Assert without message 14 | #define Assert(cond) \ 15 | do { \ 16 | if (!(cond)) \ 17 | { \ 18 | char format[1024]; \ 19 | sprintf(format, "Assertion failed at file %s line %d. \n assert: %s\n", __FILE__, __LINE__, #cond); \ 20 | MsgPrinter::err(format); \ 21 | assert(0); \ 22 | } \ 23 | } while(false) 24 | 25 | // Assert with message 26 | #define AssertMsg(cond, msg, ...) \ 27 | do { \ 28 | if (!(cond)) \ 29 | { \ 30 | char prefix[1024]; \ 31 | sprintf(prefix, "Assertion failed at file %s line %d.\n assert: %s\n", __FILE__, __LINE__, #cond); \ 32 | std::string format = std::string(prefix) + " message: " + std::string(msg); \ 33 | MsgPrinter::err(format.c_str(), ##__VA_ARGS__); \ 34 | assert(0); \ 35 | } \ 36 | } while (false) 37 | #else // NDEBUG 38 | #define Assert(cond) \ 39 | do { \ 40 | } while(false) 41 | #define AssertMsg(cond, msg, ...) \ 42 | do { \ 43 | } while (false) 44 | #endif // NDEBUG 45 | #endif // ZKTUIL_ASSERT_H_ 46 | -------------------------------------------------------------------------------- /src/place/ProximityMgr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ProximityMgr.h 3 | * @brief Proximity Maneger 4 | * @author Keren Zhu 5 | * @date 02/22/2020 6 | */ 7 | 8 | #ifndef IDEAPLACE_PROXIMITY_MGR_H_ 9 | #define IDEAPLACE_PROXIMITY_MGR_H_ 10 | 11 | #include "db/Database.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | 16 | /// @class IDEAPLACE::ProximityMgr 17 | /// @brief the proximity manager 18 | class ProximityMgr 19 | { 20 | static constexpr IntType DEFAULT_DUMMY_NET_WEIGHT = 10; 21 | /// @brief quick shortcut for recording the pin idx in cell 22 | struct PinInCellIdx 23 | { 24 | PinInCellIdx(IndexType cellIdx_, IndexType pinIdx_) : cellIdx(cellIdx_), pinIdx(pinIdx_) {} 25 | IndexType cellIdx; 26 | IndexType pinIdx; 27 | }; 28 | public: 29 | /// @brief default constructor 30 | explicit ProximityMgr(Database &db) : _db(db) {} 31 | /// @brief restore all the changes 32 | void restore(); 33 | /// @brief configure the proximity with adding dummy nets 34 | void applyProximityWithDummyNets(); 35 | private: 36 | /// @brief add dummy net for a proximity group 37 | /// @param a ProximityGroup 38 | void addDummyNetForProximityGroup(const ProximityGroup &pg); 39 | private: 40 | Database &_db; ///< The placement engine database 41 | std::vector _dummyPins; ///< The indices of dummy pins 42 | std::vector _dummyNets; ///< The indices of dummy nets 43 | std::vector _dummyCells; ///< The indices for dummy cells 44 | }; 45 | 46 | 47 | PROJECT_NAMESPACE_END 48 | 49 | #endif //IDEAPLACE_PROXIMITY_MGR_H_ 50 | -------------------------------------------------------------------------------- /src/global/type.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file type.h 3 | * @brief Define some the types being used globally 4 | * @author Keren Zhu 5 | * @date 09/30/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_TYPE_H_ 9 | #define IDEAPLACE_TYPE_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include "namespace.h" 15 | 16 | PROJECT_NAMESPACE_BEGIN 17 | // Built-in type aliases 18 | using IndexType = std::uint32_t; 19 | using IntType = std::int32_t; 20 | using RealType = double; 21 | using Byte = std::uint8_t; 22 | using LocType = std::int32_t; // Location/design unit // Location/design unit 23 | using BoolType = Byte; 24 | // Location/design unit 25 | // Built-in type constants 26 | constexpr IndexType INDEX_TYPE_MAX = UINT32_MAX; 27 | constexpr IntType INT_TYPE_MAX = INT32_MAX; 28 | constexpr IntType INT_TYPE_MIN = INT32_MIN; 29 | constexpr RealType REAL_TYPE_MAX = 1e100; 30 | constexpr RealType REAL_TYPE_MIN = -1e100; 31 | constexpr RealType REAL_TYPE_TOL = 1e-6; 32 | constexpr LocType LOC_TYPE_MAX = INT32_MAX; 33 | constexpr LocType LOC_TYPE_MIN = INT32_MIN; 34 | 35 | // Type aliases 36 | //using CostTy = double; 37 | using CostType = RealType; 38 | constexpr CostType COST_TYPE_INVALID = REAL_TYPE_MIN; 39 | constexpr CostType COST_TYPE_MAX = REAL_TYPE_MAX; 40 | 41 | 42 | // Enums 43 | 44 | /// @brief The type of symmetry 45 | enum class SymType 46 | { 47 | HORIZONTAL = 0, 48 | VERTICAL = 1, 49 | NONE = 2 50 | }; 51 | 52 | enum class Orient2DType 53 | { 54 | HORIZONTAL = 0, 55 | VERTICAL = 1, 56 | NONE = 2 57 | }; 58 | 59 | enum class Direction2DType 60 | { 61 | WEST = 0, 62 | EAST = 1, 63 | SOUTH = 2, 64 | NORTH = 3, 65 | NONE = 4 66 | }; 67 | PROJECT_NAMESPACE_END 68 | 69 | #endif // AROUTER_TYPE_H_ 70 | 71 | -------------------------------------------------------------------------------- /src/global/parameter.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file parameter.h 3 | * @brief Define some hyperparameters 4 | * @author Keren Zhu 5 | * @date 09/30/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_PARAMETER_H_ 9 | #define IDEAPLACE_PARAMETER_H_ 10 | 11 | #include "type.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | /* NLP wn conj */ 16 | constexpr RealType LAMBDA_1Init = 1; ///< The initial value for x/y overlapping penalty 17 | constexpr RealType LAMBDA_2Init = 1; ///< The initial value for out of boundry penalty 18 | constexpr RealType LAMBDA_3Init = 16; ///< The initial value for wirelength penalty 19 | constexpr RealType LAMBDA_4Init = 1; ///< The initial value for asymmetric penalty 20 | constexpr RealType LAMBDA_MAX_OVERLAP_Init = 0; ///< The initial value for asymmetric penalty 21 | constexpr RealType NLP_WN_CONJ_OVERLAP_THRESHOLD = 0.001; ///< The threshold for whether increase the penalty for overlapping 22 | constexpr RealType NLP_WN_CONJ_OOB_THRESHOLD = 0.05; ///< The threshold for wehther increasing the penalty for out of boundry 23 | constexpr RealType NLP_WN_CONJ_ASYM_THRESHOLD = 2.5; ///< The threshodl for whether increase the penalty for asymmetry 24 | constexpr RealType NLP_WN_CONJ_ALPHA = 1; ///< "alpha" should be a very small value. Used in objective function 25 | constexpr RealType NLP_WN_CONJ_EXP_DECAY_TARGET = 0.05; ///< The exponential decay facor for global placement step size. 26 | constexpr IndexType NLP_WN_CONJ_DEFAULT_MAX_ITER = 20; ///< The default maxmimum iterations for the global placement 27 | constexpr RealType NLP_WN_CONJ_EPISLON = 200 / NLP_WN_CONJ_DEFAULT_MAX_ITER ; 28 | constexpr RealType NLP_WN_CONJ_DEFAULT_MAX_WHITE_SPACE = 2; ///< The default extra white space for setting the boundry 29 | constexpr RealType NLP_WN_MAX_PENALTY = 1024; 30 | constexpr RealType NLP_WN_REDUCE_PENALTY = 512 / NLP_WN_MAX_PENALTY ; 31 | 32 | PROJECT_NAMESPACE_END 33 | 34 | #endif ///IDEAPLACE_PARAMETER_H_ 35 | -------------------------------------------------------------------------------- /src/parser/ParserTechSimple.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ParserTechSimple.h 3 | * @brief Parser for Tech simple file 4 | * @author Keren Zhu 5 | * @date 10/04/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_PARSER_TECHSIMPLE_H_ 9 | #define IDEAPLACE_PARSER_TECHSIMPLE_H_ 10 | 11 | #include "db/Database.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | /// @class IDEAPLACE::PaserTechSimple 16 | /// @brief Parsing in the Techfile.simple. This file is simply the layer name + GDS layer 17 | class ParserTechSimple 18 | { 19 | public: 20 | /// @brief constructor 21 | /// @param Reference to the placement engine database 22 | explicit ParserTechSimple(Database &db) : _db(db) {} 23 | /// @brief parsing in the file 24 | /// @param input file name 25 | /// @return if the parsing is successful 26 | bool read(const std::string &filename); 27 | private: 28 | Database &_db; ///< The placement engine database 29 | }; 30 | 31 | inline bool ParserTechSimple::read(const std::string &filename) 32 | { 33 | std::ifstream inf(filename.c_str()); 34 | if (!inf.is_open()) 35 | { 36 | ERR("ParserTechSimple::%s: cannot open file: %s \n", __FUNCTION__ , filename.c_str()); 37 | Assert(false); 38 | return false; 39 | } 40 | // Read in the file 41 | std::string line; 42 | while (std::getline(inf, line)) 43 | { 44 | // Split the line into words 45 | std::vector words; 46 | std::istringstream iss(line); 47 | std::string layerName; 48 | IndexType gdsLayer = INDEX_TYPE_MAX; 49 | iss >> layerName; 50 | iss >> gdsLayer; 51 | // Add to the database 52 | _db.tech().addGdsLayer(gdsLayer); 53 | } 54 | _db.tech().initRuleDataStructure(); 55 | return true; 56 | } 57 | 58 | PROJECT_NAMESPACE_END 59 | 60 | #endif ///IDEAPLACE_PARSER_TECHSIMPLE_H_ 61 | -------------------------------------------------------------------------------- /src/parser/ParserSignalPath.cpp: -------------------------------------------------------------------------------- 1 | #include "ParserSignalPath.h" 2 | 3 | PROJECT_NAMESPACE_BEGIN 4 | 5 | 6 | bool ParserSignalPath::read(const std::string &filename) 7 | { 8 | std::ifstream inf(filename.c_str()); 9 | if (!inf.is_open()) 10 | { 11 | ERR("ParserPin::%s: cannot open file: %s \n", __FUNCTION__ , filename.c_str()); 12 | Assert(false); 13 | return false; 14 | } 15 | // Read in the file 16 | std::string line; 17 | while (std::getline(inf, line)) 18 | { 19 | // Split the line into words 20 | std::vector words; 21 | std::istringstream iss(line); 22 | for (std::string str; iss >> str; ) 23 | { 24 | words.emplace_back(str); 25 | } 26 | if (words.size() <= 1) 27 | { 28 | continue; 29 | } 30 | auto & sig = _db.signalPath(_db.allocateSignalPath()); 31 | for (IndexType idx =0; idx < words.size() - 1; idx +=2) 32 | { 33 | auto & cellName = words.at(idx); 34 | auto & pinName = words.at(idx + 1); 35 | IndexType pinIdx = INDEX_TYPE_MAX; 36 | for (IndexType idx = 0; idx < _db.numCells(); ++idx) 37 | { 38 | const auto & cell = _db.cell(idx); 39 | if (cell.name() == cellName) 40 | { 41 | for (IndexType jdx = 0; jdx < cell.numPinIdx(); ++jdx) 42 | { 43 | const auto &pin = _db.pin(cell.pinIdx(jdx)); 44 | if (pin.name() == pinName) 45 | { 46 | pinIdx = cell.pinIdx(jdx); 47 | break; 48 | } 49 | } 50 | break; 51 | } 52 | } 53 | AssertMsg(pinIdx != INDEX_TYPE_MAX, "Unknown pin! cellname: %s, pinname %s \n", cellName.c_str(), pinName.c_str()); 54 | sig.addPinIdx(pinIdx); 55 | } 56 | } 57 | return true; 58 | } 59 | 60 | PROJECT_NAMESPACE_END 61 | -------------------------------------------------------------------------------- /src/util/MsgPrinter.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | //namespace klib 4 | //{ 5 | //}; 6 | // Created by Keren on 04/12/2018 7 | // 8 | 9 | 10 | #ifndef ZKUTIL_MSGPRINTER_H_ 11 | #define ZKUTIL_MSGPRINTER_H_ 12 | 13 | #include // FILE *, stderr 14 | #include 15 | #include 16 | #include 17 | #include "global/namespace.h" 18 | 19 | PROJECT_NAMESPACE_BEGIN 20 | 21 | /// ================================================================================ 22 | /// MsgPrinter, used to manage printing message into the log or on the screen 23 | /// Copied and implemented based on Wuxi's 24 | /// ================================================================================ 25 | 26 | 27 | /// Enum type for message printing 28 | enum class MsgType 29 | { 30 | INF, 31 | WRN, 32 | ERR, 33 | DBG 34 | }; 35 | 36 | /// Function converting enum type to std::string 37 | std::string msgTypeToStr(MsgType msgType); 38 | 39 | /// Message printing class 40 | class MsgPrinter 41 | { 42 | public: 43 | static void startTimer() { _startTime = std::time(nullptr); } // Cache start time 44 | static void screenOn() { _screenOutStream = stderr; } // Turn on screen printing 45 | static void screenOff() { _screenOutStream = nullptr; } // Turn off screen printing 46 | 47 | static void openLogFile(const std::string &file); 48 | static void closeLogFile(); 49 | static void inf(const char *rawFormat, ...); 50 | static void wrn(const char *rawFormat, ...); 51 | static void err(const char *rawFormat, ...); 52 | static void dbg(const char *rawFormat, ...); 53 | 54 | private: 55 | static void print(MsgType msgType, const char *rawFormat, va_list args); 56 | 57 | private: 58 | static std::time_t _startTime; 59 | static FILE * _screenOutStream; // Out stream for screen printing 60 | static FILE * _logOutStream; // Out stream for log printing 61 | static std::string _logFileName; // Current log file name 62 | }; 63 | 64 | PROJECT_NAMESPACE_END 65 | 66 | #endif // ZKUTIL_MSGPRINTER_H_ 67 | -------------------------------------------------------------------------------- /src/util/linear_programming.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file linear_programming_trait.h 3 | * @brief The wrappers for linear programming interface 4 | * @author Keren Zhu 5 | * @date 03/19/2020 6 | */ 7 | 8 | #ifndef KLIB_LINEAR_PROGRAMMING_H_ 9 | #define KLIB_LINEAR_PROGRAMMING_H_ 10 | 11 | #include "global/namespace.h" 12 | #include "lp_limbo.h" 13 | 14 | namespace klib { 15 | // Select LP solver 16 | namespace _lp { 17 | 18 | template 19 | struct lp_rank 20 | { 21 | static const bool if_enable = true; 22 | typedef _undefined LpModel; 23 | typedef linear_programming_trait<_undefined> LpTrait; 24 | }; 25 | 26 | template<> 27 | struct lp_rank<0> 28 | { 29 | #ifndef LP_NOT_USE_GUROBI 30 | static const bool if_enable = true; 31 | typedef LimboLpGurobi LpModel; 32 | typedef LimboLpGurobiTrait LpTrait; 33 | #else 34 | static const bool if_enable = false; 35 | #endif 36 | }; 37 | 38 | template<> 39 | struct lp_rank<1> 40 | { 41 | #ifndef LP_NOT_USE_LPSOLVE 42 | static const bool if_enable = true; 43 | typedef LimboLpsolve LpModel; 44 | typedef LimboLpsolveTrait LpTrait; 45 | #else 46 | static const bool if_enable = false; 47 | #endif 48 | }; 49 | 50 | template 51 | struct select_lp {}; 52 | template 53 | struct select_lp 54 | { 55 | typedef typename lp_rank::LpModel LpModel; 56 | typedef typename lp_rank::LpTrait LpTrait; 57 | }; 58 | template 59 | struct select_lp 60 | { 61 | typedef lp_rank rank_type; 62 | typedef typename select_lp::LpModel LpModel; 63 | typedef typename select_lp::LpTrait LpTrait; 64 | }; 65 | }; //namspace _lp 66 | 67 | namespace lp 68 | { 69 | typedef typename _lp::select_lp<0, _lp::lp_rank<0>::if_enable>::LpModel LpModel; 70 | typedef typename _lp::select_lp<0, _lp::lp_rank<0>::if_enable>::LpTrait LpTrait; 71 | }; 72 | 73 | } //namespace klib 74 | 75 | #endif //KLIB_LINEAR_PROGRAMMING_H_ 76 | -------------------------------------------------------------------------------- /src/parser/ParserNetwgt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ParserNetwgt.h 3 | * @brief Parser for .netwgt file 4 | * @author Keren Zhu 5 | * @date 10/02/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_NETWGT_H_ 9 | #define IDEAPLACE_NETWGT_H_ 10 | 11 | #include "db/Database.h" 12 | #include 13 | 14 | PROJECT_NAMESPACE_BEGIN 15 | 16 | /// @class IDEAPLACE::ParserNetwgt 17 | /// @brief the parser for .netwgt files 18 | class ParserNetwgt 19 | { 20 | public: 21 | /// @brief constructor 22 | /// @param The reference to the placement database 23 | explicit ParserNetwgt(Database &db) : _db(db) {} 24 | /// @brief parsing in the file 25 | /// @param input file name 26 | /// @return if the parsing is successful 27 | bool read(const std::string &filename); 28 | private: 29 | Database &_db; ///< The reference to the placement database 30 | }; 31 | 32 | inline bool ParserNetwgt::read(const std::string &filename) 33 | { 34 | std::ifstream inf(filename.c_str()); 35 | if (!inf.is_open()) 36 | { 37 | ERR("ParserNetwgt::%s: cannot open file: %s \n", __FUNCTION__ , filename.c_str()); 38 | Assert(false); 39 | return false; 40 | } 41 | // Make a map of the net names 42 | std::unordered_map netNameMap; 43 | for (IndexType netIdx = 0; netIdx < _db.numNets(); ++netIdx) 44 | { 45 | netNameMap[_db.net(netIdx).name()] = netIdx; 46 | } 47 | // Read in the file 48 | std::string line; 49 | while (std::getline(inf, line)) 50 | { 51 | std::istringstream iss(line); 52 | std::string netName; 53 | iss >> netName; 54 | IntType netWgt; 55 | iss >> netWgt; 56 | auto mapIter = netNameMap.find(netName); 57 | if (mapIter == netNameMap.end()) 58 | { 59 | ERR("ParserNetwgt::%s: Net %s is not found in the placement database \n", __FUNCTION__, netName.c_str()); 60 | Assert(false); 61 | return false; 62 | } 63 | else 64 | { 65 | IndexType netIdx = mapIter->second; 66 | _db.net(netIdx).setWeight(netWgt); 67 | } 68 | } 69 | return true; 70 | } 71 | 72 | PROJECT_NAMESPACE_END 73 | 74 | #endif ///IDEAPLACE_NETWGT_H_ 75 | -------------------------------------------------------------------------------- /src/parser/ParserGds.cpp: -------------------------------------------------------------------------------- 1 | #include "ParserGds.h" 2 | #include "util/Polygon2Rect.h" 3 | 4 | PROJECT_NAMESPACE_BEGIN 5 | 6 | bool ParserCellGds::parseCellGds(const std::string &filename, IndexType cellIdx) 7 | { 8 | // Flaten the gds by the last cell 9 | ::GdsParser::GdsDB::GdsDB unflatenDb; 10 | ::GdsParser::GdsDB::GdsReader reader(unflatenDb); 11 | if (!reader(filename)) 12 | { 13 | ERR("Placement Gds Parser: cannot open file %s! \n", filename.c_str()); 14 | } 15 | // Set the gds unit based on precision 16 | _gdsDBU = ::klib::autoRound(1e-6 / unflatenDb.precision()); 17 | 18 | 19 | // Flaten the gds 20 | std::string topCellName = ::klib::topCell(unflatenDb); 21 | auto flatCell = unflatenDb.extractCell(topCellName); 22 | ::GdsParser::GdsDB::GdsDB _gdsDb; 23 | _gdsDb.addCell(flatCell); 24 | 25 | 26 | // Process the shapes in the gds 27 | for (const auto &object : flatCell.objects()) 28 | { 29 | ::GdsParser::GdsDB::GdsObjectHelpers()(object.first, object.second, ExtractShapeLayerAction(_db.tech().layerIdxMap(), _polygons)); 30 | } 31 | 32 | // Scale the shapes to the placer database unit 33 | this->scaleDesign(); 34 | 35 | // Find the cell index if not given 36 | if (cellIdx == INDEX_TYPE_MAX) 37 | { 38 | // Check the cell name with the top cell name 39 | for (IndexType idx = 0; idx < _db.numCells(); ++idx) 40 | { 41 | if (topCellName == _db.cell(idx).name()) 42 | { 43 | cellIdx = idx; 44 | break; 45 | } 46 | } 47 | AssertMsg(cellIdx != INDEX_TYPE_MAX, "ParserCellGds::%s cannot locate the cell %s in database \n", __FUNCTION__, topCellName.c_str()); 48 | } 49 | 50 | // Write the read shapes into the database 51 | this->dumpToDb(cellIdx); 52 | return true; 53 | } 54 | 55 | 56 | void ParserCellGds::scaleDesign() 57 | { 58 | auto dbDBU = _db.tech().dbu(); 59 | RealType scale = std::round(static_cast(dbDBU) / static_cast(_gdsDBU)); 60 | for (auto & poly : _polygons) 61 | { 62 | poly.scale(scale, scale); 63 | } 64 | } 65 | 66 | void ParserCellGds::dumpToDb(IndexType cellIdx) 67 | { 68 | auto &cell = _db.cell(cellIdx); 69 | for (const auto &poly : _polygons) 70 | { 71 | IndexType placerLayer = poly.layer; 72 | std::vector> shapes; 73 | ::klib::convertPolygon2Rects(poly.pts, shapes); 74 | for (const auto &shape : shapes) 75 | { 76 | cell.unionBBox(placerLayer, shape); 77 | } 78 | } 79 | cell.calculateCellBBox(); 80 | } 81 | 82 | PROJECT_NAMESPACE_END 83 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import sys 4 | import platform 5 | import subprocess 6 | 7 | from setuptools import setup, Extension 8 | from setuptools.command.build_ext import build_ext 9 | from distutils.version import LooseVersion 10 | 11 | 12 | class CMakeExtension(Extension): 13 | def __init__(self, name, sourcedir=''): 14 | Extension.__init__(self, name, sources=[]) 15 | self.sourcedir = os.path.abspath(sourcedir) 16 | 17 | 18 | class CMakeBuild(build_ext): 19 | def run(self): 20 | try: 21 | out = subprocess.check_output(['cmake', '--version']) 22 | except OSError: 23 | raise RuntimeError("CMake must be installed to build the following extensions: " + 24 | ", ".join(e.name for e in self.extensions)) 25 | 26 | if platform.system() == "Windows": 27 | cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1)) 28 | if cmake_version < '3.1.0': 29 | raise RuntimeError("CMake >= 3.1.0 is required on Windows") 30 | 31 | for ext in self.extensions: 32 | self.build_extension(ext) 33 | 34 | def build_extension(self, ext): 35 | extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) 36 | cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, 37 | '-DPYTHON_EXECUTABLE=' + sys.executable] 38 | 39 | cfg = 'Debug' if self.debug else 'Release' 40 | build_args = ['--config', cfg] 41 | 42 | if platform.system() == "Windows": 43 | cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)] 44 | if sys.maxsize > 2**32: 45 | cmake_args += ['-A', 'x64'] 46 | build_args += ['--', '/m'] 47 | else: 48 | cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg] 49 | build_args += ['--', '-j2'] 50 | 51 | env = os.environ.copy() 52 | env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''), 53 | self.distribution.get_version()) 54 | if not os.path.exists(self.build_temp): 55 | os.makedirs(self.build_temp) 56 | subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env) 57 | subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp) 58 | 59 | setup( 60 | name='IdeaPlaceExPy', 61 | version='0.0.1', 62 | author='Keren Zhu', 63 | author_email='keren.zhu@utexas.edu', 64 | description='The python interface to IdeaPlaceEx', 65 | long_description='', 66 | ext_modules=[CMakeExtension('abc_py')], 67 | cmdclass=dict(build_ext=CMakeBuild), 68 | zip_safe=False, 69 | ) 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | IdeaPlaceEx 2 | -------- 3 | This is a analog placement engine. 4 | # Install 5 | 6 | Some components depend on external libraries, such as 7 | 8 | [Boost](www.boost.org) 9 | 10 | [LIMBO](https://github.com/limbo018/Limbo) Configure, make and install the LIMBO package. Set environment variable LIMBO\_DIR to the path, or specify the path to the library as Cmake cache variable LIMBO\_DIR `cmake -DLIMBO_DIR=$PATH` 11 | 12 | 13 | [lemon](https://lemon.cs.elte.hu) Configure, make and install the Lemon package. Set environment variable LEMON\_DIR to the path, or specify the path to the library as Cmake cache variable LEMON\_DIR `cmake -DLEMON_DIR=$PATH` 14 | 15 | [Eigen](http://eigen.tuxfamily.org/index.php) Configure, make and install the Eigen package. Set environment variable EIGEN\_DIR to the path, or specify the path to the library as Cmake cache variable EIGEN\_DIR `cmake -DEIGEN_DIR=$PATH` 16 | 17 | [pybind11](https://github.com/pybind/pybind11) Please see the official [document](http://pybind11.readthedocs.org/en/master) for installing the pybind11. 18 | Set the path to pybind11. Either export to system variable `PYBIND11_DIR` or add flag to cmake `cmake -DPYBIND11_DIR=`. 19 | The cmake will automatically find the system Python. 20 | To use the other Python, add cmake flags `cmake -DPYTHON_INCLUDE_DIR= -DPYTHON_LIBRARIES=`. 21 | For example, `-DPYTHON_INCLUDE_DIR=/include/python3.7m -DPYTHON_LIBRARIES=/lib/libpython3.7m.a` 22 | 23 | Either Gurobi or lpsolve. If one of them is not set through system variable or Cmake variable, the compilation will automatically look for the another. 24 | 25 | [Gurobi](https://www.gurobi.com) Install the Gurobi package. Set environment variable GUROBI\_HOME to the path, or specify the path to the library as Cmake cache variable GUROBI\_HOME `cmake -DGUROBI_HOME=$PATH` 26 | 27 | [lpsolve](http://lpsolve.sourceforge.net) Install the lpsolve package. Set environment variable LPSOLVE\_DIR to the path, or specify the path to the library as Cmake cache variable LPSOLVE\_DIR` `cmake -DLPSOLVE\_DIR=$PATH` 28 | , 29 | Build the program: 30 | ``` 31 | mkdir build 32 | cd build 33 | cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_DOCUMENTATION=ON .. 34 | cmake -DCMAKE_BUILD_TYPE=Release .. (alternative) # If no doxygen 35 | make 36 | make doc (optional) 37 | cd ../../ 38 | pip install IdeaPlaceEx 39 | ``` 40 | 41 | Specify the install prefix: 42 | ``` 43 | cmake -DCMAKE_INSTALL_PREFIX=./install 44 | ``` 45 | ``` 46 | -------- 47 | # Usage 48 | 49 | Please use the Python interface for this program. 50 | The interface is defined in src/api/IdeaPlaceExAPI.cpp 51 | Usage example can be found in [MAGICAL](https://github.com/magical-eda/MAGICAL) 52 | 53 | -------- 54 | -------- 55 | # Copyright 56 | The software is released under MIT license except third party packages. 57 | -------------------------------------------------------------------------------- /src/parser/ParserSymFile.cpp: -------------------------------------------------------------------------------- 1 | #include "ParserSymFile.h" 2 | 3 | PROJECT_NAMESPACE_BEGIN 4 | 5 | IndexType ParserSymFile::cellIdx(const std::string &cellName) 6 | { 7 | IndexType findIdx = INDEX_TYPE_MAX; 8 | for (IndexType idx = 0; idx < _db.numCells(); ++idx) 9 | { 10 | if (_db.cell(idx).name() == cellName) 11 | { 12 | findIdx = idx; 13 | break; 14 | } 15 | } 16 | return findIdx; 17 | } 18 | 19 | bool ParserSymFile::read(const std::string &filename) 20 | { 21 | std::ifstream inf(filename.c_str()); 22 | if (!inf.is_open()) 23 | { 24 | ERR("ParserConnection::%s: cannot open file: %s \n", __FUNCTION__ , filename.c_str()); 25 | Assert(false); 26 | return false; 27 | } 28 | // Read in the file 29 | std::string line; 30 | 31 | IntType idx = -1; 32 | while (std::getline(inf, line)) 33 | { 34 | // Split the line into words 35 | std::vector words; 36 | std::istringstream iss(line); 37 | for (std::string str; iss >> str; ) 38 | { 39 | words.emplace_back(str); 40 | } 41 | if (idx == -1 && words.size() != 0) 42 | { 43 | idx = _db.allocateSymGrp(); 44 | } 45 | if (words.size() == 0) 46 | { 47 | idx = -1; 48 | } 49 | if (words.size() == 2) 50 | { 51 | std::string cellName1 = words.at(0); 52 | std::string cellName2 = words.at(1); 53 | // Low efficency implementation 54 | IndexType cellIdx1 = cellIdx(cellName1); 55 | IndexType cellIdx2 = cellIdx(cellName2); 56 | if (cellIdx1 == INDEX_TYPE_MAX) 57 | { 58 | ERR("ParserSymFile: cannot find cell %s \n", cellName1.c_str()); 59 | Assert(false); 60 | return false; 61 | } 62 | if (cellIdx2 == INDEX_TYPE_MAX) 63 | { 64 | ERR("ParserSymFile: cannot find cell %s \n", cellName2.c_str()); 65 | Assert(false); 66 | return false; 67 | } 68 | _db.symGroup(idx).addSymPair(cellIdx1, cellIdx2); 69 | _db.cell(cellIdx1).setSymNetIdx(cellIdx2); 70 | _db.cell(cellIdx2).setSymNetIdx(cellIdx1); 71 | } 72 | if (words.size() == 1) 73 | { 74 | std::string cellName = words.at(0); 75 | // Low efficency implementation 76 | IndexType cellId = cellIdx(cellName); 77 | if (cellId == INDEX_TYPE_MAX) 78 | { 79 | ERR("ParserSymFile: cannot find cell %s \n", cellName.c_str()); 80 | Assert(false); 81 | return false; 82 | } 83 | _db.symGroup(idx).addSelfSym(cellId); 84 | _db.cell(cellId).setSelfSym(true); 85 | } 86 | } 87 | return true; 88 | } 89 | 90 | PROJECT_NAMESPACE_END 91 | -------------------------------------------------------------------------------- /src/parser/ParserSymNet.cpp: -------------------------------------------------------------------------------- 1 | #include "ParserSymNet.h" 2 | 3 | PROJECT_NAMESPACE_BEGIN 4 | 5 | 6 | bool ParserSymNet::read(const std::string &filename) 7 | { 8 | std::ifstream inf(filename.c_str()); 9 | if (!inf.is_open()) 10 | { 11 | ERR("Symnet parser:%s: cannot open file: %s \n", __FUNCTION__ , filename.c_str()); 12 | Assert(false); 13 | return false; 14 | } 15 | INF("Symnet parser: reading %s...\n", filename.c_str()); 16 | std::string lineStr; 17 | while (std::getline(inf, lineStr)) 18 | { 19 | std::istringstream iss(lineStr); 20 | std::vector split; 21 | std::string token; 22 | while(std::getline(iss, token, ' ')) 23 | { 24 | split.emplace_back(token); 25 | } 26 | if (split.size() == 2) 27 | { 28 | _pairs.emplace_back(std::make_pair(split.at(0), split.at(1))); 29 | } 30 | else if (split.size() == 1) 31 | { 32 | _selfs.emplace_back(split.at(0)); 33 | } 34 | else 35 | { 36 | Assert(false); 37 | } 38 | } 39 | 40 | /// Process the pairs read from the files 41 | if (!processNamePair()) 42 | { 43 | return false; 44 | } 45 | return true; 46 | } 47 | 48 | 49 | bool ParserSymNet::processNamePair() 50 | { 51 | /// Build a look up table for net names 52 | std::unordered_map netNameMap; 53 | for (IndexType netIdx = 0; netIdx < _db.numNets(); ++netIdx) 54 | { 55 | const auto &net = _db.net(netIdx);; 56 | netNameMap[net.name()] = netIdx; 57 | } 58 | /// If the pairs match the record of nets name, add them as a symmetry net 59 | for (const auto &pair : _pairs) 60 | { 61 | if (netNameMap.find(pair.first) != netNameMap.end() && netNameMap.find(pair.second) != netNameMap.end()) 62 | { 63 | IndexType netIdx1 = netNameMap[pair.first]; 64 | IndexType netIdx2 = netNameMap[pair.second]; 65 | _db.net(netIdx1).setSymNet(netIdx2, true); 66 | _db.net(netIdx2).setSymNet(netIdx1, false); 67 | INF("ParserSymNet:: left net %s %d\n, right net %s %d\n", _db.net(netIdx1).name().c_str(), netIdx1, _db.net(netIdx2).name().c_str(), netIdx2); 68 | } 69 | else 70 | { 71 | ERR("Symnet parser: symmetry net pair: %s %s are not inside the netlist! Ignored. \n", pair.first.c_str(), pair.second.c_str()); 72 | } 73 | } 74 | 75 | // Self 76 | for (const auto &self : _selfs) 77 | { 78 | if (netNameMap.find(self) != netNameMap.end()) 79 | { 80 | IndexType netIdx1 = netNameMap[self]; 81 | _db.net(netIdx1).markSelfSym(); 82 | } 83 | else 84 | { 85 | ERR("Symnet parser: self symmetry net: %s are not inside the netlist! Ignored. \n", self.c_str()); 86 | } 87 | } 88 | return true; 89 | } 90 | 91 | PROJECT_NAMESPACE_END 92 | -------------------------------------------------------------------------------- /src/util/GdsHelper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file GdsHelper.h 3 | * @brief Use utilities of the Gds db 4 | * @author Keren Zhu 5 | * @date 02/07/2019 6 | */ 7 | 8 | #ifndef ZKUTIL_GDS_HELPER_H_ 9 | #define ZKUTIL_GDS_HELPER_H_ 10 | 11 | #include 12 | #include 13 | #include "global/global.h" 14 | 15 | namespace klib 16 | { 17 | 18 | /// @brief detailed struct for the functions of processing gds shapes 19 | namespace GetSRefNameActionDetails 20 | { 21 | 22 | /// @brief default type 23 | template 24 | inline void getSName(std::string &name, ObjectType *object) 25 | { 26 | } 27 | 28 | /// @brief SREF type 29 | template<> 30 | inline void getSName(std::string &name, ::GdsParser::GdsDB::GdsCellReference *object) 31 | { 32 | name = object->refCell(); 33 | } 34 | } 35 | 36 | /// @brief aution function object to get the cell reference name 37 | struct GetSRefNameAction 38 | { 39 | /// @param A reference to the string to record the name of the sref 40 | GetSRefNameAction(std::string &name) : _name(name) {} 41 | template 42 | void operator()(::GdsParser::GdsRecords::EnumType type, ObjectType* object) 43 | { 44 | GetSRefNameActionDetails::getSName(_name, object); 45 | } 46 | 47 | /// @return a message of action for debug 48 | std::string message() const 49 | { 50 | return "GetSRefNameAction"; 51 | } 52 | 53 | 54 | std::string &_name; ///< The cell reference name 55 | }; 56 | /// @brief find the top cell of the db 57 | /// @param a gds db 58 | /// @return the name of the top cell 59 | inline std::string topCell(const ::GdsParser::GdsDB::GdsDB & db) 60 | { 61 | // Whether each cell is found as the subcell of the other 62 | std::map nameFound; 63 | // Iterate all the cells and record their names 64 | // Add reversely 65 | for (int idx = db.cells().size() - 1; idx >= 0; idx--) 66 | { 67 | nameFound[db.cells().at(idx).name()] = false; 68 | } 69 | for (auto &cell : db.cells()) 70 | { 71 | for (auto obj : cell.objects()) 72 | { 73 | std::string name = ""; 74 | ::GdsParser::GdsDB::GdsObjectHelpers()(obj.first, obj.second, GetSRefNameAction(name)); 75 | if (name != "") 76 | { 77 | nameFound[name] = true; 78 | } 79 | } 80 | } 81 | // Return the name that was not included in the other cells 82 | for (auto pair : nameFound) 83 | { 84 | if (pair.first != "" && !pair.second) 85 | { 86 | return pair.first; 87 | } 88 | } 89 | 90 | AssertMsg(0 ,"Reading Gds::%s: all cells are referenced in other cells! \n", __FUNCTION__); 91 | return ""; 92 | } 93 | } 94 | #endif //ZKUTIL_GDS_HELPER_H_ 95 | -------------------------------------------------------------------------------- /src/parser/ParserPin.cpp: -------------------------------------------------------------------------------- 1 | #include "ParserPin.h" 2 | #include 3 | 4 | PROJECT_NAMESPACE_BEGIN 5 | 6 | RealType stripShape(std::string word) 7 | { 8 | auto pos = word.rfind(')'); 9 | while (pos != std::string::npos) 10 | { 11 | word = word.substr(0, pos); 12 | pos = word.rfind(')'); 13 | } 14 | pos = word.find('('); 15 | while (pos != std::string::npos) 16 | { 17 | word = word.substr(pos+1); 18 | pos = word.find('('); 19 | } 20 | return ::atof(word.c_str()); 21 | } 22 | 23 | bool ParserPin::read(const std::string &filename) 24 | { 25 | std::ifstream inf(filename.c_str()); 26 | if (!inf.is_open()) 27 | { 28 | ERR("ParserPin::%s: cannot open file: %s \n", __FUNCTION__ , filename.c_str()); 29 | Assert(false); 30 | return false; 31 | } 32 | // Read in the file 33 | std::string line; 34 | IndexType cellIdx = INDEX_TYPE_MAX; 35 | IndexType numShapes = INDEX_TYPE_MAX; 36 | IndexType pinIdx = INDEX_TYPE_MAX; 37 | while (std::getline(inf, line)) 38 | { 39 | // Split the line into words 40 | std::vector words; 41 | std::istringstream iss(line); 42 | for (std::string str; iss >> str; ) 43 | { 44 | words.emplace_back(str); 45 | } 46 | if (words.size() == 1) 47 | { 48 | // Create a new cell 49 | cellIdx = _db.allocateCell(); 50 | _db.cell(cellIdx).setName(words.at(0)); 51 | } 52 | else if (words.size() == 2) 53 | { 54 | Assert(cellIdx != INDEX_TYPE_MAX); 55 | pinIdx = _db.allocatePin(); 56 | _db.pin(pinIdx).setName(words.at(0)); 57 | _db.cell(cellIdx).addPin(pinIdx); // Add pin to the cell 58 | numShapes = ::atoi(words.at(1).c_str()); // The second one denotes how many shapes there is in the pin 59 | } 60 | else if (words.size() > 2) 61 | { 62 | Assert(cellIdx != INDEX_TYPE_MAX); 63 | Assert(pinIdx != INDEX_TYPE_MAX); 64 | auto & pin = _db.pin(pinIdx); 65 | // Shapes are always rectagnles 66 | for (IndexType idx = 0; idx < numShapes; ++idx) 67 | { 68 | //IndexType gdsLayer = ::atoi(words.at(idx * 5).c_str()); 69 | RealType real = stripShape(words.at(idx *5 + 1)) * _db.tech().dbu(); 70 | LocType xLo = ::klib::autoRound(real); 71 | real = stripShape(words.at(idx *5 + 2)) * _db.tech().dbu(); 72 | LocType yLo = ::klib::autoRound(real); 73 | real = stripShape(words.at(idx *5 + 3)) * _db.tech().dbu(); 74 | LocType xHi = ::klib::autoRound(real); 75 | real = stripShape(words.at(idx *5 + 4)) * _db.tech().dbu(); 76 | LocType yHi = ::klib::autoRound(real); 77 | pin.shape().unionBox(Box(xLo, yLo, xHi, yHi)); 78 | } 79 | } 80 | else 81 | { 82 | // 0? empty line? 83 | Assert(false); 84 | return false; 85 | } 86 | } 87 | return true; 88 | } 89 | 90 | PROJECT_NAMESPACE_END 91 | -------------------------------------------------------------------------------- /src/place/signalPathMgr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file signalPathMgr.h 3 | * @brief The placement database data structure 4 | * @author Keren Zhu 5 | * @date 02/25/2020 6 | */ 7 | 8 | #ifndef IDEAPLACE_SIGALPATHMGR_H_ 9 | #define IDEAPLACE_SIGALPATHMGR_H_ 10 | 11 | #include "db/Database.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | /// @brief the decomposed signal path segment. It will contain four pins and involves three cells 16 | class SigPathSeg 17 | { 18 | public: 19 | explicit SigPathSeg() = default; 20 | explicit SigPathSeg(IndexType sPinIdx, IndexType midPinIdxA, IndexType midPinIdxB, IndexType tPinIdx) 21 | : _sPinIdx(sPinIdx), _midPinIdxA(midPinIdxA), _midPinIdxB(midPinIdxB), _tPinIdx(tPinIdx) 22 | {} 23 | /// @brief get the starting pin of the first segment 24 | IndexType beginPinFirstSeg() const { return _sPinIdx; } 25 | /// @brief get the ending pin of the first segment 26 | IndexType endPinFirstSeg() const { return _midPinIdxA; } 27 | /// @brief get the starting pin of the second segment 28 | IndexType beginPinSecondSeg() const { return _midPinIdxB; } 29 | /// @brief get the ending pin of the second segment 30 | IndexType endPinSecondSeg() const { return _tPinIdx; } 31 | private: 32 | IndexType _sPinIdx = INDEX_TYPE_MAX; ///< The starting pin index of the first segment. It belongs to cell 1, 33 | IndexType _midPinIdxA = INDEX_TYPE_MAX; ///< The ending pin index of the first segment. It belongs to cell 2. 34 | IndexType _midPinIdxB = INDEX_TYPE_MAX; ///< The starting pin index of the second segment. It belongs to cell 2. 35 | IndexType _tPinIdx = INDEX_TYPE_MAX; ///< The ending pin index of the second segment. It belongs to cell 3. 36 | }; 37 | 38 | /// @brief only has two pin segnments 39 | class SigPathTwoPinSeg 40 | { 41 | public: 42 | explicit SigPathTwoPinSeg() = default; 43 | explicit SigPathTwoPinSeg(IndexType sPinIdx, IndexType tPinIdx) : _sPinIdx(sPinIdx), _tPinIdx(tPinIdx) {} 44 | IndexType beginPin() const { return _sPinIdx; } 45 | IndexType endPin() const { return _tPinIdx; } 46 | private: 47 | IndexType _sPinIdx = INDEX_TYPE_MAX; ///< The starting pin 48 | IndexType _tPinIdx = INDEX_TYPE_MAX; ///< The ending pin 49 | }; 50 | 51 | 52 | /// @brief the signal path manager 53 | class SigPathMgr 54 | { 55 | public: 56 | /// @brief constructor 57 | /// @param the placement database 58 | explicit SigPathMgr(Database &db); 59 | /// @brief get the segment list 60 | const std::vector & vSegList() const { return _segs; } 61 | const std::vector> & vvSegList() const { return _segByPath; } 62 | const std::vector> & currentFlowRemainingTwoPinSegs() const { return _currentFlowRemainingTwoPinSegs; } 63 | private: 64 | void decomposeSignalPaths(); 65 | private: 66 | Database &_db; 67 | std::vector _segs; ///< The decomposed segments 68 | std::vector> _segByPath; 69 | std::vector> _currentFlowRemainingTwoPinSegs; 70 | }; 71 | 72 | PROJECT_NAMESPACE_END 73 | 74 | #endif //IDEAPLACE_SIGALPATHMGR_H_ 75 | -------------------------------------------------------------------------------- /src/parser/ProgArgs.cpp: -------------------------------------------------------------------------------- 1 | #include /// boost:iequals 2 | #include "ProgArgs.h" 3 | 4 | PROJECT_NAMESPACE_BEGIN 5 | 6 | /* Command Line member function */ 7 | 8 | 9 | /// Construct and parse command line options 10 | CommandLineOptions::CommandLineOptions(int argc, char** argv) 11 | { 12 | // Define options 13 | // 1st argument is long name 14 | // 2nd argument is short name (no short name if '\0' specified) 15 | // 3rd argument is description 16 | // 4th argument is mandatory (optional. default is false) 17 | // 5th argument is default value (optional. it used when mandatory is false) 18 | 19 | // 6th argument is extra constraint. 20 | // example: cmdline::range(1, 65535) 21 | // cmdline::oneof("http", "https", "ssh", "ftp") 22 | _parser.add ("pin", '\0', ".pin file", false); 23 | _parser.add ("netwgt", '\0', ".netwgt file", false); 24 | _parser.add ("connection", '\0', ".connection file", false); 25 | _parser.add ("techsimple", '\0', "techsimple file", false); 26 | _parser.add ("sym", '\0', ".sym file", false); 27 | _parser.add ("symnet", '\0', ".symnet file", false); 28 | _parser.add ("sigpath", '\0', ".sigpath file", false); 29 | _parser.add ("log", '\0', "log file", false, ""); 30 | 31 | // boolean options don't need template 32 | //_parser.add ("mute", '\0', "mute screen output"); 33 | 34 | // Parse and check command line 35 | // It returns only if command line arguments are valid. 36 | // If arguments are invalid, a parser output error msgs then exit program. 37 | // If help flag ('--help' or '-?') is specified, a parser output usage message then exit program. 38 | _parser.parse_check(argc, argv); 39 | 40 | populateAndCheckOptions(); 41 | } 42 | 43 | 44 | /*! Check command line arguments and update options for regular parsing 45 | */ 46 | void CommandLineOptions::populateAndCheckOptions() 47 | { 48 | // Populate options 49 | pinFile = _parser.get("pin"); 50 | netwgtFile = _parser.get("netwgt"); 51 | connectionFile = _parser.get("connection"); 52 | techsimpleFile = _parser.get("techsimple"); 53 | symFile = _parser.get("sym"); 54 | symnetFile = _parser.get("symnet"); 55 | sigpathFile = _parser.get("sigpath"); 56 | log = _parser.get("log"); 57 | for (const auto &rest : _parser.rest()) 58 | { 59 | gdsFiles.emplace_back(rest); 60 | } 61 | //mute = _parser.exist("mute"); 62 | } 63 | 64 | 65 | namespace ProgArgsDetails 66 | { 67 | ProgArgs parseProgArgsCMD(IntType argc, char** argv) 68 | { 69 | CommandLineOptions opt(argc, argv); 70 | ProgArgs progArgs; 71 | progArgs.setPinFile(opt.pinFile); 72 | progArgs.setNetwgtFile(opt.netwgtFile); 73 | progArgs.setConnectionFile(opt.connectionFile); 74 | progArgs.setTechsimpleFile(opt.techsimpleFile); 75 | progArgs.setSymFile(opt.symFile); 76 | progArgs.setSymnetFile(opt.symnetFile); 77 | progArgs.setSigpathFile(opt.sigpathFile); 78 | progArgs.gdsFiles() = opt.gdsFiles; 79 | 80 | return progArgs; 81 | } 82 | } 83 | 84 | PROJECT_NAMESPACE_END 85 | -------------------------------------------------------------------------------- /src/util/StopWatch.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file StopWatch.h 3 | * @brief My utility of stop watch 4 | * @author Keren Zhu 5 | * @date 04/01/2020 6 | */ 7 | 8 | #ifndef KLIB_STOPWATCH_HPP_ 9 | #define KLIB_STOPWATCH_HPP_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace klib 19 | { 20 | class StopWatch; 21 | /// @brief class for maintain the global stop watch 22 | class StopWatchMgr 23 | { 24 | public: 25 | static std::unique_ptr createNewStopWatch(std::string &&name); 26 | static void recordTime(std::uint64_t time, std::uint32_t idx) 27 | { 28 | _us[idx] = time; 29 | } 30 | static std::uint64_t time(std::string &&name) 31 | { 32 | auto iter = _nameToIdxMap.find(std::move(name)); 33 | assert(iter != _nameToIdxMap.end()); 34 | return _us[iter->second]; 35 | } 36 | /// @brief start the default timer. The time will return on the end, and won't be recorded 37 | static void quickStart(); 38 | /// @brief end the default timer. 39 | /// @return the time since start 40 | static uint64_t quickEnd(); 41 | 42 | private: 43 | static std::vector _us; // The record of the stop watch times 44 | static std::unordered_map _nameToIdxMap; ///< Map timer names to indices 45 | static StopWatch _watch; ///< The default one for quick usage that don't need to record 46 | }; 47 | /// @brief the single stop watch 48 | class StopWatch 49 | { 50 | public: 51 | StopWatch(std::uint32_t idx) : _idx(idx) { _count = false; start(); _us = 0; } 52 | StopWatch(const StopWatch &o) = delete; 53 | StopWatch(StopWatch &&o) 54 | : _last(std::move(o._last)), _count(std::move(o._count)), _us(std::move(o._us)), _idx(std::move(o._idx)) {} 55 | ~StopWatch() 56 | { 57 | stop(); 58 | StopWatchMgr::recordTime(_us, _idx); 59 | } 60 | void stop() 61 | { 62 | if (_count == false) { return; } 63 | _us += curTime(); 64 | _count = false; 65 | StopWatchMgr::recordTime(_us, _idx); 66 | } 67 | void start() 68 | { 69 | if (_count == true) { return; } 70 | _last = std::chrono::high_resolution_clock::now(); 71 | _count = true; 72 | } 73 | std::uint64_t curTime() 74 | { 75 | return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - _last).count(); 76 | } 77 | std::uint64_t record() 78 | { 79 | return _us; 80 | } 81 | void clear() 82 | { 83 | _us = 0; 84 | _count = false; 85 | } 86 | private: 87 | std::chrono::time_point _last; 88 | bool _count = false; 89 | std::uint64_t _us; ///< total microsecond 90 | std::uint32_t _idx; ///< The index in mgr 91 | }; 92 | }; 93 | #endif //KLIB_STOPWATCH_HPP_ 94 | -------------------------------------------------------------------------------- /src/place/ProximityMgr.cpp: -------------------------------------------------------------------------------- 1 | #include "ProximityMgr.h" 2 | 3 | PROJECT_NAMESPACE_BEGIN 4 | 5 | void ProximityMgr::applyProximityWithDummyNets() 6 | { 7 | for (const auto &proxmtGrp : _db.proximityGrps()) 8 | { 9 | this->addDummyNetForProximityGroup(proxmtGrp); 10 | } 11 | } 12 | 13 | void ProximityMgr::addDummyNetForProximityGroup(const ProximityGroup &pg) 14 | { 15 | IndexType netIdx = _db.allocateNet(); 16 | _dummyNets.emplace_back(netIdx); 17 | auto &net = _db.net(netIdx); 18 | net.setIsIo(false); 19 | net.markAsDummyNet(); 20 | net.setWeight(DEFAULT_DUMMY_NET_WEIGHT); 21 | for (IndexType cellIdx : pg.cells()) 22 | { 23 | IndexType pinIdx = _db.allocatePin(); 24 | net.addPin(pinIdx); 25 | auto &pin = _db.pin(pinIdx); 26 | pin.setCellIdx(cellIdx); 27 | _dummyPins.emplace_back(pinIdx); 28 | auto &cell = _db.cell(cellIdx); 29 | cell.addPin(pinIdx); 30 | _dummyCells.emplace_back(PinInCellIdx(cellIdx, cell.numPinIdx() - 1)); 31 | // Congigure the dummy pin 32 | pin.markAsDummyPin(); 33 | pin.shape() = Box(0, 0, 0, 0); 34 | } 35 | } 36 | 37 | void ProximityMgr::restore() 38 | { 39 | // Sort the indices in descending order and erase the vector 40 | std::sort(_dummyPins.begin(), _dummyPins.end(), std::greater()); 41 | std::sort(_dummyNets.begin(), _dummyNets.end(), std::greater()); 42 | auto comparePinInCellFunc = [&](const PinInCellIdx &lhs, const PinInCellIdx &rhs) 43 | { 44 | if (lhs.cellIdx == rhs.cellIdx) { return lhs.pinIdx > rhs.pinIdx; } 45 | else { return lhs.cellIdx < rhs.cellIdx; } 46 | }; 47 | std::sort(_dummyCells.begin(), _dummyCells.end(), comparePinInCellFunc); 48 | // The logic in the below are similar 49 | // 1. check the indices are in arithemeic progression 50 | // 2. clear the vector 51 | if (_dummyPins.size() > 0) 52 | { 53 | IndexType last = _dummyPins.front(); 54 | Assert(last == _db.numPins() - 1); 55 | for (IndexType idx = 1; idx < _dummyPins.size(); ++idx) 56 | { 57 | Assert(last -1 == _dummyPins[idx]); 58 | last = _dummyPins[idx]; 59 | } 60 | _db.vPinArray().erase(_db.vPinArray().begin() + _dummyPins.back(), _db.vPinArray().end()); 61 | } 62 | if (_dummyNets.size() > 0) 63 | { 64 | IndexType last = _dummyNets.front(); 65 | Assert(last == _db.numNets() - 1); 66 | for (IndexType idx = 1; idx < _dummyNets.size(); ++idx) 67 | { 68 | Assert(last -1 == _dummyNets[idx]); 69 | last = _dummyNets[idx]; 70 | } 71 | _db.nets().erase(_db.nets().begin() + _dummyNets.back(), _db.nets().end()); 72 | } 73 | // Dummy pins in cells need to be clear cell-wise 74 | auto clearCellFunc = [&] (IndexType idx) 75 | { 76 | IndexType cellIdx = _dummyCells.at(idx).cellIdx; 77 | IndexType last = _dummyCells.at(idx).pinIdx; 78 | Assert(last = _db.cell(cellIdx).pins().size() - 1); 79 | for(idx += 1; idx < _dummyCells.size(); ++idx) 80 | { 81 | if (_dummyCells.at(idx).cellIdx != cellIdx) { idx -=1; break; } 82 | Assert(last + 1 == _dummyCells.at(idx).pinIdx); 83 | last = _dummyCells[idx].pinIdx; 84 | } 85 | _db.cell(cellIdx).pins().erase(_db.cell(cellIdx).pins().begin() + last, _db.cell(cellIdx).pins().end()); 86 | return idx; 87 | }; 88 | for (IndexType idx = 0; idx < _dummyCells.size(); ++idx) 89 | { 90 | idx = clearCellFunc(idx); 91 | } 92 | } 93 | 94 | PROJECT_NAMESPACE_END 95 | -------------------------------------------------------------------------------- /src/writer/gdsii/WriteGds.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Keren on 09/14/2018 3 | // 4 | 5 | #include "WriteGds.h" 6 | 7 | PROJECT_NAMESPACE_BEGIN 8 | 9 | bool WriteGds::initWriter() 10 | { 11 | if (_isActive) 12 | { 13 | ERR("%s: Error: Try initing a gdsWriter while there is already one in active! \n", __FUNCTION__); 14 | return false; 15 | } 16 | //_gw = GdsParser::GdsWriter(outfile.c_str()); 17 | _isActive = true; 18 | return true; 19 | } 20 | 21 | 22 | bool WriteGds::createLib(const std::string &libName, RealType dbu_uu, RealType dbu_m) 23 | { 24 | checkActive(); 25 | _gw.create_lib(libName.c_str(), dbu_uu, dbu_m); 26 | return true; 27 | } 28 | 29 | bool WriteGds::endLib() 30 | { 31 | checkActive(); 32 | _gw.gds_write_endlib(); 33 | _isActive = false; 34 | return true; 35 | } 36 | 37 | bool WriteGds::writeCellBgn(const std::string &cellName) 38 | { 39 | checkActive(); 40 | _gw.gds_write_bgnstr(); 41 | _gw.gds_write_strname(cellName.c_str()); 42 | return true; 43 | } 44 | 45 | bool WriteGds::writeCellEnd() 46 | { 47 | checkActive(); 48 | _gw.gds_write_endstr(); 49 | return true; 50 | } 51 | 52 | bool WriteGds::writeCellRef(std::string cellName, XY loc, RealType mag, RealType angle) 53 | { 54 | checkActive(); 55 | _gw.gds_write_sref(); /// Contain an instance of ... 56 | _gw.gds_write_sname(cellName.c_str()); /// the cell ... 57 | int x = loc.x(); int y = loc.y(); 58 | _gw.gds_write_xy(&x, &y, 1); /// at these coordinates (database units) 59 | //_gw.gds_write_mag(mag); /// scale some magnitude 60 | //_gw.gds_write_angle(angle); /// tilted at some angle 61 | _gw.gds_write_endel( ); /// end of element 62 | return true; 63 | } 64 | 65 | bool WriteGds::writeRectangle(const Box &box, IntType layer, IntType dataType) 66 | { 67 | checkActive(); 68 | _gw.gds_write_boundary( ); /// write just the token 69 | _gw.gds_write_layer(static_cast(layer)); /// write layer 70 | _gw.gds_write_datatype(static_cast (dataType)); /// write datatype 71 | 72 | IntType x[5], y[5]; 73 | x[0] = box.xLo(); y[0] = box.yLo(); 74 | x[1] = box.xHi(); y[1] = box.yLo(); 75 | x[2] = box.xHi(); y[2] = box.yHi(); 76 | x[3] = box.xLo(); y[3] = box.yHi(); 77 | x[4] = box.xLo(); y[4] = box.yLo(); 78 | 79 | _gw.gds_write_xy( x, y, 5 ); // polygon, four vertices, first vertex repeated => 5 points 80 | _gw.gds_write_endel( ); // end of element 81 | return true; 82 | } 83 | 84 | bool WriteGds::writeText(const std::string &text, IntType x, IntType y, IntType layer, IntType size) 85 | { 86 | _gw.gds_create_text(text.c_str(), x, y, layer, size); 87 | return true; 88 | } 89 | 90 | 91 | bool WriteGds::writePath(const std::vector x, const std::vector y, IntType width, IntType layer, IntType dataType, IntType endCapType) 92 | { 93 | 94 | checkActive(); 95 | Assert(x.size() == y.size()); 96 | Assert(x.size() > 0); 97 | // create a path 98 | 99 | _gw.gds_write_path( ); 100 | _gw.gds_write_layer(layer); // layer 101 | _gw.gds_write_datatype(dataType); // datatype 102 | _gw.gds_write_pathtype(endCapType); // extended square ends 103 | _gw.gds_write_width(width); // nm wide 104 | _gw.gds_write_xy( &x[0], &y[0], x.size() ); 105 | _gw.gds_write_endel( ); 106 | return true; 107 | } 108 | PROJECT_NAMESPACE_END 109 | -------------------------------------------------------------------------------- /src/place/signalPathMgr.cpp: -------------------------------------------------------------------------------- 1 | #include "signalPathMgr.h" 2 | 3 | PROJECT_NAMESPACE_BEGIN 4 | 5 | SigPathMgr::SigPathMgr(Database &db) 6 | : _db(db) 7 | { 8 | this->decomposeSignalPaths(); 9 | } 10 | 11 | void SigPathMgr::decomposeSignalPaths() 12 | { 13 | for (IndexType pathIdx = 0; pathIdx < _db.vSignalPaths().size(); ++pathIdx) 14 | { 15 | const auto &path = _db.vSignalPaths().at(pathIdx); 16 | _segByPath.emplace_back(std::vector()); 17 | _currentFlowRemainingTwoPinSegs.emplace_back(std::vector()); 18 | // since the automatic generated current flow could include both sides of differential pair, we need to split the path is seen such scenario 19 | for (IntType idx = 0; idx < static_cast(path.vPinIdxArray().size()) - 3; ++idx) 20 | { 21 | const IndexType pinIdx1 = path.vPinIdxArray().at(idx); const auto &pin1 = _db.pin(pinIdx1); const IndexType cellIdx1 = pin1.cellIdx(); 22 | const IndexType pinIdx2 = path.vPinIdxArray().at(idx+1); const auto &pin2 = _db.pin(pinIdx2); const IndexType cellIdx2 = pin2.cellIdx(); 23 | const IndexType pinIdx3 = path.vPinIdxArray().at(idx+2); const auto &pin3 = _db.pin(pinIdx3); const IndexType cellIdx3 = pin3.cellIdx(); 24 | const IndexType pinIdx4 = path.vPinIdxArray().at(idx+3); const auto &pin4 = _db.pin(pinIdx4); const IndexType cellIdx4 = pin4.cellIdx(); 25 | 26 | bool pin23Same = cellIdx2 == cellIdx3; 27 | bool pin12Diff = cellIdx1 != cellIdx2; 28 | bool pin34Diff = cellIdx3 != cellIdx4; 29 | bool pin14Diff = cellIdx1 != cellIdx4; 30 | if (pin23Same and pin12Diff and pin34Diff and pin14Diff) 31 | { 32 | // valid segment 33 | _segs.emplace_back(SigPathSeg(pinIdx1, pinIdx2, pinIdx3, pinIdx4)); 34 | _segByPath.back().emplace_back(SigPathSeg(pinIdx1, pinIdx2, pinIdx3, pinIdx4)); 35 | DBG("SigPathMgr: add cell %d %s pin %d %s-> cell %d %s pin %d %s -> cell %d %s pin %d %s -> cell %d %s -> pin %d %s\n", 36 | cellIdx1, _db.cell(cellIdx1).name().c_str(), pinIdx1, _db.pin(pinIdx1).name().c_str(), 37 | cellIdx2, _db.cell(cellIdx2).name().c_str(), pinIdx2, _db.pin(pinIdx2).name().c_str(), 38 | cellIdx3, _db.cell(cellIdx3).name().c_str(), pinIdx3, _db.pin(pinIdx3).name().c_str(), 39 | cellIdx4, _db.cell(cellIdx4).name().c_str(), pinIdx4, _db.pin(pinIdx4).name().c_str()); 40 | } 41 | } 42 | // Process the corner case that a current flow path has only two pin. In this case it should implicitly mean the path ending in ground pin 43 | if (path.vPinIdxArray().size() == 2 and path.isPower()) 44 | { 45 | const IndexType pinIdx1 = path.vPinIdxArray().at(0); const auto &pin1 = _db.pin(pinIdx1); const IndexType cellIdx1 = pin1.cellIdx(); 46 | const IndexType pinIdx2 = path.vPinIdxArray().at(1); const auto &pin2 = _db.pin(pinIdx2); const IndexType cellIdx2 = pin2.cellIdx(); 47 | if (cellIdx1 != cellIdx2) 48 | { 49 | DBG("SigPathMgr: add cell %d %s pin %d %s-> cell %d %s pin %d %s \n", 50 | cellIdx1, _db.cell(cellIdx1).name().c_str(), pinIdx1, _db.pin(pinIdx1).name().c_str(), 51 | cellIdx2, _db.cell(cellIdx2).name().c_str(), pinIdx2, _db.pin(pinIdx2).name().c_str()); 52 | _currentFlowRemainingTwoPinSegs.back().emplace_back(SigPathTwoPinSeg(cellIdx1, cellIdx2)); 53 | } 54 | } 55 | } 56 | } 57 | 58 | PROJECT_NAMESPACE_END 59 | -------------------------------------------------------------------------------- /src/util/BasicTypeSelection.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASICTYPESELECTION_H__ 2 | #define __BASICTYPESELECTION_H__ 3 | 4 | #include 5 | 6 | // This file contains basic type selection utilities using meta-programming features of C++ 7 | // One common case that needs basic type selection is that when we have template function accepts two basic types. 8 | // Considering the following function. 9 | // 10 | // template 11 | // (RETURN_TYPE) add(T1 a, T2 b) 12 | // { 13 | // return a + b; 14 | // } 15 | // 16 | // What should be the RETURN_TYPE here? We cannot tell it should be T1 or T2 without knowing what are they 17 | // For example, if T1 is int and T2 is double, then the return type should be a double (T2). 18 | // However, if T1 is long, T2 is int, the return type should be long (T1). 19 | // 20 | // So we need a way to tell, between two types, which one has larger range, and we should return that type. 21 | // For integer types with same range, like std::int8_t and std::uint8_t, we define the signed version has larger rank 22 | 23 | namespace MetaProg 24 | { 25 | 26 | // Struct to get the rank of a given type T 27 | template 28 | struct TypeRank; 29 | 30 | // Template specialization to rank different types by their range from low to high 31 | template <> struct TypeRank {static constexpr std::uint32_t value = 0; }; 32 | template <> struct TypeRank {static constexpr std::uint32_t value = 1; }; 33 | template <> struct TypeRank {static constexpr std::uint32_t value = 2; }; 34 | template <> struct TypeRank {static constexpr std::uint32_t value = 3; }; 35 | template <> struct TypeRank {static constexpr std::uint32_t value = 4; }; 36 | template <> struct TypeRank {static constexpr std::uint32_t value = 5; }; 37 | template <> struct TypeRank {static constexpr std::uint32_t value = 6; }; 38 | template <> struct TypeRank {static constexpr std::uint32_t value = 7; }; 39 | template <> struct TypeRank {static constexpr std::uint32_t value = 8; }; 40 | template <> struct TypeRank {static constexpr std::uint32_t value = 9; }; 41 | 42 | // Struct to get the type of a given rank R 43 | template 44 | struct RankType; 45 | 46 | // Template specialization to map different ranks back to the corresponding types 47 | template <> struct RankType<0> { using type = std::uint8_t; }; 48 | template <> struct RankType<1> { using type = std::int8_t; }; 49 | template <> struct RankType<2> { using type = std::uint16_t; }; 50 | template <> struct RankType<3> { using type = std::int16_t; }; 51 | template <> struct RankType<4> { using type = std::uint32_t; }; 52 | template <> struct RankType<5> { using type = std::int32_t; }; 53 | template <> struct RankType<6> { using type = std::uint64_t; }; 54 | template <> struct RankType<7> { using type = std::int8_t; }; 55 | template <> struct RankType<8> { using type = float; }; 56 | template <> struct RankType<9> { using type = double; }; 57 | 58 | // Function that returns the max between two ranks 59 | template 60 | constexpr T maxRank(const T &r1, const T &r2) { return (r1 > r2 ? r1 : r2); } 61 | 62 | // Function to choose between two types 63 | // Choose the one with higher rank 64 | template 65 | struct selectBasicType 66 | { 67 | static constexpr std::uint32_t r1 = TypeRank::value; 68 | static constexpr std::uint32_t r2 = TypeRank::value; 69 | static constexpr std::uint32_t max = maxRank(r1, r2); 70 | using type = typename RankType::type; 71 | }; 72 | 73 | } // End of namespace MetaProg 74 | 75 | 76 | #endif // __BASICTYPESELECTION_H__ 77 | -------------------------------------------------------------------------------- /src/parser/ParserConnection.cpp: -------------------------------------------------------------------------------- 1 | #include "ParserConnection.h" 2 | 3 | PROJECT_NAMESPACE_BEGIN 4 | 5 | bool ParserConnection::read(const std::string &filename) 6 | { 7 | std::ifstream inf(filename.c_str()); 8 | if (!inf.is_open()) 9 | { 10 | ERR("ParserConnection::%s: cannot open file: %s \n", __FUNCTION__ , filename.c_str()); 11 | Assert(false); 12 | return false; 13 | } 14 | // Read in the file 15 | std::string line; 16 | while (std::getline(inf, line)) 17 | { 18 | // Split the line into words 19 | std::vector words; 20 | std::istringstream iss(line); 21 | for (std::string str; iss >> str; ) 22 | { 23 | words.emplace_back(str); 24 | } 25 | if (words.size() == 0) 26 | { 27 | ERR("ParserConnection::%s: unexpected syntax %s \n", __FUNCTION__, line.c_str()); 28 | Assert(false); 29 | return false; 30 | } 31 | IndexType netIdx = _db.allocateNet(); 32 | _db.net(netIdx).setName(words.at(0)); 33 | std::vector cells; 34 | std::vector pins; 35 | for (IndexType idx = 0; idx < (words.size() - 1)/2; ++idx) 36 | { 37 | std::string cellName = words.at(1 + idx * 2); 38 | std::string pinName = words.at(1 + idx * 2 + 1); 39 | if (pinName == "B" || pinName == "BULK") 40 | { 41 | WRN("ParserConnection::%s: ignore the bulk connection \n", __FUNCTION__); 42 | continue; 43 | } 44 | cells.emplace_back(cellName); 45 | pins.emplace_back(pinName); 46 | } 47 | // Find the corresponding pins in the database 48 | for (IndexType cellsIdx = 0; cellsIdx < cells.size(); ++cellsIdx) 49 | { 50 | const auto &cellName = cells.at(cellsIdx); 51 | const auto &pinName = pins.at(cellsIdx); 52 | IndexType cellIdx = INDEX_TYPE_MAX; 53 | for (IndexType idx = 0; idx < _db.numCells(); ++idx) 54 | { 55 | if (_db.cell(idx).name() == cellName) 56 | { 57 | cellIdx = idx; 58 | break; 59 | } 60 | } 61 | if (cellIdx == INDEX_TYPE_MAX) 62 | { 63 | // Did not find the cell 64 | ERR("ParserConnection::%s: cannot find the cell %s \n", __FUNCTION__, cellName.c_str()); 65 | Assert(false); 66 | return false; 67 | } 68 | const auto &cell = _db.cell(cellIdx); 69 | IndexType pinIdx = INDEX_TYPE_MAX; 70 | for (IndexType idx = 0; idx < cell.numPinIdx(); ++idx) 71 | { 72 | const auto & name = _db.pin(cell.pinIdx(idx)).name(); 73 | if (pinName == name) 74 | { 75 | pinIdx = cell.pinIdx(idx); 76 | break; 77 | } 78 | } 79 | if (pinIdx == INDEX_TYPE_MAX) 80 | { 81 | // Did not find the pin 82 | continue; 83 | // ERR("ParserConnection::%s: cannot find the pin %s in cell %s \n", 84 | // __FUNCTION__, cellName.c_str(), pinName.c_str()); 85 | // Assert(false); 86 | // return false; 87 | } 88 | // Add the pin to the net in the database 89 | _db.net(netIdx).addPin(pinIdx); 90 | _db.pin(pinIdx).addNetIdx(netIdx); 91 | _db.pin(pinIdx).setCellIdx(cellIdx); 92 | } 93 | } 94 | return true; 95 | } 96 | 97 | PROJECT_NAMESPACE_END 98 | -------------------------------------------------------------------------------- /src/place/ConstraintGraph.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ConstraintGraph.h 3 | * @brief The constraint graph implementation with boost graph 4 | * @author Keren Zhu 5 | * @date 11/25/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_CONSTRAINT_GRAPH_H_ 9 | #define IDEAPLACE_CONSTRAINT_GRAPH_H_ 10 | 11 | #include 12 | #include 13 | 14 | #include "global/global.h" 15 | 16 | PROJECT_NAMESPACE_BEGIN 17 | 18 | class ConstraintGraph 19 | { 20 | public: 21 | /// @brief default constructor 22 | explicit ConstraintGraph() 23 | { 24 | _cg.clear(); 25 | } 26 | typedef boost::adjacency_list < boost::setS, boost::vecS, boost::bidirectionalS, boost::no_property, boost::property < boost::edge_weight_t, IntType > > graph_t; 27 | typedef boost::graph_traits < graph_t >::vertex_descriptor vertex_descriptor; 28 | typedef boost::graph_traits < graph_t >::edge_descriptor edge_descriptor; 29 | typedef boost::graph_traits < graph_t >::edge_iterator edge_iterator; 30 | typedef boost::property_map::type IndexMap; 31 | typedef boost::graph_traits < graph_t >::adjacency_iterator adjacency_iterator; 32 | /// @brief return the boost graph 33 | graph_t & boostGraph() { return _cg; } 34 | /// @brief construct the graph with number of vertices 35 | /// @param the number of vertices 36 | void allocateVertices(IndexType numVex) { _cg.clear(); _cg = graph_t(numVex);} 37 | /// @brief get the number of nodes 38 | /// @return the number of nodes 39 | IndexType numNodes() const { return boost::num_vertices(_cg); } 40 | /// @brief get the source node index 41 | /// @return the index of the source node 42 | IndexType sourceNodeIdx() const { return numNodes() - 2;} 43 | /// @brief get the target node index 44 | /// @return the index of the target node 45 | IndexType targetNodeIdx() const { return numNodes() - 1; } 46 | /// @brief get the number of cells 47 | /// @return the number of cell nodes in the graph 48 | IndexType numCellNodes() const { return numNodes() - 2; } 49 | /// @brief add edge to the graph 50 | /// @param the source node index 51 | /// @param the target node index 52 | void addEdge(IndexType sourceIdx, IndexType targetIdx, IntType weight=1) 53 | { 54 | boost::add_edge(boost::vertex(sourceIdx, _cg), 55 | boost::vertex(targetIdx, _cg), 56 | weight, _cg); 57 | } 58 | /// @brief remove a edge from the graph 59 | /// @param the source index 60 | /// @param the target index 61 | void removeEdge(IndexType sourceIdx, IndexType targetIdx) 62 | { 63 | boost::remove_edge(boost::vertex(sourceIdx, _cg), 64 | boost::vertex(targetIdx, _cg), 65 | _cg); 66 | } 67 | /// @brief determine whether the graph has one specific edge 68 | /// @param the source index of the edge 69 | /// @param the target index of the edge 70 | /// @return true if has edge. false if not 71 | bool hasEdge(IndexType sourceIdx, IndexType targetIdx) 72 | { 73 | auto edge = boost::edge(boost::vertex(sourceIdx, _cg), 74 | boost::vertex(targetIdx, _cg), _cg); 75 | return edge.second; 76 | } 77 | 78 | void clear() 79 | { 80 | _cg.clear(); 81 | } 82 | 83 | private: 84 | graph_t _cg; ///< The boost graph 85 | }; 86 | 87 | PROJECT_NAMESPACE_END 88 | 89 | #endif //IDEAPLACE_CONSTRAINT_GRAPH_H_ 90 | -------------------------------------------------------------------------------- /src/db/Pin.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Pin.h 3 | * @brief The placement pin data structure 4 | * @author Keren Zhu 5 | * @date 10/01/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_PIN_H_ 9 | #define IDEAPLACE_PIN_H_ 10 | 11 | #include "global/global.h" 12 | #include "util/Box.h" 13 | 14 | PROJECT_NAMESPACE_BEGIN 15 | 16 | /// @class IDEAPLACE::Pin 17 | /// @brief the Pin class 18 | class Pin 19 | { 20 | public: 21 | /// @brief default constructor 22 | explicit Pin() = default; 23 | /*------------------------------*/ 24 | /* Getters */ 25 | /*------------------------------*/ 26 | /// @brief get the index of the cell this pin belonging to 27 | /// @return the index of the cell this pin belonging to 28 | IndexType cellIdx() const { return _cellIdx; } 29 | /// @brief get the relative location of the pin with respect to the cell 30 | /// @return the relative location of the pin with respect to the cell 31 | const Box & shape() const { return _shape; } 32 | /// @brief get the relative location of the pin with respect to the cell 33 | /// @return the relative location of the pin with respect to the cell 34 | Box & shape() { return _shape; } 35 | /// @brief get the name of the pin 36 | /// @return the name of the pin 37 | const std::string & name() const { return _name; } 38 | /// @brief get wether this pin is a dummy pin 39 | /// @return whether this pin is a dummy pin 40 | bool isDummyPin() const { return _isDummy; } 41 | /*------------------------------*/ 42 | /* Setters */ 43 | /*------------------------------*/ 44 | /// @brief set the index of the cell this pin belonging to 45 | /// @param the index of the cell this pin belonging to 46 | void setCellIdx(IndexType cellIdx) { _cellIdx = cellIdx; } 47 | /// @brief set the name of the pin 48 | /// @param the name of the pin 49 | void setName(const std::string &name) { _name = name; } 50 | void markAsDummyPin() { _isDummy = true; } 51 | /*------------------------------*/ 52 | /* Vector operations */ 53 | /*------------------------------*/ 54 | /// @brief get the number of nets 55 | /// @return the number of nets 56 | IndexType numNetIdx() const { return _netIdxArray.size(); } 57 | /// @brief add a net index to the pin 58 | /// @param the net index to be added 59 | void addNetIdx(IndexType netIdx) { _netIdxArray.emplace_back(netIdx); } 60 | /// @brief get one net index that this pin has 61 | /// @param the index in the net indices array 62 | /// @return one net index in database 63 | IndexType netIdx(IndexType idx) const { return _netIdxArray.at(idx); } 64 | /*------------------------------*/ 65 | /* Utils */ 66 | /*------------------------------*/ 67 | /// @brief get the relative middle point location of the pin with respect to the cell 68 | /// @return the middle point location of the pin 69 | XY midLoc() const { return _shape.center(); } 70 | private: 71 | std::string _name = ""; ///< The name for the pin 72 | std::vector _netIdxArray; ///< The indices of nets connected to this pin 73 | IndexType _cellIdx = INDEX_TYPE_MAX; ///< The cell this pin belongs to. Each pin can belong on only one cell 74 | Box _shape = Box(LOC_TYPE_MAX, LOC_TYPE_MAX, LOC_TYPE_MIN, LOC_TYPE_MIN); ///< The relative location of this pin with respect to the cell 75 | bool _isDummy = false; ///< This is a dummy pin 76 | }; 77 | 78 | PROJECT_NAMESPACE_END 79 | 80 | #endif ///IDEAPLACE_PIN_H_ 81 | -------------------------------------------------------------------------------- /src/util/MsgPrinter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Keren on 04/12/2018 3 | // 4 | 5 | #include "MsgPrinter.h" 6 | #include "Assert.h" 7 | 8 | PROJECT_NAMESPACE_BEGIN 9 | 10 | std::time_t MsgPrinter::_startTime = std::time(nullptr); 11 | FILE* MsgPrinter::_screenOutStream = stderr; 12 | FILE* MsgPrinter::_logOutStream = nullptr; 13 | std::string MsgPrinter::_logFileName = ""; 14 | 15 | /// Converting enum type to std::string 16 | std::string msgTypeToStr(MsgType msgType) 17 | { 18 | switch (msgType) 19 | { 20 | case MsgType::INF: return "INF"; break; 21 | case MsgType::WRN: return "WRN"; break; 22 | case MsgType::ERR: return "ERR"; break; 23 | case MsgType::DBG: return "DBG"; break; 24 | } 25 | AssertMsg(false, "Unknown MsgType. \n"); 26 | } 27 | 28 | /// Open a log file, all output will be stored in the log 29 | void MsgPrinter::openLogFile(const std::string &logFileName) 30 | { 31 | if (_logOutStream != nullptr) 32 | { 33 | fclose(_logOutStream); 34 | wrn("Current log file %s is forcibly closed\n", _logFileName.c_str()); 35 | } 36 | 37 | _logFileName = logFileName; 38 | _logOutStream = fopen(logFileName.c_str(), "w"); 39 | 40 | if (_logOutStream == nullptr) 41 | { 42 | err("Cannot open log file %s\n", logFileName.c_str()); 43 | } 44 | else { 45 | inf("Open log file %s\n", logFileName.c_str()); 46 | } 47 | } 48 | 49 | /// Close current log file 50 | void MsgPrinter::closeLogFile() 51 | { 52 | if (_logOutStream == nullptr) 53 | { 54 | wrn("No log file is opened. Call to %s is ignored.\n", __func__); 55 | } 56 | else 57 | { 58 | inf("Close log file %s.\n", _logFileName.c_str()); 59 | } 60 | } 61 | 62 | /// Print information 63 | void MsgPrinter::inf(const char* rawFormat, ...) 64 | { 65 | va_list args; 66 | va_start(args, rawFormat); 67 | print(MsgType::INF, rawFormat, args); 68 | va_end(args); 69 | } 70 | 71 | /// Print Warnings 72 | void MsgPrinter::wrn(const char* rawFormat, ...) 73 | { 74 | va_list args; 75 | va_start(args, rawFormat); 76 | print(MsgType::WRN, rawFormat, args); 77 | va_end(args); 78 | } 79 | 80 | ///Print errors 81 | void MsgPrinter::err(const char* rawFormat, ...) 82 | { 83 | va_list args; 84 | va_start(args, rawFormat); 85 | print(MsgType::ERR, rawFormat, args); 86 | va_end(args); 87 | } 88 | 89 | /// Print debugging information 90 | void MsgPrinter::dbg(const char* rawFormat, ...) 91 | { 92 | va_list args; 93 | va_start(args, rawFormat); 94 | print(MsgType::DBG, rawFormat, args); 95 | va_end(args); 96 | } 97 | 98 | /// Message printing kernel 99 | void MsgPrinter::print(MsgType msgType, const char* rawFormat, va_list args) 100 | { 101 | /// Get the message type 102 | std::string type = "[" + msgTypeToStr(msgType); 103 | 104 | /// Get local time and elapsed time 105 | struct tm* timeInfo; 106 | std::time_t now = std::time(nullptr); 107 | timeInfo = localtime(&now); 108 | double elapsed = difftime(now, _startTime); 109 | 110 | /// Local time 111 | char locTime[32]; 112 | strftime(locTime, 32, " %F %T ", timeInfo); 113 | 114 | /// Elapsed time 115 | char elpTime[32]; 116 | sprintf(elpTime, "%5.0lf sec] ", elapsed); 117 | 118 | // Combine all the strings together 119 | std::string format = type + std::string(locTime) + std::string(elpTime) + std::string(rawFormat); 120 | 121 | // print to log 122 | if (_logOutStream) 123 | { 124 | va_list args_copy; 125 | va_copy(args_copy, args); 126 | vfprintf(_logOutStream, format.c_str(), args_copy); 127 | va_end(args_copy); 128 | fflush(_logOutStream); 129 | } 130 | 131 | // print to screen 132 | if (_screenOutStream) 133 | { 134 | vfprintf(_screenOutStream, format.c_str(), args); 135 | fflush(_screenOutStream); 136 | } 137 | } 138 | PROJECT_NAMESPACE_END 139 | -------------------------------------------------------------------------------- /src/writer/gdsii/WriteGds.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Keren on 09/14/2018 3 | // 4 | 5 | #ifndef AROUTER_WRITEGDS_H_ 6 | #define AROUTER_WRITEGDS_H_ 7 | 8 | #include 9 | #include "global/global.h" 10 | #include "util/Box.h" 11 | 12 | // ================================================================================ 13 | // WriteGds.h 14 | // 15 | // A wrapper for Yibo's gds writer 16 | // 17 | // ================================================================================ 18 | 19 | PROJECT_NAMESPACE_BEGIN 20 | 21 | /// @brief enum for the datatype 22 | enum class GdsDataTypeType : Byte 23 | { 24 | NODATA = 0, 25 | BITARRAY = 1, 26 | INT2 = 2, 27 | INT4 = 3, 28 | REAL4 = 4, 29 | REAL8 = 5, 30 | ASCII = 6 31 | }; 32 | 33 | static IntType gdsDataTypeType2Int(GdsDataTypeType dataType) 34 | { 35 | switch(dataType) 36 | { 37 | case GdsDataTypeType::NODATA : return 0; break; 38 | case GdsDataTypeType::BITARRAY : return 1; break; 39 | case GdsDataTypeType::INT2 : return 2; break; 40 | case GdsDataTypeType::INT4 : return 3; break; 41 | case GdsDataTypeType::REAL4 : return 4; break; 42 | case GdsDataTypeType::REAL8 : return 5; break; 43 | case GdsDataTypeType::ASCII : return 6; break; 44 | default : return 0; break; 45 | } 46 | } 47 | 48 | // see http://www.artwork.com/gdsii/gdsii/page4.htm for the end cap path types 49 | enum class GdsPathEndCapType : Byte 50 | { 51 | FLUSH = 0, 52 | HALF_ROUND_EXTENSION = 1, 53 | HALF_WIDTH_EXTENSION = 2, 54 | CUSTOM = 4 55 | }; 56 | 57 | static IntType gdsPathEndCapType2Int(GdsPathEndCapType pathEnd) 58 | { 59 | switch(pathEnd) 60 | { 61 | case GdsPathEndCapType::FLUSH : return 0; break; 62 | case GdsPathEndCapType::HALF_ROUND_EXTENSION : return 1; break; 63 | case GdsPathEndCapType::HALF_WIDTH_EXTENSION : return 2; break; 64 | case GdsPathEndCapType::CUSTOM : return 4; break; 65 | default : return 0; break; 66 | } 67 | } 68 | 69 | // Check if the _gw is active, and if not, return false 70 | #ifdef NDEBUG 71 | #define checkActive() \ 72 | do { \ 73 | } while(false) 74 | #else 75 | #define checkActive() \ 76 | if (!_isActive) \ 77 | { \ 78 | ERR("%s: Error: There is no active gdsWriter inited yet! \n", __FUNCTION__); \ 79 | return false; \ 80 | } 81 | #endif 82 | 83 | /// Define a macro to check wheter _isActive 84 | class WriteGds 85 | { 86 | public: 87 | explicit WriteGds(std::string filename) : _gw(filename.c_str()) {} 88 | 89 | ////////////////////////////// 90 | /// Writing function routines 91 | ////////////////////////////// 92 | 93 | bool initWriter(); 94 | bool createLib(const std::string &libName, RealType dbu_uu = 0.001, RealType dbu_m = 1e-09); 95 | bool endLib(); 96 | bool writeCellBgn(const std::string &cellName); 97 | bool writeCellEnd(); 98 | 99 | //////////////////////////////// 100 | /// Write shapes, cells etc. 101 | //////////////////////////////// 102 | /// Write a cell/structure 103 | bool writeCellRef(std::string cellName, XY loc, RealType mag = 1.0, RealType angle = 0.0); 104 | 105 | /// Write an rectangle 106 | bool writeRectangle(const Box &box, IntType layer = 1, IntType dataType = 0); 107 | bool writeRectangle(const Box &box, IntType layer = 1, GdsDataTypeType dataType = GdsDataTypeType::NODATA) { return writeRectangle(box, layer, gdsDataTypeType2Int(dataType)); } 108 | 109 | /// Write an text 110 | bool writeText(const std::string &text, IntType x, IntType y, IntType layer, IntType size); 111 | 112 | /// write an path 113 | bool writePath(const std::vector x, const std::vector y, IntType width, IntType layer = 1, IntType dataType = 0, IntType ennCapType = 0); 114 | bool writePath(const std::vector x, const std::vector y, IntType width, IntType layer = 1, GdsDataTypeType dataType = GdsDataTypeType::NODATA, GdsPathEndCapType endCapType= GdsPathEndCapType::FLUSH) { return writePath(x, y, width, layer, gdsDataTypeType2Int(dataType), gdsPathEndCapType2Int(endCapType)); } 115 | private: 116 | GdsParser::GdsWriter _gw; 117 | bool _isActive = false; /// Whether GdsParser::GdsWriter is in active writing 118 | }; 119 | 120 | PROJECT_NAMESPACE_END 121 | #endif //AROUTER_WRITEGDS_H_ 122 | -------------------------------------------------------------------------------- /src/pinassign/VirtualPinAssigner.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file VirtualPinAssigner.h 3 | * @brief Kernel for assigning virtual pins on the placement boundary 4 | * @author Keren Zhu 5 | * @date 02/21/2020 6 | */ 7 | 8 | #ifndef IDEAPLACE_VIRTUAL_PIN_ASSIGNMER_H_ 9 | #define IDEAPLACE_VIRTUAL_PIN_ASSIGNMER_H_ 10 | 11 | #include "db/Database.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | /// @class IDEAPLACE::VirtualPinAssigner 16 | /// @brief The kernel for assigning virtual pins 17 | class VirtualPinAssigner 18 | { 19 | public: 20 | explicit VirtualPinAssigner(Database &db) : _db(db) 21 | { 22 | _virtualPinInterval = db.parameters().virtualPinInterval(); 23 | _virtualBoundaryExtension = db.parameters().virtualBoundaryExtension(); 24 | } 25 | /* Kernal interface */ 26 | /// @brief cnfigure the virtual boundary based on databse 27 | void reconfigureVirtualPinLocationFromDB(IndexType iter); 28 | /// @brief reconfigure the virtual boundary and pin locations 29 | void reconfigureVirtualPinLocations(const Box &cellsBBox); 30 | /// @brief solve pin assignment from information from DB 31 | bool pinAssignmentFromDB(); 32 | /// @brief short cut to solve the problem from databse information 33 | bool solveFromDB(); 34 | /// @brief solve the pin assignment problem. Export the solution to the database 35 | /// @param a function for query cell location 36 | bool pinAssignment(std::function(IndexType)> cellLocQueryFunc); 37 | 38 | /* Parameter settings */ 39 | /// @brief set the extension distance of placement boundary to cell boundary 40 | void setVirtualBoundaryExtension(LocType ex) { _virtualBoundaryExtension = ex; } 41 | /// @brief set the interval between pins 42 | void setVirtualPinInterval(LocType in) { _virtualPinInterval = in; } 43 | /// @brief use fast mode 44 | void useFastMode() { _fastMode = true; } 45 | void useSlowMode() { _fastMode = false; } 46 | private: 47 | void assignPowerPin() 48 | { 49 | #ifdef DEBUG_PINASSIGN 50 | DBG("Ideaplace: pinassgin: %s\n", __FUNCTION__); 51 | #endif 52 | for (IndexType netIdx = 0; netIdx < _db.numNets(); ++netIdx) 53 | { 54 | auto & net = _db.net(netIdx); 55 | if (net.isVdd()) 56 | { 57 | _topPin.assign(netIdx); 58 | net.setVirtualPin(_topPin); 59 | continue; 60 | } 61 | if (net.isVss()) 62 | { 63 | _botPin.assign(netIdx); 64 | net.setVirtualPin(_botPin); 65 | continue; 66 | } 67 | } 68 | #ifdef DEBUG_PINASSIGN 69 | DBG("Ideaplace: pinassgin: end %s\n", __FUNCTION__); 70 | #endif 71 | } 72 | bool _lpSimplexPinAssignment( 73 | std::function isSymNetFunc, 74 | std::function isLeftPinFunc, 75 | std::function isOtherNetFunc, 76 | std::function isOtherPinFunc, 77 | std::function symNetToPinCostFunc, 78 | std::function otherNetToPinCostFunc, 79 | std::function setSymNetPairToPinFunc, 80 | std::function setOtherNetToPinFunc 81 | ); 82 | bool _networkSimplexPinAssignment( 83 | std::function useNetFunc, 84 | std::function usePinFunc, 85 | std::function netToPinCostFunc, 86 | std::function setNetToVirtualPinFunc); 87 | private: 88 | Database &_db; ///< The placement database 89 | Box _boundary; ///< The virtual boundary of the placement 90 | std::vector _virtualPins; ///< The locations for virtual pins 91 | VirtualPin _topPin; ///< The pin at top 92 | VirtualPin _botPin; ///< The pin at bottom 93 | LocType _virtualBoundaryExtension = -1; ///< The extension to placement cell bounding box 94 | LocType _virtualPinInterval = -1; ///< The interval between virtual pins 95 | std::map _leftToRightMap; // _leftToRightMap[idx of left] = idx of right 96 | bool _fastMode = false; ///< True : use two pass MCMF. False: use simplex 97 | }; 98 | 99 | PROJECT_NAMESPACE_END 100 | 101 | #endif //IDEAPLACE_VIRTUAL_PIN_ASSIGNMER_H_ 102 | -------------------------------------------------------------------------------- /src/util/linear_programming_trait.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file linear_programming_trait.h 3 | * @brief The linear programming concept 4 | * @author Keren Zhu 5 | * @date 03/10/2020 6 | */ 7 | 8 | #ifndef KLIB_LINEAR_PROGRAMMING_TRAIT_H_ 9 | #define KLIB_LINEAR_PROGRAMMING_TRAIT_H_ 10 | 11 | #include "Assert.h" 12 | #include 13 | 14 | namespace klib 15 | { 16 | 17 | namespace _lp 18 | { 19 | 20 | struct _undefined 21 | { 22 | typedef int variable_type; 23 | typedef double value_type; 24 | typedef double expr_type; 25 | typedef double constr_type; 26 | typedef int status_type; 27 | 28 | variable_type addVar() { Assert(false); return 0;} 29 | void addConstr(const constr_type &) {} 30 | void setVarLowerBound(const variable_type &, const value_type &) {} 31 | void setVarUpperBound(const variable_type &, const value_type &) {} 32 | void setVarInteger(const variable_type &) {} 33 | void setVarContinuous(const variable_type &) {} 34 | void setObjectiveMaximize() {} 35 | void setObjectiveMinimize() {} 36 | void setObjective(const expr_type &) {} 37 | void solve() {} 38 | status_type status() { return 0;} 39 | bool isOptimal() { return true; } 40 | bool isSuboptimal() { return true; } 41 | bool isUnbounded() { return true; } 42 | bool isInfeasible() { return false;} 43 | value_type evaluateExpr(const expr_type &) const {return 0;} 44 | value_type solution(const variable_type &) const { return 0;} 45 | std::string statusStr() const { return "";} 46 | void setNumThreads(std::uint32_t) {} 47 | }; 48 | 49 | template 50 | struct linear_programming_trait 51 | { 52 | typedef typename solver_type::variable_type variable_type; ///< The LP variable type 53 | typedef typename solver_type::value_type value_type; ///< The value type of LP problem. Usually variety of floats 54 | typedef typename solver_type::expr_type expr_type; ///< The type for expressions 55 | typedef typename solver_type::constr_type constr_type; ///< The type for constraints 56 | typedef typename solver_type::status_type status_type; ///< The LP solving status 57 | 58 | static variable_type addVar(solver_type &solver) 59 | { 60 | return solver.addVar(); 61 | } 62 | static void addConstr(solver_type &solver, const constr_type &constr) 63 | { 64 | solver.addConstr(constr); 65 | } 66 | static void setVarLowerBound(solver_type &solver, const variable_type &var, const value_type &val) 67 | { 68 | solver.setVarLowerBound(var, val); 69 | } 70 | static void setVarUpperBound(solver_type &solver, const variable_type &var, const value_type &val) 71 | { 72 | solver.setVarUpperBound(var, val); 73 | } 74 | static void setVarInteger(solver_type &solver, const variable_type &var) 75 | { 76 | solver.setVarInteger(var); 77 | } 78 | static void setVarContinuous(solver_type &solver, const variable_type &var) 79 | { 80 | solver.setVarContinuous(var); 81 | } 82 | static void setObjectiveMaximize(solver_type &solver) 83 | { 84 | solver.setObjectiveMaximize(); 85 | } 86 | static void setObjectiveMinimize(solver_type &solver) 87 | { 88 | solver.setObjectiveMinimize(); 89 | } 90 | static void setObjective(solver_type &solver, const expr_type &expr) 91 | { 92 | solver.setObjective(expr); 93 | } 94 | static void solve(solver_type &solver) 95 | { 96 | solver.solve(); 97 | } 98 | static status_type status(solver_type &solver) 99 | { 100 | return solver.status(); 101 | } 102 | static bool isOptimal(solver_type &solver) 103 | { 104 | return solver.isOptimal(); 105 | } 106 | static bool isSuboptimal(solver_type &solver) 107 | { 108 | return solver.isSuboptimal(); 109 | } 110 | static bool isUnbounded(solver_type &solver) 111 | { 112 | return solver.isUnbounded(); 113 | } 114 | static bool isInfeasible(solver_type &solver) 115 | { 116 | return solver.isInfeasible(); 117 | } 118 | static value_type evaluateExpr(const solver_type &solver, const expr_type &expr) 119 | { 120 | return solver.evaluateExpr(expr); 121 | } 122 | static value_type solution(const solver_type &solver, const variable_type &var) 123 | { 124 | return solver.solution(var); 125 | } 126 | static std::string statusStr(const solver_type &solver) 127 | { 128 | return solver.statusStr(); 129 | } 130 | static void setNumThreads(solver_type &solver, std::uint32_t numThreads) 131 | { 132 | solver.setNumThreads(numThreads); 133 | } 134 | }; 135 | 136 | } //namespace _lp 137 | 138 | } // namespace klib 139 | 140 | #endif // KLIB_LINEAR_PROGRAMMING_BASE_H_ 141 | -------------------------------------------------------------------------------- /src/util/Polygon2Rect.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Polygon2Rect.h 3 | * @author Keren Zhu 4 | * @date 11/06/2018 5 | */ 6 | 7 | #ifndef KLIB_POLYGON2RECT_H_ 8 | #define KLIB_POLYGON2RECT_H_ 9 | 10 | #include "Box.h" 11 | #include 12 | 13 | 14 | //using namespace limbo::geometry; 15 | 16 | 17 | namespace limbo { namespace geometry { 18 | 19 | /** 20 | * @brief if your point class setting is different from that in the default point_traits, please create a specialization 21 | * 22 | * The specialization should be in the same scope as the original template struct 23 | */ 24 | template 25 | struct point_traits> 26 | { 27 | /// point type 28 | typedef PROJECT_NAMESPACE::XY point_type; 29 | /// coordinate type 30 | typedef T coordinate_type; 31 | 32 | /** 33 | * @brief access coordinates 34 | * @param point a data point 35 | * @param orient orientation can be HORIZONTAL(x) or VERTICAL(y) 36 | * @return x or y coordinate 37 | */ 38 | static coordinate_type get(const point_type& point, orientation_2d orient) 39 | { 40 | if (orient == HORIZONTAL) return point.x(); 41 | else if (orient == VERTICAL) return point.y(); 42 | else assert(0); 43 | } 44 | /** 45 | * @brief set coordinates 46 | * @param point a data point 47 | * @param orient orientation can be HORIZONTAL(x) or VERTICAL(y) 48 | * @param value data value 49 | */ 50 | static void set(point_type& point, orientation_2d orient, coordinate_type value) 51 | { 52 | if (orient == HORIZONTAL) return point.setX(value); 53 | else if (orient == VERTICAL) return point.setY(value); 54 | else assert(0); 55 | } 56 | /** 57 | * @brief construct a point object 58 | * @param x x coordinate 59 | * @param y y coordinate 60 | * @return the point object 61 | */ 62 | static point_type construct(coordinate_type x, coordinate_type y) 63 | { 64 | point_type p; 65 | p.setX(x); p.setY(y); 66 | return p; 67 | } 68 | }; 69 | 70 | }} 71 | 72 | 73 | namespace limbo { namespace geometry { 74 | 75 | /** 76 | * @brief if your rectangle class setting is different from that in the default point_traits, please create a specialization 77 | */ 78 | template 79 | struct rectangle_traits> 80 | { 81 | /// rectangle type 82 | typedef PROJECT_NAMESPACE::Box rectangle_type; 83 | /// coordinate type 84 | typedef T coordinate_type; 85 | 86 | /** 87 | * @brief access coordinates 88 | * @param rect a rectangle object 89 | * @param dir can be LEFT (xl), BOTTOM (yl), RIGHT (xh) or TOP (yh) 90 | * @return coordinate 91 | */ 92 | static coordinate_type get(const rectangle_type& rect, direction_2d dir) 93 | { 94 | switch (dir) 95 | { 96 | case LEFT: return rect.xLo(); 97 | case BOTTOM: return rect.yLo(); 98 | case RIGHT: return rect.xHi(); 99 | case TOP: return rect.yHi(); 100 | default: assert(0); 101 | } 102 | } 103 | /** 104 | * @brief set coordinates 105 | * @param rect a rectangle object 106 | * @param dir can be LEFT (xl), BOTTOM (yl), RIGHT (xh) or TOP (yh) 107 | * @param value coordinate value 108 | */ 109 | static void set(rectangle_type& rect, direction_2d dir, coordinate_type value) 110 | { 111 | switch (dir) 112 | { 113 | case LEFT: rect.setXLo(value); break; 114 | case BOTTOM: rect.setYLo(value); break; 115 | case RIGHT: rect.setXHi(value); break; 116 | case TOP: rect.YHi(value); break; 117 | default: assert(0); 118 | } 119 | } 120 | /** 121 | * @brief construct rectangle 122 | * @param xl, yl, xh, yh coordinates of rectangle 123 | * @return a rectangle object 124 | */ 125 | static rectangle_type construct(coordinate_type xl, coordinate_type yl, coordinate_type xh, coordinate_type yh) 126 | { 127 | rectangle_type rect; 128 | rect.setXLo(xl); rect.setYLo(yl); 129 | rect.setXHi(xh); rect.setYHi(yh); 130 | return rect; 131 | } 132 | }; 133 | 134 | }} 135 | 136 | namespace klib 137 | { 138 | template 139 | inline bool convertPolygon2Rects(const std::vector> &pts, std::vector> &rects) 140 | { 141 | typedef typename PROJECT_NAMESPACE::XY PtType; 142 | typedef typename PROJECT_NAMESPACE::Box RectType; 143 | 144 | limbo::geometry::Polygon2Rectangle, std::vector> p2r(rects, pts.begin(), pts.end(), limbo::geometry::HOR_VER_SLICING); 145 | return p2r(); 146 | } 147 | } 148 | 149 | #endif ///KLIB_POLYGON2RECT_H_ 150 | -------------------------------------------------------------------------------- /src/db/Parameters.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Parameters.h 3 | * @brief The placement parameters 4 | * @author Keren Zhu 5 | * @date 10/16/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_PARAMETERS_H_ 9 | #define IDEAPLACE_PARAMETERS_H_ 10 | 11 | #include "global/global.h" 12 | #include "util/Box.h" 13 | 14 | PROJECT_NAMESPACE_BEGIN 15 | 16 | /// @class IDEAPLACE::Parameters 17 | /// @brief The placement eingie parameters 18 | class Parameters 19 | { 20 | public: 21 | /// @brief default constrcutor 22 | explicit Parameters(); 23 | /*------------------------------*/ 24 | /* Set the parameters */ 25 | /*------------------------------*/ 26 | /// @brief set the boundry constraints 27 | /// @param the placement boundry 28 | void setBoundaryConstraint(const Box &boundaryConstraint) { _boundaryConstraint = boundaryConstraint; } 29 | /// @brief open the functionality of virtual pin assignment 30 | void openVirtualPinAssignment() { _ifUsePinAssignment = true; } 31 | /// @brief close the functionality of virtual pin assignment 32 | void closeVirtualPinAssignment() { _ifUsePinAssignment = false; } 33 | /// @brief set the number of threads 34 | void setNumThreads(IndexType numThreads) { _numThreads = numThreads; } 35 | /// @brief set the grid step constraint 36 | void setGridStep(LocType gridStep) { _gridStep = gridStep; } 37 | /// @brief set the virutal boundary extension. The extension of boundary to io pin with respect to the cell placement 38 | void setVirtualBoundaryExtension(LocType virtualBoundaryExtension) { _virtualBoundaryExtension = virtualBoundaryExtension; _layoutOffset = 2 * virtualBoundaryExtension; } 39 | /// @brief set the pin interval 40 | void setVirtualPinInterval(LocType virtualPinInterval) { _virtualPinInterval = virtualPinInterval; } 41 | /*------------------------------*/ 42 | /* Query the parameters */ 43 | /*------------------------------*/ 44 | /// @brief whether the boundry constraint is set 45 | /// @return whether the boundry constraint is set 46 | bool isBoundaryConstraintSet() const { return _boundaryConstraint.valid(); } 47 | /// @brief get the boundry constraint 48 | /// @return the boundry constraint 49 | const Box & boundaryConstraint() const { return _boundaryConstraint; } 50 | /// @brief get whether to use the virtual pin assignment functionality 51 | bool ifUsePinAssignment() const { return _ifUsePinAssignment; } 52 | /// @brief get the number of thread 53 | IndexType numThreads() const { return _numThreads; } 54 | /// @brief get the grid step 55 | LocType gridStep() const { return _gridStep; } 56 | /// @brief get wether there is grid step constraint 57 | bool hasGridStep() const { return _gridStep > 0; } 58 | /// @brief get the extension of virtual boundary of cell placement boundary 59 | LocType virtualBoundaryExtension() const { return _virtualBoundaryExtension; } 60 | /// @brief get the interval of virtual io pins 61 | LocType virtualPinInterval() const { return _virtualPinInterval; } 62 | /// @brief get the layout offset 63 | LocType layoutOffset() const { return _layoutOffset; } 64 | /// @brief get the default aspect ratio for the global placement 65 | RealType defaultAspectRatio() const { return _defaultAspectRatio; } 66 | /// @brief get the default max white space 67 | RealType maxWhiteSpace() const { return _maxWhiteSpace; } 68 | /// @brief get the default signal flow operator weight 69 | RealType defaultSignalFlowWeight() const { return _defaultSignalFlowWeight; } 70 | /// @brief get the default current flow operator weight 71 | RealType defaultCurrentFlowWeight() const { return _defaultCurrentFlowWeight; } 72 | /// @@brief get the weighing ratio of power to regular net 73 | RealType defaultRelativeRatioOfPowerNet() const { return _defaultRelativeRatioOfPowerNet; } 74 | private: 75 | Box _boundaryConstraint = Box(LOC_TYPE_MAX, LOC_TYPE_MAX, LOC_TYPE_MIN, LOC_TYPE_MIN); 76 | bool _ifUsePinAssignment; ///< If do pin assignment 77 | IndexType _numThreads; 78 | LocType _gridStep; 79 | LocType _virtualBoundaryExtension; ///< The extension of current virtual boundary to the bounding box of placement 80 | LocType _virtualPinInterval; ///< The interval between each virtual pin 81 | LocType _layoutOffset; ///< The default offset for the placement 82 | RealType _defaultAspectRatio; ///< The defaut aspect ratio for global placement 83 | RealType _maxWhiteSpace; ///< The default maximum white space target 84 | RealType _defaultSignalFlowWeight; ///< The default weight for signal flow operators 85 | RealType _defaultCurrentFlowWeight; ///< The default weight for current flow operators 86 | RealType _defaultRelativeRatioOfPowerNet; ///< The weighing ratio of power to regular net 87 | 88 | }; 89 | 90 | PROJECT_NAMESPACE_END 91 | 92 | #endif ///IDEAPLACE_PARAMETERS_H_ 93 | -------------------------------------------------------------------------------- /src/place/nlp/nlpInitPlace.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file nlpInitPlace.hpp 3 | * @brief The non-lnear programming init place algorithms for global plaement 4 | * @author Keren Zhu 5 | * @date 04/02/2020 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "global/global.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | namespace nlp { 16 | namespace init_place 17 | { 18 | 19 | /* Initial placement */ 20 | template 21 | struct init_place_trait 22 | { 23 | // static T construct(NlpType &) 24 | // static void initPlace(T&, NlpType &) 25 | }; 26 | 27 | // @brief random spread among the boundary. With grid of number of cells 28 | struct init_random_placement_with_number_of_cells_uniform_distribution 29 | { 30 | static constexpr RealType range = 0.8; ///< Distrubute the location into range ratio of the boundary 31 | }; 32 | 33 | template<> 34 | struct init_place_trait 35 | { 36 | typedef init_random_placement_with_number_of_cells_uniform_distribution T; 37 | template 38 | static T construct(NlpType &) { return T(); } 39 | template 40 | static void initPlace(T &, NlpType &nlp) 41 | { 42 | using coord_type = typename NlpType::nlp_coordinate_type; 43 | const auto xCenter = (nlp._boundary.xLo() + nlp._boundary.xHi()) / 2; 44 | const auto yCenter = (nlp._boundary.yLo() + nlp._boundary.yHi()) / 2; 45 | XY initLoc(xCenter, yCenter); 46 | const IndexType numCells = nlp._db.numCells(); 47 | for (IndexType cellIdx = 0; cellIdx < numCells; ++cellIdx) 48 | { 49 | const auto xIdx = nlp.plIdx(cellIdx, Orient2DType::HORIZONTAL); 50 | const auto yIdx = nlp.plIdx(cellIdx, Orient2DType::VERTICAL); 51 | const IntType ranx = rand() % numCells; 52 | const IntType rany = rand() % numCells; 53 | const IntType adjustx = ranx - numCells / 2; 54 | const IntType adjusty = rany - numCells / 2; 55 | const auto ranfx = static_cast(adjustx); 56 | const auto ranfy = static_cast(adjusty); 57 | const auto locx = ranfx * T::range + xCenter; 58 | const auto locy = ranfy * T::range + xCenter; 59 | nlp._pl(xIdx) = locx; 60 | nlp._pl(yIdx) = locy; 61 | } 62 | } 63 | }; 64 | 65 | /// @brief randomly spread the cells in a normal distrubtion near the center 66 | struct init_random_placement_with_normal_distribution_near_center 67 | { 68 | static constexpr RealType randomInitPlaceStddev = 0.01; ///< The standard deviation of the initial random placement in terms of the width/height of the boundary 69 | }; 70 | 71 | template<> 72 | struct init_place_trait 73 | { 74 | typedef init_random_placement_with_normal_distribution_near_center T; 75 | template 76 | static T construct(NlpType &) { return T(); } 77 | template 78 | static void initPlace(T &, NlpType &nlp) 79 | { 80 | using coord_type = typename NlpType::nlp_coordinate_type; 81 | const auto xCenter = (nlp._boundary.xLo() + nlp._boundary.xHi()) / 2; 82 | const auto yCenter = (nlp._boundary.yLo() + nlp._boundary.yHi()) / 2; 83 | XY initLoc(xCenter, yCenter); 84 | const IndexType numCells = nlp._db.numCells(); 85 | std::default_random_engine gen(0); 86 | RealType stddev = init_random_placement_with_normal_distribution_near_center::randomInitPlaceStddev * std::min(nlp._boundary.xLen(), nlp._boundary.yLen()); 87 | std::normal_distribution movDistrX(initLoc.x(), stddev); 88 | std::normal_distribution movDistrY(initLoc.y(), stddev); 89 | for (IndexType cellIdx = 0; cellIdx < numCells; ++cellIdx) 90 | { 91 | const coord_type xOffset = nlp._db.cell(cellIdx).cellBBox().xLen() * nlp._scale; 92 | const coord_type yOffset = nlp._db.cell(cellIdx).cellBBox().yLen() * nlp._scale; 93 | const auto xIdx = nlp.plIdx(cellIdx, Orient2DType::HORIZONTAL); 94 | const auto yIdx = nlp.plIdx(cellIdx, Orient2DType::VERTICAL); 95 | const coord_type locx = movDistrX(gen) - xOffset * 0.5; 96 | const coord_type locy = movDistrY(gen) - yOffset * 0.5; 97 | nlp._pl(xIdx) = locx; 98 | nlp._pl(yIdx) = locy; 99 | } 100 | //nlp.alignToSym(); 101 | } 102 | }; 103 | } // namespace init_placement 104 | } //namespae nlp 105 | 106 | PROJECT_NAMESPACE_END 107 | -------------------------------------------------------------------------------- /src/place/constraintGraphGeneration.cpp: -------------------------------------------------------------------------------- 1 | #include "constraintGraphGeneration.h" 2 | 3 | PROJECT_NAMESPACE_BEGIN 4 | 5 | void SweeplineConstraintGraphGenerator::solve() 6 | { 7 | originalSweepLine(); // TCAD-87 8 | } 9 | 10 | 11 | void originalInsert(const CellCoord &cellCoord, SweeplineConstraintGraphGenerator::CellCoordTree &dTree, std::vector &cand) 12 | { 13 | dTree.insert(cellCoord); 14 | cand.at(cellCoord.cellIdx()) = dTree.left(cellCoord); 15 | cand.at(dTree.right(cellCoord)) = cellCoord.cellIdx(); // dTree.right should never be -1. Because R0 is always there 16 | } 17 | 18 | void SweeplineConstraintGraphGenerator::originalDelete(const CellCoord &cellCoord, CellCoordTree &dTree, std::vector &cand, Constraints &cs) 19 | { 20 | auto left = dTree.left(cellCoord); 21 | if (left != -1 && left == cand.at(cellCoord.cellIdx())) 22 | { 23 | IntType from = left; 24 | IntType to = cellCoord.cellIdx(); 25 | IntType weight = 0; //< We actually don't care. In the original algorithm, the weight is the width of the left, and it uses shortest path to compact the layout. 26 | if (!isExempted(from, to)) 27 | { 28 | cs.addConstraintEdge(from, to, weight); 29 | } 30 | } 31 | auto right = dTree.right(cellCoord); 32 | if (cand.at(right) == static_cast(cellCoord.cellIdx())) 33 | { 34 | IntType from = cellCoord.cellIdx(); 35 | IntType to = right; 36 | IntType weight = 0; 37 | if (!isExempted(from, to)) 38 | { 39 | cs.addConstraintEdge(from, to, weight); 40 | } 41 | } 42 | dTree.erase(cellCoord); 43 | } 44 | 45 | /// @brief generate the constraint edges with TCAD-1987 compact ver. 1 46 | /// @param first: the constraints to save results in 47 | /// @param second: the sorted events 48 | /// @param third: the recorded cell coordinates 49 | void SweeplineConstraintGraphGenerator::originalConstraintGeneration(Constraints &cs, std::vector &events, std::vector &cellCoords) 50 | { 51 | SweeplineConstraintGraphGenerator::CellCoordTree dTree; 52 | IndexType numCells = cellCoords.size(); 53 | std::vector cand(numCells + 2, -1); 54 | // Insert R0 55 | dTree.insert(CellCoord(numCells + 1, LOC_TYPE_MAX)); // R0 is behaving as the target node in the DAG. which in convention is numCells + 1. 56 | for (const auto &event : events) 57 | { 58 | if (event.isLow()) 59 | { 60 | originalInsert(cellCoords.at(event.cellIdx()), dTree, cand); 61 | } 62 | else 63 | { 64 | originalDelete(cellCoords.at(event.cellIdx()), dTree, cand, cs); 65 | } 66 | } 67 | } 68 | 69 | void SweeplineConstraintGraphGenerator::recordCellCoords(std::vector &cellCoords, bool isHor) 70 | { 71 | cellCoords.clear(); 72 | for (IndexType cellIdx = 0; cellIdx < _db.numCells(); ++cellIdx) 73 | { 74 | const auto &cell = _db.cell(cellIdx); 75 | if (isHor) 76 | { 77 | cellCoords.emplace_back(CellCoord(cellIdx, cell.xLo())); 78 | } 79 | else 80 | { 81 | cellCoords.emplace_back(CellCoord(cellIdx, cell.yLo())); 82 | } 83 | } 84 | } 85 | 86 | void SweeplineConstraintGraphGenerator::generateEvents(std::vector &events, bool isHor) 87 | { 88 | events.clear(); 89 | for (IndexType cellIdx = 0; cellIdx < _db.numCells(); ++cellIdx) 90 | { 91 | const auto &cell = _db.cell(cellIdx); 92 | if (isHor) 93 | { 94 | events.emplace_back(Event(cellIdx, cell.yLo(), true)); 95 | events.emplace_back(Event(cellIdx, cell.yHi(), false)); 96 | } 97 | else 98 | { 99 | events.emplace_back(Event(cellIdx, cell.xLo(), true)); 100 | events.emplace_back(Event(cellIdx, cell.xHi(), false)); 101 | } 102 | } 103 | std::sort(events.begin(), events.end()); 104 | } 105 | 106 | void addEdgesFromSource(Constraints &cs, IndexType numCells) 107 | { 108 | std::vector hasIngoingEdges(numCells + 2, false); 109 | for (const auto &edge : cs.edges()) 110 | { 111 | IndexType to = edge.target(); 112 | hasIngoingEdges.at(to) = true; 113 | } 114 | IndexType sourceIdx = numCells; 115 | for (IndexType idx = 0; idx < numCells; ++idx) 116 | { 117 | if (!hasIngoingEdges.at(idx)) 118 | { 119 | IntType from = sourceIdx; 120 | IntType to = idx; 121 | IntType weight = 0; // Don't care 122 | cs.addConstraintEdge(from, to, weight); 123 | } 124 | } 125 | } 126 | 127 | void SweeplineConstraintGraphGenerator::originalSweepLine() 128 | { 129 | std::vector events; 130 | std::vector cellCoords; 131 | // First finding horizontal edges 132 | generateEvents(events, true); 133 | recordCellCoords(cellCoords, true); 134 | originalConstraintGeneration(_hC, events, cellCoords); 135 | addEdgesFromSource(_hC, cellCoords.size()); 136 | // Vertical 137 | generateEvents(events, false); 138 | recordCellCoords(cellCoords, false); 139 | originalConstraintGeneration(_vC, events, cellCoords); 140 | addEdgesFromSource(_vC, cellCoords.size()); 141 | } 142 | 143 | PROJECT_NAMESPACE_END 144 | -------------------------------------------------------------------------------- /src/db/Constraints.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Constraints.h 3 | * @brief The placement database data structure 4 | * @author Keren Zhu 5 | * @date 10/02/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_DATABASE_CONSTRAINTS_H_ 9 | #define IDEAPLACE_DATABASE_CONSTRAINTS_H_ 10 | 11 | #include "global/global.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | /// @brief the data structures for symmetric pairs 16 | class SymPair 17 | { 18 | public: 19 | /// @brief default constructor 20 | explicit SymPair() = default; 21 | /// @brief constructor 22 | /// @param one cell index 23 | /// @param another cell index 24 | explicit SymPair(IndexType cellIdx1, IndexType cellIdx2) { this->setCellIdx(cellIdx1, cellIdx2); } 25 | /// @brief set the cell indices. The order stored is always left is lower in index 26 | /// @param one cell index 27 | /// @param another cell index 28 | void setCellIdx(IndexType cellIdx1, IndexType cellIdx2) 29 | { 30 | if (cellIdx1 < cellIdx2) 31 | { 32 | _firstCell = cellIdx1; 33 | _secondCell = cellIdx2; 34 | } 35 | else 36 | { 37 | _secondCell = cellIdx1; 38 | _firstCell = cellIdx2; 39 | } 40 | } 41 | /// @brief get the first cell index 42 | /// @return the first cell index 43 | IndexType firstCell() const { Assert(_firstCell != INDEX_TYPE_MAX); return _firstCell; } 44 | /// @brief get the second cell index 45 | /// @return the second cell index 46 | IndexType secondCell() const { Assert(_secondCell != INDEX_TYPE_MAX); return _secondCell; } 47 | private: 48 | IndexType _firstCell = INDEX_TYPE_MAX; ///< The first cell 49 | IndexType _secondCell = INDEX_TYPE_MAX; ///< The second cell 50 | }; 51 | 52 | /// @brief the data structure for the symmetric group 53 | class SymGroup 54 | { 55 | public: 56 | /// @brief default constructor 57 | explicit SymGroup() = default; 58 | /// @brief add self symmetric cell 59 | /// @param cell index 60 | void addSelfSym(IndexType cellIdx) { _selfSyms.emplace_back(cellIdx); } 61 | /// @brief get the number of self symmetric cells 62 | /// @return the number of self symmetric cells in this group 63 | IndexType numSelfSyms() const { return _selfSyms.size(); } 64 | /// @brief get one cell index of the self symmetric constraint in this group 65 | /// @param the index of self symmetric constraint in this group 66 | /// @return a cell index 67 | IndexType selfSym(IndexType idx) const { return _selfSyms.at(idx); } 68 | /// @brief add symmetric pair. The parameters order does not matter 69 | /// @param one cell index 70 | /// @param another cell index 71 | void addSymPair(IndexType cellIdx1, IndexType cellIdx2) { _symPairs.emplace_back(SymPair(cellIdx1, cellIdx2)); } 72 | /// @brief get the number of symmetric pairs in this group 73 | /// @return the number of symmetric pairs in this group 74 | IndexType numSymPairs() const { return _symPairs.size(); } 75 | /// @brief get a symmetric pair in this group 76 | /// @param the index of the pair in this group 77 | /// @return a symmetric pair 78 | const SymPair & symPair(IndexType idx) const { return _symPairs.at(idx); } 79 | IndexType numConstraints() const { return numSelfSyms() + numSymPairs(); } 80 | const std::vector & vSymPairs() const { return _symPairs; } 81 | const std::vector & vSelfSyms() const { return _selfSyms; } 82 | private: 83 | std::vector _symPairs; ///< The symmetric pairs 84 | std::vector _selfSyms; ///< The self symmetric cells 85 | }; 86 | 87 | /// @brief simple proximity 88 | class ProximityGroup 89 | { 90 | public: 91 | /// @brief default constructor 92 | explicit ProximityGroup() = default; 93 | /// @brief add a cell to this proximity group 94 | /// @param the cell index 95 | void addCell(IndexType cellIdx) { _cells.emplace_back(cellIdx); } 96 | /// @brief set the weight of the proximity group 97 | /// @param the weight of this proximity group 98 | void setWeight(IntType weight) { _weight = weight; } 99 | /// @brief get the vector of the cell indices 100 | /// @return get the vector of the cell indices 101 | const std::vector &cells() const { return _cells; } 102 | 103 | private: 104 | std::vector _cells; ///< The cells belonging to this proximity group 105 | IntType _weight; ///< The weight of this proximity group 106 | }; 107 | 108 | /// @brief the signal/current path 109 | class SignalPath 110 | { 111 | public: 112 | /// @brief default constructor 113 | explicit SignalPath() = default; 114 | const std::vector & vPinIdxArray() const { return _pinIdxArray; } 115 | std::vector & vPinIdxArray() { return _pinIdxArray; } 116 | void addPinIdx(IndexType pinIdx) { _pinIdxArray.emplace_back(pinIdx); } 117 | void markAsPower() { _isPower = true; } 118 | BoolType isPower() const { return _isPower; } 119 | /// @brief copy the settings of another SigalPath 120 | void copySettings(const SignalPath & other) 121 | { 122 | this->_isPower = other._isPower; 123 | } 124 | private: 125 | std::vector _pinIdxArray; ///< The indices of pins composing the path 126 | BoolType _isPower = false; 127 | }; 128 | 129 | PROJECT_NAMESPACE_END 130 | 131 | #endif //IDEAPLACE_DBASE_CONSTRAINTS_H.at( 132 | -------------------------------------------------------------------------------- /src/util/XY.h: -------------------------------------------------------------------------------- 1 | #ifndef __XY_H__ 2 | #define __XY_H__ 3 | 4 | #include "global/namespace.h" 5 | #include "BasicTypeSelection.h" 6 | #include "MsgPrinter.h" 7 | #include 8 | #include 9 | 10 | PROJECT_NAMESPACE_BEGIN 11 | 12 | /// enum type for position of segments versus points 13 | enum class PtPosType : std::uint8_t 14 | { 15 | NORTH = 0, 16 | SOUTH = 1, 17 | WEST = 2, 18 | EAST = 3, 19 | TOP = 4, 20 | BOTTOM = 5, 21 | NOT_NEIGHBOR = 6 22 | }; 23 | 24 | template 25 | class XY 26 | { 27 | typedef boost::geometry::model::point boostPointType; 28 | public: 29 | 30 | template 31 | friend XY::type> operator*(U lhs, const XY &rhs) { return XY::type>(lhs * rhs.x(), lhs * rhs.y()); } 32 | 33 | template 34 | friend XY::type> operator*(const XY &lhs, U rhs) { return XY::type>(lhs.x() * rhs, lhs.y() * rhs); } 35 | 36 | template 37 | friend XY::type> operator/(const XY &lhs, U rhs) { return XY::type>(lhs.x() / rhs, lhs.y() / rhs); } 38 | 39 | public: 40 | explicit XY() = default; 41 | explicit XY(T x, T y) : _x(x), _y(y) {} 42 | //explicit XY(T x, T y, T z) : _x(x), _y(y) {MsgPrinter::wrn("%s, ignore z for XY(x,y,z) \n", __PRETTY_FUNCTION__);} 43 | 44 | template 45 | explicit XY(const XY &other) : _x((T)other.x()), _y((T)other.y()) {} 46 | 47 | // Getters 48 | T x() const { return _x; } 49 | T y() const { return _y; } 50 | XY left() const { return XY(_x - 1, _y); } 51 | XY right() const { return XY(_x + 1, _y); } 52 | XY bottom() const { return XY(_x, _y - 1); } 53 | XY top() const { return XY(_x, _y + 1); } 54 | 55 | // Setters 56 | void setX(T x) { _x = x; } 57 | void setY(T y) { _y = y; } 58 | void setXY(T x, T y) { _x = x; _y = y; } 59 | 60 | bool operator==(const XY &rhs) const { return _x == rhs.x() && _y == rhs.y(); } 61 | bool operator!=(const XY &rhs) const { return ! (*this == rhs); } 62 | bool operator<(const XY &rhs) const { return _y == rhs.y() ? _x < rhs.x() : _y < rhs.y(); } 63 | 64 | template 65 | XY::type> operator+(const XY &rhs) const { return XY::type>(_x + rhs.x(), _y + rhs.y()); } 66 | 67 | template 68 | XY::type> operator-(const XY &rhs) const { return XY::type>(_x - rhs.x(), _y - rhs.y()); } 69 | 70 | template 71 | XY & operator+=(const XY &rhs) { _x += rhs.x(); _y += rhs.y(); return *this; } 72 | 73 | template 74 | XY & operator-=(const XY &rhs) { _x -= rhs.x(); _y -= rhs.y(); return *this; } 75 | 76 | template 77 | XY & operator*=(U rhs) { _x *= rhs; _y *= rhs; return *this; } 78 | 79 | template 80 | XY & operator/=(U rhs) { _x /= rhs; _y /= rhs; return *this; } 81 | 82 | /// Find the relative position of the rhs TO this 83 | PtPosType ptPos(const XY &rhs) const 84 | { 85 | if (top() == rhs) 86 | { 87 | return PtPosType::NORTH; 88 | } 89 | else if (bottom() == rhs) 90 | { 91 | return PtPosType::SOUTH; 92 | } 93 | else if (right() == rhs) 94 | { 95 | return PtPosType::EAST; 96 | } 97 | else if (left() == rhs) 98 | { 99 | return PtPosType::WEST; 100 | } 101 | else 102 | { 103 | return PtPosType::NOT_NEIGHBOR; 104 | } 105 | } 106 | 107 | boostPointType toBoost() const 108 | { 109 | return boostPointType(_x, _y); 110 | } 111 | void fromBoost(const boostPointType &rtV) 112 | { 113 | T x = boost::geometry::get<0>(rtV); 114 | T y = boost::geometry::get<1>(rtV); 115 | setXY(x,y); 116 | } 117 | 118 | /// Misc. 119 | std::string toStr() const 120 | { 121 | std::ostringstream oss; 122 | oss << " ("<<_x<<","<<_y<<") "; 123 | return oss.str(); 124 | } 125 | private: 126 | T _x = 0; 127 | T _y = 0; 128 | }; 129 | 130 | template 131 | struct XYHashFunc 132 | { 133 | std::size_t operator() (const XY &xy) const 134 | { 135 | std::size_t seed = 0; 136 | boost::hash_combine(seed, xy.x()); 137 | boost::hash_combine(seed, xy.y()); 138 | return seed; 139 | }; 140 | }; 141 | 142 | PROJECT_NAMESPACE_END 143 | 144 | /// Hash function 145 | namespace std 146 | { 147 | template 148 | struct hash > 149 | { 150 | typedef PROJECT_NAMESPACE::XY argumentType; 151 | typedef std::size_t resultType; 152 | resultType operator()(argumentType const& s) const noexcept 153 | { 154 | resultType seed = 0; 155 | boost::hash_combine(seed, s.x()); 156 | boost::hash_combine(seed, s.y()); 157 | return seed; 158 | } 159 | }; 160 | } 161 | 162 | #endif // __XY_H__ 163 | -------------------------------------------------------------------------------- /src/util/XYZ.h: -------------------------------------------------------------------------------- 1 | #ifndef __XYZ_H__ 2 | #define __XYZ_H__ 3 | 4 | #include "global/namespace.h" 5 | #include "MsgPrinter.h" 6 | #include "XY.h" 7 | 8 | PROJECT_NAMESPACE_BEGIN 9 | 10 | 11 | inline PtPosType revertPtPos(PtPosType init) 12 | { 13 | if (init == PtPosType::NORTH) 14 | { 15 | return PtPosType::SOUTH; 16 | } 17 | else if (init == PtPosType::SOUTH) 18 | { 19 | return PtPosType::NORTH; 20 | } 21 | else if (init == PtPosType::WEST) 22 | { 23 | return PtPosType::EAST; 24 | } 25 | else if (init == PtPosType::EAST) 26 | { 27 | return PtPosType::WEST; 28 | } 29 | else if (init == PtPosType::TOP) 30 | { 31 | return PtPosType::BOTTOM; 32 | } 33 | else if (init == PtPosType::BOTTOM) 34 | { 35 | return PtPosType::TOP; 36 | } 37 | return PtPosType::NOT_NEIGHBOR; 38 | } 39 | 40 | 41 | template 42 | class XYZ 43 | { 44 | typedef boost::geometry::model::point boostPointType; 45 | public: 46 | explicit XYZ() = default; 47 | explicit XYZ(XYType x, XYType y, ZType z) : _xy(x, y), _z(z) {} 48 | explicit XYZ(XY xy, ZType z) : _xy(xy), _z(z) {} 49 | explicit XYZ(XYType x, XYType y) :_xy(x,y), _z(0) { MsgPrinter::wrn("%s, filling in 0 as z for XYZ(x,y) \n", __PRETTY_FUNCTION__);} 50 | 51 | /// Getters 52 | XYType x() const { return _xy.x(); } 53 | XYType y() const { return _xy.y(); } 54 | ZType z() const { return _z; } 55 | const XY & xy() const { return _xy; } 56 | XYZ north() const { return XYZ(_xy.x(), _xy.y() + 1, _z); } 57 | XYZ south() const { return XYZ(_xy.x(), _xy.y() - 1, _z); } 58 | XYZ east() const { return XYZ(_xy.x() + 1, _xy.y(), _z); } 59 | XYZ west() const { return XYZ(_xy.x() - 1, _xy.y(), _z); } 60 | XYZ top() const { return XYZ(_xy.x(), _xy.y(), _z + 1); } 61 | XYZ bottom() const { return XYZ(_xy.x(), _xy.y(), _z - 1); } 62 | 63 | /// Setters 64 | void setX(XYType x) { _xy.setX(x); } 65 | void setY(XYType y) { _xy.setY(y); } 66 | void setZ(ZType z) { _z = z; } 67 | void setXY(const XY &xy) { _xy = xy; } 68 | void setXY(XYType x, XYType y) { _xy.setXY(x, y); } 69 | void setXYZ(XYType x, XYType y, ZType z) { _xy.setXY(x, y); _z = z; } 70 | 71 | bool operator==(const XYZ &rhs) const { return _xy == rhs.xy() && _z == rhs.z(); } 72 | bool operator!=(const XYZ &rhs) const { return ! (*this == rhs); } 73 | bool operator<(const XYZ &rhs) const { return _z == rhs.z() ? _xy < rhs.xy() : _z < rhs.z(); } 74 | 75 | 76 | /// Find the relative position of the rhs TO this 77 | PtPosType ptPos(const XYZ &rhs) const 78 | { 79 | if (north() == rhs) 80 | { 81 | return PtPosType::NORTH; 82 | } 83 | else if (south() == rhs) 84 | { 85 | return PtPosType::SOUTH; 86 | } 87 | else if (east() == rhs) 88 | { 89 | return PtPosType::EAST; 90 | } 91 | else if (west() == rhs) 92 | { 93 | return PtPosType::WEST; 94 | } 95 | else if (bottom() == rhs) 96 | { 97 | return PtPosType::BOTTOM; 98 | } 99 | else if (top() == rhs) 100 | { 101 | return PtPosType::TOP; 102 | } 103 | else 104 | { 105 | return PtPosType::NOT_NEIGHBOR; 106 | } 107 | } 108 | 109 | boostPointType toBoost() const 110 | { 111 | return boostPointType(_xy.x(), _xy.y(), _z); 112 | } 113 | 114 | void fromBoost(const boostPointType &rtV) 115 | { 116 | XYType x = boost::geometry::get<0>(rtV); 117 | XYType y = boost::geometry::get<1>(rtV); 118 | ZType z = boost::geometry::get<2>(rtV); 119 | setXYZ(x,y,z); 120 | } 121 | 122 | /// Misc. 123 | std::string toStr() const 124 | { 125 | return std::string(*this); 126 | } 127 | 128 | operator std::string() const 129 | { 130 | std::ostringstream oss; 131 | oss << " ("<<_xy.x()<<","<<_xy.y()<<","<<_z<<") "; 132 | return oss.str(); 133 | } 134 | private: 135 | XY _xy; 136 | ZType _z = 0; 137 | }; 138 | 139 | template 140 | struct XYZHashFunc 141 | { 142 | std::size_t operator() (const XYZ &xyz) const 143 | { 144 | std::size_t seed = 0; 145 | boost::hash_combine(seed, xyz.x()); 146 | boost::hash_combine(seed, xyz.y()); 147 | boost::hash_combine(seed, xyz.z()); 148 | return seed; 149 | }; 150 | }; 151 | 152 | PROJECT_NAMESPACE_END 153 | 154 | 155 | /// Hash function 156 | namespace std 157 | { 158 | template 159 | struct hash > 160 | { 161 | typedef PROJECT_NAMESPACE::XYZ argumentType; 162 | typedef std::size_t resultType; 163 | resultType operator()(argumentType const& s) const noexcept 164 | { 165 | resultType seed = 0; 166 | boost::hash_combine(seed, s.x()); 167 | boost::hash_combine(seed, s.y()); 168 | boost::hash_combine(seed, s.z()); 169 | return seed; 170 | } 171 | }; 172 | template<> 173 | struct hash > 174 | { 175 | typedef PROJECT_NAMESPACE::XYZ argumentType; 176 | typedef std::size_t resultType; 177 | resultType operator()(argumentType const& s) const noexcept 178 | { 179 | resultType seed = 0; 180 | boost::hash_combine(seed, s.x()); 181 | boost::hash_combine(seed, s.y()); 182 | boost::hash_combine(seed, s.z()); 183 | return seed; 184 | } 185 | }; 186 | } 187 | 188 | #endif // __XYZ_H__ 189 | -------------------------------------------------------------------------------- /src/parser/ProgArgs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ProgArgs.h 3 | * @brief Parsing in the program arguments from system arguments 4 | * @author Keren Zhu 5 | * @date 10/04/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_PROGARGS_H_ 9 | #define IDEAPLACE_PROGARGS_H_ 10 | 11 | #include "global/global.h" 12 | #include "util/thirdparty/cmdline.h" 13 | 14 | PROJECT_NAMESPACE_BEGIN 15 | 16 | /// @class IDEAPLACE::CommandLineOptions 17 | /// @brief Class to parse command line options 18 | class CommandLineOptions 19 | { 20 | public: 21 | CommandLineOptions(int argc, char **argv); 22 | 23 | private: 24 | void populateAndCheckOptions(); 25 | 26 | public: 27 | // Options 28 | std::string pinFile = ""; 29 | std::string netwgtFile = ""; 30 | std::string connectionFile = ""; 31 | std::string techsimpleFile = ""; 32 | std::string symFile = ""; 33 | std::string symnetFile = ""; 34 | std::string sigpathFile = ""; 35 | std::string log = ""; 36 | std::vector gdsFiles; 37 | 38 | private: 39 | cmdline::parser _parser; 40 | }; 41 | 42 | /// @class IDEAPLACE::ProgArgs 43 | /// @brief The program arguments 44 | class ProgArgs 45 | { 46 | public: 47 | /// @brief default constructor 48 | explicit ProgArgs() = default; 49 | /*------------------------------ */ 50 | /* Getters */ 51 | /*------------------------------ */ 52 | /// @brief get the .pin file file name 53 | /// @return the .pin file file name 54 | const std::string pinFile() const { Assert(this->pinFileIsSet()); return _pinFile; } 55 | /// @brief determine whether the .pin file is set 56 | /// @return whether .pin file is set 57 | bool pinFileIsSet() const { return _pinFile != ""; } 58 | /// @brief get the .netwgt file file name 59 | /// @return the .netwgt file file name 60 | const std::string netwgtFile() const { Assert(this->netwgtFileIsSet()); return _netwgtFile; } 61 | /// @brief determine whether the .netwgt file is set 62 | /// @return whether .netwgt file is set 63 | bool netwgtFileIsSet() const { return _netwgtFile != ""; } 64 | /// @brief get the .connection file file name 65 | /// @return the .connection file file name 66 | const std::string connectionFile() const { Assert(this->connectionFileIsSet()); return _connectionFile; } 67 | /// @brief determine whether the .connection file is set 68 | /// @return whether .connection file is set 69 | bool connectionFileIsSet() const { return _connectionFile != ""; } 70 | /// @brief get the .connection file file name 71 | /// @return the .connection file file name 72 | const std::string symFile() const { Assert(this->symFileIsSet()); return _symFile; } 73 | /// @brief determine whether the .sym file is set 74 | /// @return whether .sym file is set 75 | bool symFileIsSet() const { return _symFile != ""; } 76 | /// @brief get the .symnet file 77 | /// @return the .symnet file 78 | const std::string symnetFile() const { Assert(this->symnetFileIsSet()); return _symnetFile; } 79 | /// @brief determine whether the .symnet file is set 80 | /// @return whether .symnet file is set 81 | bool symnetFileIsSet() const { return _symnetFile != ""; } 82 | /// @brief get the .sigpath file 83 | /// @return the .sigpath file 84 | const std::string sigpathFile() const { Assert(this->sigpathFileIsSet()); return _sigpathFile; } 85 | /// @brief determine whether the .sigpath file is set 86 | /// @return whether .sigpath file is set 87 | bool sigpathFileIsSet() const { return _sigpathFile != ""; } 88 | /// @brief get the techsimple file file name 89 | /// @return the techsimple file file name 90 | const std::string techsimpleFile() const { Assert(this->techsimpleFileIsSet()); return _techsimpleFile; } 91 | /// @brief determine whether the techsimple file is set 92 | /// @return whether techsimple file is set 93 | bool techsimpleFileIsSet() const { return _techsimpleFile != ""; } 94 | /// @brief get the gds files given from the arguments 95 | /// @return the gds files 96 | const std::vector & gdsFiles() const { return _gdsFiles; } 97 | /// @brief get the gds files given from the arguments 98 | /// @return the gds files 99 | std::vector & gdsFiles() { return _gdsFiles; } 100 | /*------------------------------ */ 101 | /* Setters */ 102 | /*------------------------------ */ 103 | /// @brief set the .pin file 104 | /// @param the .pin file file name 105 | void setPinFile(const std::string &pinFile) { _pinFile = pinFile; } 106 | /// @brief set the .sym file 107 | /// @param the .sym file file name 108 | void setSymFile(const std::string &symFile) { _symFile = symFile; } 109 | /// @brief set the .netwgt file 110 | /// @param the .netwgt file file name 111 | void setNetwgtFile(const std::string &netwgtFile) { _netwgtFile = netwgtFile; } 112 | /// @brief set the .connection file 113 | /// @param the .connection file file name 114 | void setConnectionFile(const std::string &connectionFile) { _connectionFile = connectionFile; } 115 | /// @brief set the techsimple file 116 | /// @param the techsimple file file name 117 | void setTechsimpleFile(const std::string &techsimpleFile) { _techsimpleFile = techsimpleFile; } 118 | /// @brief set the symnet file 119 | /// @param the symnet file file name 120 | void setSymnetFile(const std::string &symnetFile) { _symnetFile = symnetFile; } 121 | /// @brief set the sigpath file 122 | /// @param the sigpath file file name 123 | void setSigpathFile(const std::string &sigpathFile) { _sigpathFile = sigpathFile; } 124 | private: 125 | std::string _pinFile = ""; ///< .pin file 126 | std::string _netwgtFile = ""; ///< .netwgt file 127 | std::string _connectionFile = ""; ///< .connection file 128 | std::string _techsimpleFile = ""; ///< The techfile simple file 129 | std::string _symFile = ""; ///< The .sym file 130 | std::string _symnetFile = ""; ///< The .symnet file 131 | std::string _sigpathFile = ""; ///< The .sigpath file 132 | std::vector _gdsFiles; ///< The gds files for read 133 | }; 134 | 135 | namespace ProgArgsDetails 136 | { 137 | /// @brief Parse in arguments to the program (cmdline version) 138 | /// @param program arguments 139 | /// @return ProgArgs class with parsed arguments 140 | ProgArgs parseProgArgsCMD(IntType argc, char** argv); 141 | } 142 | PROJECT_NAMESPACE_END 143 | 144 | #endif ///IDEAPLACE_PROGARGS_H_ 145 | -------------------------------------------------------------------------------- /src/util/Vector2D.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Keren on 04/17/2018 3 | // 4 | 5 | #ifndef ZKUTIL_VECTOR2D_H_ 6 | #define ZKUTIL_VECTOR2D_H_ 7 | 8 | #include 9 | #include 10 | #include "global/namespace.h" 11 | #include "global/type.h" 12 | #include "global/define.h" 13 | #include "XY.h" 14 | 15 | PROJECT_NAMESPACE_BEGIN 16 | 17 | /// ================================================================================ 18 | /// Vector map class 19 | /// A templete for 2D vector using flat vector 20 | /// This is a Y-dominate implementation, that is elements in the 21 | /// same column (with the same Y) are in a piece of consecutive memory. 22 | /// Thus, when iterate through this 2D vector using a two-level for loop, 23 | /// the following pattern is better from the memory/cache hit prespective 24 | /// for (x ...) 25 | /// { 26 | /// for (y ....) 27 | /// { 28 | /// .... 29 | /// } 30 | /// } 31 | /// 32 | /// Update: 10/26/2018 add option to yMajor 33 | /// ================================================================================ 34 | template 35 | class Vector2D 36 | { 37 | public: 38 | /// Class for initializer_list type 39 | enum class InitListType : Byte 40 | { 41 | XMajor, 42 | yMajor 43 | }; 44 | 45 | public: 46 | explicit Vector2D() = default; 47 | explicit Vector2D(IndexType xSize, IndexType ySize) : _vec(xSize * ySize), _xSize(xSize), _ySize(ySize) {} 48 | explicit Vector2D(IndexType xSize, IndexType ySize, const T &v) : _vec(xSize * ySize, v), _xSize(xSize), _ySize(ySize) {} 49 | explicit Vector2D(IndexType xSize, IndexType ySize, InitListType t, std::initializer_list l); 50 | 51 | void clear() { _vec.clear(); _xSize = _ySize = 0; } 52 | void resize(IndexType xSize, IndexType ySize) { _vec.resize(xSize * ySize); _xSize = xSize; _ySize = ySize; } 53 | void resize(IndexType xSize, IndexType ySize, const T &v) { _vec.resize(xSize * ySize, v); _xSize = xSize; _ySize = ySize; } 54 | void setType(InitListType type) { _type = type; } 55 | 56 | IndexType xSize() const { return _xSize; } 57 | IndexType ySize() const { return _ySize; } 58 | IndexType size() const { return _vec.size(); } 59 | InitListType type() const { return _type; } 60 | 61 | const T & at(IndexType x, IndexType y) const { return this->atIdx(xyToIndex(x, y)); } 62 | T & at(IndexType x, IndexType y) { return this->atIdx(xyToIndex(x, y)); } 63 | const T & at(XY xy) const { return this->at(xyToIndex(xy)); } 64 | T & at(XY xy) { return this->at(xyToIndex(xy)); } 65 | const T & atIdx(IndexType idx) const { return _vec.at(idx); } 66 | T & atIdx(IndexType idx) { return _vec.at(idx); } 67 | 68 | /// Iterator 69 | typename std::vector::iterator begin() { return _vec.begin(); } 70 | typename std::vector::const_iterator begin() const { return _vec.begin(); } 71 | typename std::vector::iterator end() { return _vec.end(); } 72 | typename std::vector::const_iterator end() const { return _vec.end(); } 73 | 74 | /// Conversion 75 | IndexType xyToIndex(IndexType x, IndexType y) const; 76 | IndexType xyToIndex(XY xy) const { return xyToIndex(xy.x(), xy.y()); } 77 | IndexType idxToX(IndexType idx) const; 78 | IndexType idxToY(IndexType idx) const; 79 | XY idxToXY(IndexType idx) const { return XY(idxToX(idx), idxToY(idx)); } 80 | 81 | private: 82 | std::vector _vec; 83 | IndexType _xSize = 0; 84 | IndexType _ySize = 0; 85 | InitListType _type = InitListType::XMajor; 86 | }; 87 | 88 | template 89 | inline IndexType Vector2D::xyToIndex(IndexType x, IndexType y) const 90 | { 91 | if (_type == InitListType::XMajor) 92 | { 93 | return _ySize * x + y; 94 | } 95 | else 96 | { 97 | /// Y major 98 | return _xSize *y + x; 99 | } 100 | } 101 | 102 | template 103 | inline IndexType Vector2D::idxToX(IndexType idx) const 104 | { 105 | if (_type == InitListType::XMajor) 106 | { 107 | return idx / _ySize; 108 | } 109 | else 110 | { 111 | return idx % _xSize; 112 | } 113 | } 114 | 115 | template 116 | inline IndexType Vector2D::idxToY(IndexType idx) const 117 | { 118 | if (_type == InitListType::XMajor) 119 | { 120 | return idx % _ySize; 121 | } 122 | else 123 | { 124 | return idx / _xSize; 125 | } 126 | } 127 | /// Ctor using initializer_list 128 | template 129 | inline Vector2D::Vector2D(IndexType xSize, IndexType ySize, InitListType t, std::initializer_list l) 130 | : _vec(xSize * ySize), _xSize(xSize), _ySize(ySize) 131 | { 132 | Assert(l.size == size()); 133 | if (t == InitListType::XMajor) 134 | { 135 | /// Data in Vector2D is in X-major manner 136 | /// Just copy the initializer_list to the _vec 137 | std::copy(l.begin, l.end(), _vec.begin()); 138 | } 139 | else 140 | { // t == InitiListType::YMajor 141 | for (IndexType idx = 0; idx < size(); ++idx) 142 | { 143 | IndexType x = idx % _xSize; 144 | IndexType y = idx / _xSize; 145 | at(x, y) = *(l.begin() + idx); 146 | } 147 | } 148 | } 149 | 150 | PROJECT_NAMESPACE_END 151 | 152 | #endif //ZKUTIL_VECTOR2D_H_ 153 | -------------------------------------------------------------------------------- /src/db/Net.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Net.h 3 | * @brief The placement net data structure 4 | * @author Keren Zhu 5 | * @date 09/30/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_NET_H_ 9 | #define IDEAPLACE_NET_H_ 10 | 11 | #include "global/global.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | 16 | class VirtualPin 17 | { 18 | public: 19 | VirtualPin() = default; 20 | VirtualPin(const XY &loc) : _loc(loc) {} 21 | const XY & loc() const { return _loc; } 22 | XY & loc() { return _loc; } 23 | LocType x() const { return _loc.x(); } 24 | LocType y() const { return _loc.y(); } 25 | IndexType netIdx() const { return _netIdx; } 26 | bool assigned() const { return _netIdx != INDEX_TYPE_MAX; } 27 | void free() { _netIdx = INDEX_TYPE_MAX; } 28 | void assign(IndexType netIdx) { _netIdx = netIdx; } 29 | void setDirection(Direction2DType dir) { _dir = dir; } 30 | Direction2DType direction() const { return _dir; } 31 | 32 | bool operator<(const VirtualPin &pin) const 33 | { 34 | return _loc < pin._loc; 35 | } 36 | std::string toStr() const 37 | { 38 | std::stringstream ss; 39 | ss << _loc.toStr() <<" net: " << _netIdx; 40 | return ss.str(); 41 | } 42 | private: 43 | XY _loc; 44 | IndexType _netIdx = INDEX_TYPE_MAX; 45 | Direction2DType _dir; ///< The location on the placement boundary 46 | }; 47 | /// @class IDEAPLACE::Net 48 | /// @brief the net class 49 | class Net 50 | { 51 | public: 52 | /// @brief default constructor 53 | explicit Net() = default; 54 | /*------------------------------*/ 55 | /* Getters */ 56 | /*------------------------------*/ 57 | /// @brief get the weight of the net 58 | /// @return the weight of this net 59 | IntType weight() const { return _weight; } 60 | /// @brief get the name for the net 61 | /// @return the name of this net 62 | const std::string & name() const { return _name; } 63 | /// @brief get whether this pin is an IO pin 64 | bool isIo() const { return _isIo; } 65 | /// @brief get the virtual pin location 66 | /// @return the location for the virtual pin 67 | const XY &virtualPinLoc() const { return _virtualPin.loc(); } 68 | /// @brief get whether need to consider the virtual pin: If not IO net, or if no vitual pin assigned 69 | bool isValidVirtualPin() const { return (_isIo or _isVdd or _isVss) && _virtualPin.assigned(); } 70 | /// @brief get whether this net is a dummy net 71 | /// @return whether this net is a dummy net 72 | bool isDummyNet() const { return _isDummy; } 73 | /// @brief get whether the io pin is on top or bottom 74 | /// @return true: top or bottom 75 | /// @return false: left or right 76 | bool iopinVertical() const { return _virtualPin.direction() == Direction2DType::NORTH or _virtualPin.direction() == Direction2DType::SOUTH; } 77 | /// @brief the net index that is sym pair of this one 78 | /// @return the net index that is sym pair of this one 79 | IndexType symNetIdx() const { return _symNetIdx; } 80 | /// @brief get whether this net is self-symmetric 81 | /// @return whether this net is self-symmetric 82 | bool isSelfSym() const { return _isSelfSym; } 83 | /// @brief get whether this net has symmetric net 84 | bool hasSymNet() const { return _symNetIdx != INDEX_TYPE_MAX; } 85 | /// @brief get whether this net is vdd 86 | bool isVdd() const { return _isVdd; } 87 | /// @brief get whether this net is vss 88 | bool isVss() const { return _isVss; } 89 | /// @brief whether this should be on the left of the symnet pair 90 | bool isLeftSym() const { return _isLeftSym; } 91 | /*------------------------------*/ 92 | /* Setters */ 93 | /*------------------------------*/ 94 | /// @brief set the weight of the net 95 | /// @param the weight of the net 96 | void setWeight(IntType weight) { _weight = weight; } 97 | /// @brief set the name of the net 98 | /// @param the name of the net 99 | void setName(const std::string &name) { _name = name; } 100 | /// @brief set whether this net is an IO net 101 | void setIsIo(bool isIo) { _isIo =isIo; } 102 | /// @brief set the virtual pin location of this net 103 | void setVirtualPin(const VirtualPin &virtualPinLocation) { _virtualPin = virtualPinLocation; } 104 | /// @brief invalidate the virtual pin 105 | void invalidateVirtualPin() { _virtualPin.free(); } 106 | /// @brief mark this net as a dummy net 107 | void markAsDummyNet() { _isDummy = true; } 108 | /// @brief set the symmetric pair net index of this one 109 | /// @param the net index that this one should be symmetric to 110 | void setSymNet(IndexType symNet, bool isLeftSym) { _symNetIdx = symNet; _isLeftSym = isLeftSym; } 111 | /// @brief mark this net as self symmetric 112 | void markSelfSym() { _isSelfSym = true; } 113 | /// @brief revoke the mark of this net is self symmetric 114 | void revokeSelfSym() { _isSelfSym = false; } 115 | /// @brief mark this net as vdd 116 | void markAsVdd() { _isVdd = true; _isVss = false; _isIo = false; } 117 | /// @brief mark this net as vss 118 | void markAsVss() { DBG("mark net %s as vss \n", _name.c_str()); _isVss = true; _isVdd = false; _isIo = false; } 119 | /*------------------------------*/ 120 | /* Vector operations */ 121 | /*------------------------------*/ 122 | /// @brief get the number of pins 123 | /// @return the number of pins this cell has 124 | IndexType numPinIdx() const { return _pinIdxArray.size(); } 125 | /// @brief add one pin to the cell 126 | /// @param the index of pin that want to be added 127 | void addPin(IndexType pinIdx) { _pinIdxArray.emplace_back(pinIdx); } 128 | /// @brief get the database pin index 129 | /// @param the index of pin array 130 | /// @return the databse pin index 131 | IndexType pinIdx(IndexType idx) const { return _pinIdxArray.at(idx); } 132 | const std::vector & pinIdxArray() const { return _pinIdxArray; } 133 | private: 134 | std::string _name = ""; ///< The name for the net 135 | std::vector _pinIdxArray; ///< The index to the pins belonging to the net 136 | IntType _weight = 1; ///< The weight of this net 137 | bool _isIo = false; ///< Whether thisnet is an IO net 138 | VirtualPin _virtualPin; ///< The virtual pin location 139 | bool _isDummy = false; ///< Whether this is a dummy net 140 | IndexType _symNetIdx = INDEX_TYPE_MAX; ///< The symmetric pair of this net. If INDEX_TYPE_MAX, it does not have a sym pair 141 | bool _isLeftSym = true; ///< Whethet this should be on the left in sym net pair 142 | bool _isSelfSym = false; ///< Whether this net is self-symmetric 143 | bool _isVdd = false; ///< whether this net is vdd 144 | bool _isVss = false; ///< Whether this net is vss 145 | }; 146 | 147 | PROJECT_NAMESPACE_END 148 | 149 | #endif /// IDEAPLACE_NET_H_ 150 | -------------------------------------------------------------------------------- /src/parser/ParserGds.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ParserGds.h 3 | * @brief Parser for cell gds files 4 | * @author Keren Zhu 5 | * @date 10/15/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_PARSER_GDS_H_ 9 | #define IDEAPLACE_PARSER_GDS_H_ 10 | 11 | #include "db/Database.h" 12 | #include "util/GdsHelper.h" 13 | 14 | PROJECT_NAMESPACE_BEGIN 15 | 16 | /// @class IDEAPLACE::ParserCellGds 17 | /// @brief Parser for gds file. Each time reading in a gds for a cell 18 | class ParserCellGds 19 | { 20 | public: 21 | 22 | /// @briVVef struct for polygon with layer 23 | struct PolygonLayer 24 | { 25 | public: 26 | explicit PolygonLayer() = default; 27 | std::string toStr() const 28 | { 29 | std::stringstream oss; 30 | oss<<"Layer "<(x * scaleX); 45 | LocType newY = ::klib::autoRound(y * scaleY); 46 | 47 | pts.at(ptIdx).setX(newX); 48 | pts.at(ptIdx).setY(newY); 49 | } 50 | } 51 | 52 | ///Members 53 | std::vector> pts; ///< The points of the polygon 54 | IndexType layer = INDEX_TYPE_MAX; ///< The layer of the polygon 55 | }; 56 | 57 | public: 58 | /// @brief constructor 59 | /// @param the reference to the placement database 60 | explicit ParserCellGds(Database &db) : _db(db) {} 61 | /// @brief parsing in a gds file 62 | /// @param first: the gds file name 63 | /// @param second: the cell index. If given INDEX_TYPE_MAX or ungiven, search the cell by name 64 | /// @return if the parsing is successful 65 | bool parseCellGds(const std::string &filename, IndexType cellIdx = INDEX_TYPE_MAX); 66 | /// @brief scale the design based on the router precision 67 | void scaleDesign(); 68 | /// @brief dump the read gds shapes to the database 69 | /// @param the cell index 70 | void dumpToDb(IndexType cellIdx); 71 | private: 72 | Database &_db; ///< The database for the placement engine 73 | IntType _gdsDBU; ///< Based on the gds, x database units per um 74 | std::vector _polygons; ///< The polygons read from the gds 75 | }; 76 | 77 | namespace ParserCellGdsDetails 78 | { 79 | /// @brief parsing all the gds files 80 | /// @param first: the placement database 81 | /// @param second: a vector of gds file names 82 | /// @return if successful 83 | inline bool parseAllGdsFiles(Database &db, const std::vector &gdsFiles) 84 | { 85 | for (const auto &gds : gdsFiles) 86 | { 87 | if (!ParserCellGds(db).parseCellGds(gds)) 88 | { 89 | ERR("%s: parse %s failed! \n", __FUNCTION__, gds.c_str()); 90 | return false; 91 | } 92 | } 93 | return true; 94 | } 95 | } 96 | 97 | 98 | /// @brief detailed struct for the functions of processing gds shapes 99 | namespace ExtractShapeLayerActionDetails 100 | { 101 | namespace gtl = boost::polygon; 102 | /// @brief convert from gds layer to router layer 103 | /// @return INDEX_TYPE_MAX if not found, otherwise, the router layer 104 | inline IndexType layerIdx(IntType gdsLayer, std::unordered_map &map) 105 | { 106 | /// Search in the map 107 | const auto findIter = map.find(static_cast(gdsLayer)); 108 | if (findIter != map.end()) 109 | { 110 | return findIter->second; 111 | } 112 | return INDEX_TYPE_MAX; 113 | } 114 | /// @brief default action 115 | template 116 | inline void extractShape(std::unordered_map &map, std::vector &polygons, ::GdsParser::GdsRecords::EnumType type, ObjectType *object) 117 | { 118 | } 119 | 120 | 121 | /// @brief process gds rectangle 122 | template<> 123 | inline void extractShape(std::unordered_map &map, std::vector &polygons, ::GdsParser::GdsRecords::EnumType type, ::GdsParser::GdsDB::GdsRectangle *object) 124 | { 125 | DBG("Rect \n"); 126 | AssertMsg(0, "%s: Rectangle type not support yet \n", __FUNCTION__); 127 | //DBG("Gds rectangle layer %d, (%d, %d ), (%d, %d) \n", object->layer(), gtl::xl(object), gtl::yl(object), gtl::xh(object), gtl::yh(object)); 128 | } 129 | 130 | /// @brief process gds polygon 131 | template<> 132 | inline void extractShape(std::unordered_map &map, std::vector &polygons, ::GdsParser::GdsRecords::EnumType type, ::GdsParser::GdsDB::GdsPolygon *object) 133 | { 134 | /// Convert the gds layer to the router layer 135 | IndexType routerLayer = layerIdx(object->layer(), map); 136 | if (routerLayer != INDEX_TYPE_MAX) 137 | { 138 | polygons.emplace_back(ParserCellGds::PolygonLayer()); 139 | polygons.back().layer = routerLayer; 140 | /// Add points 141 | for (auto pt : *object) 142 | { 143 | polygons.back().pts.emplace_back(XY(pt.x(), pt.y())); 144 | } 145 | } 146 | } 147 | 148 | /// @brief process path 149 | template<> 150 | inline void extractShape(std::unordered_map &map, std::vector &polygons, ::GdsParser::GdsRecords::EnumType type, ::GdsParser::GdsDB::GdsPath *object) 151 | { 152 | auto polygon = object->toPolygon(); 153 | extractShape(map, polygons, type, &polygon); 154 | } 155 | 156 | } 157 | 158 | 159 | /// @brief aution function object to process the the 160 | struct ExtractShapeLayerAction 161 | { 162 | /// @param first: the map between the gds layer indices to the router layers. Only care about the mapping within this map 163 | /// @param second: a reference to a vector of polygons, saved the read polygons in this vector 164 | ExtractShapeLayerAction(std::unordered_map &map, std::vector &polygons) : _layerIdxMap(map), _polygons(polygons) {} 165 | template 166 | void operator()(::GdsParser::GdsRecords::EnumType type, ObjectType* object) 167 | { 168 | ExtractShapeLayerActionDetails::extractShape(_layerIdxMap, _polygons, type, object); 169 | } 170 | 171 | /// @return a message of action for debug 172 | std::string message() const 173 | { 174 | return "ExtractShapeLayerAction"; 175 | } 176 | 177 | std::unordered_map & _layerIdxMap; ///< A map from gds layer to IDEAPLACE layer. _layerIdxMap[ 178 | std::vector &_polygons; ///< The polygons read from the gds 179 | }; 180 | 181 | PROJECT_NAMESPACE_END 182 | 183 | #endif ///IDEAPLACE_PARSER_GDS_H_ 184 | -------------------------------------------------------------------------------- /src/db/Tech.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Tech.h 3 | * @brief The placement technology-related data structure 4 | * @author Keren Zhu 5 | * @date 09/30/2019 6 | */ 7 | 8 | #ifndef IDEAPLACE_TECH_H_ 9 | #define IDEAPLACE_TECH_H_ 10 | 11 | #include 12 | #include "global/global.h" 13 | #include "util/Vector2D.h" 14 | 15 | PROJECT_NAMESPACE_BEGIN 16 | 17 | class Tech 18 | { 19 | public: 20 | /// @brief default constructor 21 | explicit Tech() = default; 22 | /*------------------------------*/ 23 | /* Construct the tech */ 24 | /*------------------------------*/ 25 | /// @brief add a gds layer 26 | /// @param a gds layer ID 27 | /// @return the placement layer index 28 | IndexType addGdsLayer(IndexType gdsLayer) 29 | { 30 | IndexType layerIdx = _gdsLayerIdxArray.size(); 31 | _gdsLayerIdxArray.emplace_back(gdsLayer); 32 | _layerIdxMap[gdsLayer] = layerIdx; 33 | return layerIdx; 34 | } 35 | /// @brief initialize the rule data structures 36 | void initRuleDataStructure(); 37 | /// @brief set the width rule for a layer 38 | /// @param first: the layer index 39 | /// @param second: the width rule for the layer 40 | void setWidthRule(IndexType layerIdx, LocType width) { _widthRule.at(layerIdx) = width; } 41 | /// @brief set the area rule for a layer 42 | /// @param first: the layer index 43 | /// @param second: the area rule for the layer 44 | void setAreaRule(IndexType layerIdx, LocType area) { _areaRule.at(layerIdx) = area; } 45 | /// @brief set the spacing rule for a intra-layer 46 | /// @param first: the layer 47 | void setSpacingRule(IndexType layerIdx, LocType spacing) { _spacingRule.at(layerIdx, layerIdx) = spacing; } 48 | /// @brief set the spacing for inter-layer case 49 | /// @param first: the first layer 50 | /// @param second: the second layer 51 | /// @param third: the spacing required 52 | /// For now, just make two layers interchangable 53 | void setSpacingRule(IndexType layerIdxFirst, IndexType layerIdxSecond, LocType spacing) 54 | { 55 | _spacingRule.at(layerIdxFirst, layerIdxSecond) = spacing; 56 | _spacingRule.at(layerIdxSecond, layerIdxFirst) = spacing; 57 | } 58 | /// @brief set the dbu/ database unit 59 | /// @param the databse unit 60 | void setDbu(LocType dbu) { _dbu = dbu; } 61 | /*------------------------------*/ 62 | /* Query the tech */ 63 | /*------------------------------*/ 64 | /// @brief get the layer index from GDS techlayer 65 | /// @param the GDS techlayer ID 66 | /// @return the corresponding layer index in the placement 67 | IndexType gdsLayerToLayerIdx(IndexType gdsLayer) const { return _layerIdxMap.at(gdsLayer); } 68 | /// @brief get whether there is width rule in the given layer 69 | /// @param the layer index 70 | /// @return where there is width rule defined in the given layer 71 | bool hasWidthRule(IndexType layerIdx) const { return _widthRule.at(layerIdx) != -1; } 72 | /// @brief get the width rule of the given layer 73 | /// @param the layer index 74 | /// @return the width rule 75 | LocType widthRule(IndexType layerIdx) const 76 | { 77 | Assert(this->hasWidthRule(layerIdx)); 78 | return _widthRule.at(layerIdx); 79 | } 80 | /// @brief get whether there is area rule defined in the given layer 81 | /// @param the layer index 82 | /// @return where there is area rule defined in the given layer 83 | bool hasAreaRule(IndexType layerIdx) const { return _areaRule.at(layerIdx) != -1; } 84 | /// @brief get the area rule of the given layer 85 | /// @param the layer index 86 | /// @return the area rule 87 | LocType areaRule(IndexType layerIdx) const 88 | { 89 | Assert(this->hasAreaRule(layerIdx)); 90 | return _areaRule.at(layerIdx); 91 | } 92 | /// @brief get whether there is intra spacing rules. The intralayer version 93 | /// @param first: the layer index 94 | /// @return whether there is spacing rule defined 95 | bool hasSpacingRule(IndexType layerIdxFirst) const 96 | { 97 | return _spacingRule.at(layerIdxFirst, layerIdxFirst) != -1; 98 | } 99 | /// @brief get the spacing rule of intra-layer 100 | /// @param the layer index 101 | /// @return the intra-layer spacing rule 102 | LocType spacingRule(IndexType layerIdx) const 103 | { 104 | Assert(this->hasSpacingRule(layerIdx)); 105 | return _spacingRule.at(layerIdx, layerIdx); 106 | } 107 | /// @brief get whether there is intra spacing rules. The interlayer version 108 | /// @param first: the first layer index 109 | /// @param second: the second layer index 110 | /// @return whether there is spacing rule defined 111 | bool hasSpacingRule(IndexType layerIdxFirst, IndexType layerIdxSecond) const 112 | { 113 | return _spacingRule.at(layerIdxFirst, layerIdxSecond) != -1; 114 | } 115 | /// @brief get the inter-spacing rule 116 | /// @param first: the first layer index 117 | /// @param second: the second layer index 118 | /// @return the spacing rule defined 119 | LocType spacingRule(IndexType layerIdxFirst, IndexType layerIdxSecond) const 120 | { 121 | Assert(this->hasSpacingRule(layerIdxFirst, layerIdxSecond)); 122 | return _spacingRule.at(layerIdxFirst, layerIdxSecond); 123 | } 124 | /// @brief get the database unit 125 | /// @return the database unit 126 | LocType dbu() const { return _dbu; } 127 | /// @brief get the number of layers 128 | /// @return the number of layers 129 | IndexType numLayers() const { return _gdsLayerIdxArray.size(); } 130 | /*------------------------------*/ 131 | /* Getters */ 132 | /*------------------------------*/ 133 | /// @brief get the map from gds techlayer to IDEAPLACE layer 134 | /// @return the map from gds techlayer to IDEAPLACE layer 135 | const std::unordered_map & layerIdxMap() const { return _layerIdxMap; } 136 | /// @brief get the map from gds techlayer to IDEAPLACE layer 137 | /// @return the map from gds techlayer to IDEAPLACE layer 138 | std::unordered_map & layerIdxMap() { return _layerIdxMap; } 139 | private: 140 | LocType _dbu = 1000; ///< 1 um = _dbu database units 141 | std::unordered_map _layerIdxMap; ///< A map from gds layer to IDEAPLACE layer. _layerIdxMap[techlayer] = layer index 142 | std::vector _gdsLayerIdxArray; ///< The tech layer in GDS. _gdsLayerIdx[idx of layer] = techlayer in GDS 143 | std::vector _widthRule; ///< The width rule of the layer 144 | std::vector _areaRule; ///< The area rule of the layer 145 | Vector2D _spacingRule; ///< The intra/inter-layer spacing rules. _spacingRule[layer1][layer2] = spacing rules btween shapes of layer 1 and layer 2. 146 | }; 147 | 148 | inline void Tech::initRuleDataStructure() 149 | { 150 | IndexType numLayers = _gdsLayerIdxArray.size(); 151 | _widthRule.resize(numLayers, -1); 152 | _areaRule.resize(numLayers, -1); 153 | _spacingRule.resize(numLayers, numLayers, -1); 154 | } 155 | 156 | PROJECT_NAMESPACE_END 157 | 158 | #endif ///IDEAPLACE_TECH_H_ 159 | -------------------------------------------------------------------------------- /src/api/IdeaPlaceExAPI.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file IdeaPlaceEx.cpp 3 | * @brief The pybind11 interface for the core placement engine api 4 | * @author Keren Zhu 5 | * @date 12/16/2019 6 | */ 7 | 8 | #include 9 | #include 10 | #include "main/IdeaPlaceEx.h" 11 | 12 | namespace py = pybind11; 13 | void initIdeaPlaceExAPI(py::module &m) 14 | { 15 | py::class_(m , "IdeaPlaceEx") 16 | .def(py::init<>()) 17 | .def("solve", &PROJECT_NAMESPACE::IdeaPlaceEx::solve, "Solve the problem") 18 | .def("alignToGrid", &PROJECT_NAMESPACE::IdeaPlaceEx::alignToGrid, "Align the placement to grid") 19 | .def("numThreads", &PROJECT_NAMESPACE::IdeaPlaceEx::setNumThreads, "Set number of threads") 20 | .def("readTechSimpleFile", &PROJECT_NAMESPACE::IdeaPlaceEx::readTechSimpleFile, "Internal usage: Read in the techsimple file") 21 | .def("readPinFile", &PROJECT_NAMESPACE::IdeaPlaceEx::readPinFile, "Internal usage: Read in the .pin file") 22 | .def("readConnectionFile", &PROJECT_NAMESPACE::IdeaPlaceEx::readConnectionFile, "Internal usage: Read in the .connection file") 23 | .def("readNetWgtFile", &PROJECT_NAMESPACE::IdeaPlaceEx::readNetWgtFile, "Internal usage: Read in the .netwgt file") 24 | .def("readSymFile", &PROJECT_NAMESPACE::IdeaPlaceEx::readSymFile, "Internal usage: Read in the .sym file") 25 | .def("readGdsLayout", &PROJECT_NAMESPACE::IdeaPlaceEx::readGdsLayout, "Internal Usage: Read in a gds for cell, the name of the GDS cell need to match the cell name") 26 | .def("readSymNetFile", &PROJECT_NAMESPACE::IdeaPlaceEx::readSymNetFile, "Internal Usage: Read in a .symnet file") 27 | .def("readSigpathFile", &PROJECT_NAMESPACE::IdeaPlaceEx::readSigpathFile, "Internal Usage: Read in a .sigpath file") 28 | .def("addGdsLayer", &PROJECT_NAMESPACE::IdeaPlaceEx::addGdsLayer, py::arg("cellIdx") = PROJECT_NAMESPACE::INDEX_TYPE_MAX, "Add a gds to a cell") 29 | .def("finishAddingGdsLayer", &PROJECT_NAMESPACE::IdeaPlaceEx::finishAddingGdsLayer, "Finish the gds layer adding, trigger a init function") 30 | .def("allocateCell", &PROJECT_NAMESPACE::IdeaPlaceEx::allocateCell, "Allocate a new cell, return the index of the cell") 31 | .def("setCellName", &PROJECT_NAMESPACE::IdeaPlaceEx::setCellName, "Set the name of a cell") 32 | .def("setCellFlip", &PROJECT_NAMESPACE::IdeaPlaceEx::setCellFlip, "Flip a cell") 33 | .def("allocatePin", &PROJECT_NAMESPACE::IdeaPlaceEx::allocatePin, "Allocate a new pin. Return the index of the pin") 34 | .def("addPinShape", &PROJECT_NAMESPACE::IdeaPlaceEx::addPinShape, "Add a shape to a pin") 35 | .def("setPinName", &PROJECT_NAMESPACE::IdeaPlaceEx::setPinName, "Set the name of a pin") 36 | .def("allocateNet", &PROJECT_NAMESPACE::IdeaPlaceEx::allocateNet, "Allocate a new net. Return the index of the net") 37 | .def("setNetName", &PROJECT_NAMESPACE::IdeaPlaceEx::setNetName, "Set the name of a net") 38 | .def("addPinToNet", &PROJECT_NAMESPACE::IdeaPlaceEx::addPinToNet, "Add a pin to a net") 39 | .def("setNetWgt", &PROJECT_NAMESPACE::IdeaPlaceEx::setNetWgt, "Set the weight of a net") 40 | .def("allocateSymGrp", &PROJECT_NAMESPACE::IdeaPlaceEx::allocateSymGrp, "Allocate a new symmetric group") 41 | .def("addSymPair", &PROJECT_NAMESPACE::IdeaPlaceEx::addSymPair, "Add a new symmetric pair to a symmetric group") 42 | .def("addSelfSym", &PROJECT_NAMESPACE::IdeaPlaceEx::addSelfSym, "Add a self-symmetric constraint to a symmetric group") 43 | .def("addCellShape", &PROJECT_NAMESPACE::IdeaPlaceEx::addCellShape, "Add a shape to a cell") 44 | .def("numCells", &PROJECT_NAMESPACE::IdeaPlaceEx::numCells, "Get the number of cells") 45 | .def("cellIdxName", &PROJECT_NAMESPACE::IdeaPlaceEx::cellIdxName, "Get the index based on cell name") 46 | .def("cellName", &PROJECT_NAMESPACE::IdeaPlaceEx::cellName, "Get the cell name") 47 | .def("pinIdx", &PROJECT_NAMESPACE::IdeaPlaceEx::pinIdx, "Get the index based on pin name") 48 | .def("openVirtualPinAssignment", &PROJECT_NAMESPACE::IdeaPlaceEx::openVirtualPinAssignment, "Open the virtual pin assignment functionality") 49 | .def("closeVirtualPinAssignment", &PROJECT_NAMESPACE::IdeaPlaceEx::closeVirtualPinAssignment, "Close the virtual pin assignment functionality") 50 | .def("setIoPinBoundaryExtension", &PROJECT_NAMESPACE::IdeaPlaceEx::setIoPinBoundaryExtension, "Set the extension of io pin locations to the boundary of cell placements") 51 | .def("setIoPinInterval", &PROJECT_NAMESPACE::IdeaPlaceEx::setIoPinInterval, "Set the minimum interval of io pins") 52 | .def("markIoNet", &PROJECT_NAMESPACE::IdeaPlaceEx::markAsIoNet, "Mark a net as IO net") 53 | .def("revokeIoNet", &PROJECT_NAMESPACE::IdeaPlaceEx::revokeIoNet, "Revoke IO net flag on a net") 54 | .def("markAsVddNet", &PROJECT_NAMESPACE::IdeaPlaceEx::markAsVddNet, "Mark a net as VDD") 55 | .def("markAsVssNet", &PROJECT_NAMESPACE::IdeaPlaceEx::markAsVssNet, "Mark a net as VSS") 56 | .def("addSymNetPair", &PROJECT_NAMESPACE::IdeaPlaceEx::addSymNetPair, "Add a pair of symmetric nets") 57 | .def("markSelfSym", &PROJECT_NAMESPACE::IdeaPlaceEx::markSelfSymNet, "Mark a net as self symmetric") 58 | .def("allocateProximityGroup", &PROJECT_NAMESPACE::IdeaPlaceEx::allocateProximityGroup, "Allocate a new proximity group") 59 | .def("addCellToProximityGroup", &PROJECT_NAMESPACE::IdeaPlaceEx::addCellToProximityGroup, "Add a cell to a proximity group") 60 | .def("allocateSignalPath", &PROJECT_NAMESPACE::IdeaPlaceEx::allocateSignalPath, "Allocate a new signal path") 61 | .def("markSignalPathAsPower", &PROJECT_NAMESPACE::IdeaPlaceEx::markSignalPathAsPower, "Mark a signal path as power") 62 | .def("addPinToSignalPath", &PROJECT_NAMESPACE::IdeaPlaceEx::addPinToSignalPath, "add a pin to a signal path") 63 | .def("iopinX", &PROJECT_NAMESPACE::IdeaPlaceEx::iopinX, "Get the x coordinate of a net") 64 | .def("iopinY", &PROJECT_NAMESPACE::IdeaPlaceEx::iopinY, "Get the y coordinate of a net") 65 | .def("isIoPinVertical", &PROJECT_NAMESPACE::IdeaPlaceEx::isIopinVertical, "true if io pins are on top or bottom") 66 | .def("xCellLoc", &PROJECT_NAMESPACE::IdeaPlaceEx::xCellLoc, "Get x coordinate of a cell location") 67 | .def("yCellLoc", &PROJECT_NAMESPACE::IdeaPlaceEx::yCellLoc, "Get y coordinate of a cell location") 68 | .def("runtimeIdeaPlaceEx", &PROJECT_NAMESPACE::IdeaPlaceEx::runtimeIdeaPlaceEx, "Get the runtime for the Ideaplace") 69 | .def("runtimeGlobalPlace", &PROJECT_NAMESPACE::IdeaPlaceEx::runtimeGlobalPlace, "Get the time used for global placement") 70 | .def("runtimeGlobalPlaceCalcObj", &PROJECT_NAMESPACE::IdeaPlaceEx::runtimeGlobalPlaceCalcObj, "Get the time used for calculating the objectives in global placement") 71 | .def("runtimeGlobalPlaceCalcGrad", &PROJECT_NAMESPACE::IdeaPlaceEx::runtimeGlobalPlaceCalcGrad, "Get the time used for calculating the gradients in global placement") 72 | .def("runtimeGlobalPlaceOptmKernel", &PROJECT_NAMESPACE::IdeaPlaceEx::runtimeGlobalPlaceOptmKernel, "Get the time used for optimizer kernel in the global placement") 73 | .def("runtimeGlobalPlaceOptimize", &PROJECT_NAMESPACE::IdeaPlaceEx::runtimeGlobalPlaceOptimize, "Get the time used for global placement optimize routine") 74 | .def("runtimeGlobalPlaceUpdateProblem", &PROJECT_NAMESPACE::IdeaPlaceEx::runtimeGlobalPlaceUpdateProblem, "Get the time used for updating the problem in gloobal placement") 75 | .def("runtimeLegalization", &PROJECT_NAMESPACE::IdeaPlaceEx::runtimeLegalization, "Get the time used for legalization") 76 | .def("runtimeDetailedPlacement", &PROJECT_NAMESPACE::IdeaPlaceEx::runtimeDetailedPlacement, "Get the time used for detailed placement") 77 | ; 78 | } 79 | -------------------------------------------------------------------------------- /src/place/nlp/nlpOptmKernels.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file nlpOptmKernel.hpp 3 | * @brief The non-lnear programming basic optimization kernel for global plaement 4 | * @author Keren Zhu 5 | * @date 04/05/2020 6 | */ 7 | 8 | #pragma once 9 | 10 | #include "global/global.h" 11 | #include "nlpTypes.hpp" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | namespace nlp 16 | { 17 | namespace converge 18 | { 19 | template 20 | struct converge_criteria_trait {}; 21 | 22 | /// @brief used for place holder 23 | struct converge_criteria_empty {}; 24 | 25 | template<> 26 | struct converge_criteria_trait 27 | { 28 | typedef converge_criteria_empty converge_type; 29 | template 30 | static constexpr BoolType stopCriteria(nlp_type &, optm_type &, converge_type&) { return false;} 31 | template 32 | static constexpr void clear(converge_type&) {} 33 | }; 34 | 35 | 36 | template 37 | struct converge_criteria_max_iter 38 | { 39 | IntType _iter = 0; 40 | }; 41 | 42 | template 43 | struct converge_criteria_trait> 44 | { 45 | typedef converge_criteria_max_iter converge_type; 46 | static void clear(converge_type &c) 47 | { 48 | c._iter = 0; 49 | } 50 | template 51 | static BoolType stopCriteria(nlp_type &, optm_type &, converge_type &c) 52 | { 53 | if (c._iter >= max_iter) 54 | { 55 | clear(c); 56 | return true; 57 | } 58 | else 59 | { 60 | ++c._iter; 61 | return false; 62 | } 63 | } 64 | }; 65 | 66 | template 67 | struct converge_grad_norm_by_init 68 | { 69 | nlp_numerical_type confidenceRatio = 0.1; ///< stop if the norm reduce to this ratio of the init 70 | nlp_numerical_type initNorm = -1.0; 71 | }; 72 | 73 | template 74 | struct converge_criteria_trait> 75 | { 76 | typedef converge_grad_norm_by_init converge_type; 77 | static void clear(converge_type &c) 78 | { 79 | c.initNorm = -1.0; 80 | } 81 | template::value, void>* = nullptr> 82 | static BoolType stopCriteria(nlp_type &n, optm_type &, converge_type &c) 83 | { 84 | if (c.initNorm < 0) 85 | { 86 | c.initNorm = n._grad.norm(); 87 | return false; 88 | } 89 | if (n._grad.norm() < c.confidenceRatio * c.initNorm) 90 | { 91 | clear(c); 92 | return true; 93 | } 94 | return false; 95 | } 96 | }; 97 | 98 | template 99 | struct converge_criteria_stop_improve_less_in_last_two_step 100 | { 101 | static constexpr RealType _stopThreshold = 0.0001; 102 | nlp_numerical_type _fLastStep = - 1.0; 103 | nlp_numerical_type _fLastLastStep = - 1.0; 104 | }; 105 | 106 | template 107 | struct converge_criteria_trait> 108 | { 109 | typedef converge_criteria_stop_improve_less_in_last_two_step converge_type; 110 | static void clear(converge_type &c) 111 | { 112 | c._fLastStep = - 1.0; 113 | c._fLastLastStep = - 1.0; 114 | } 115 | template 116 | static BoolType stopCriteria(nlp_type &n, optm_type &, converge_type &c) 117 | { 118 | if (c._fLastLastStep >= 0.0) 119 | { 120 | if ((c._fLastLastStep - n._obj) / c._fLastLastStep < c._stopThreshold) 121 | { 122 | clear(c); 123 | return true; 124 | } 125 | } 126 | c._fLastLastStep = c._fLastStep; 127 | c._fLastStep = n._obj; 128 | return false; 129 | } 130 | }; 131 | 132 | /// @brief a convenient wrapper for combining different types of converge condition. the list in the template will be check one by one and return converge if any of them say so 133 | template 134 | struct converge_list 135 | { 136 | typedef converge_list base_type; 137 | converge_type _converge; 138 | converge_list _list; 139 | }; 140 | 141 | template 142 | struct converge_list 143 | { 144 | converge_type _converge; 145 | }; 146 | 147 | template 148 | struct converge_criteria_trait> 149 | { 150 | typedef typename converge_list::base_type base_type; 151 | static void clear(converge_list &c) 152 | { 153 | converge_criteria_trait::clear(c._converge); 154 | converge_criteria_trait::clear(c._list); 155 | } 156 | template 157 | static BoolType stopCriteria(nlp_type &n, optm_type &o, converge_list&c) 158 | { 159 | BoolType stop = false; 160 | if (converge_criteria_trait::stopCriteria(n, o, c._converge)) 161 | { 162 | stop = true; 163 | } 164 | if (converge_criteria_trait::stopCriteria(n, o, c._list)) 165 | { 166 | stop = true; 167 | } 168 | if (stop) 169 | { 170 | converge_criteria_trait::clear(c._converge); 171 | } 172 | return stop; 173 | } 174 | }; 175 | 176 | 177 | template 178 | struct converge_criteria_trait> 179 | { 180 | static void clear(converge_list &c) 181 | { 182 | converge_criteria_trait::clear(c._converge); 183 | } 184 | template 185 | static BoolType stopCriteria(nlp_type &n, optm_type &o, converge_list&c) 186 | { 187 | if (converge_criteria_trait::stopCriteria(n, o, c._converge)) 188 | { 189 | converge_criteria_trait::clear(c._converge); 190 | return true; 191 | } 192 | return false; 193 | } 194 | }; 195 | } // namespace converge 196 | } // namespace nlp 197 | 198 | PROJECT_NAMESPACE_END 199 | -------------------------------------------------------------------------------- /src/place/constraintGraphGeneration.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file constraintGraphGeneration.h 3 | * @brief The reimplement of the sweep line and transitive reduction algorithm on generating the constraint graph for legalization 4 | * @author Keren Zhu 5 | * @date 01/26/2020 6 | */ 7 | 8 | #ifndef IDEAPLACE_CONSTRAINT_GRAPH_GENERATION_H_ 9 | #define IDEAPLACE_CONSTRAINT_GRAPH_GENERATION_H_ 10 | 11 | #include "CGLegalizer.h" 12 | 13 | PROJECT_NAMESPACE_BEGIN 14 | 15 | /// @brief Events: the time stamps for lower and higher edges in sweep line. Basically, when finding horizontal edges. a sweep line is visited all cell in vertical direction. The events determine when to add or removes the devices as the sweep line cross the cell edge. 16 | class Event 17 | { 18 | public: 19 | explicit Event(IndexType cellIdx, LocType loc, bool isLow) 20 | : _cellIdx(cellIdx), _loc(loc), _isLow(isLow) 21 | {} 22 | /// @brief get the cell index this event belonging to 23 | IndexType cellIdx() const { return _cellIdx; } 24 | /// @brief get the coordinate of this event 25 | LocType loc() const { return _loc; } 26 | /// @brief get whether this event is low 27 | /// @return true: low. false: high 28 | bool isLow() const { return _isLow; } 29 | /// @brief comparing operator. The events are sorted in increasing loc order. When two coordinates are the same, the high events must before the low events. NOTE: what if there are multiple same coodinates? 30 | bool operator<(const Event &rhs) const 31 | { 32 | if (_loc == rhs.loc()) 33 | { 34 | if (_isLow == rhs.isLow()) 35 | { 36 | return _cellIdx < rhs.cellIdx(); 37 | } 38 | return !_isLow; // if lhs is low, lhs > rhs. if lhs is high (!_isLow), lhs < rhs. 39 | } 40 | return _loc < rhs.loc(); 41 | } 42 | private: 43 | IndexType _cellIdx = INDEX_TYPE_MAX; ///< The index of cell this event belonging to 44 | LocType _loc = LOC_TYPE_MIN; ///< The coordinate of the event. If finding horzional edges, the loc is the lower/higher y edge. 45 | bool _isLow = true; ///< true: low edge. false: high edge 46 | }; 47 | 48 | /// @brief a simple data structure to contain the information of the xLo/yLo 49 | class CellCoord 50 | { 51 | public: 52 | explicit CellCoord(IndexType cellIdx, LocType loc) 53 | : _cellIdx(cellIdx), _loc(loc) 54 | {} 55 | IndexType cellIdx() const { return _cellIdx; } 56 | LocType loc() const { return _loc; } 57 | /// @brief comparison operator. \lambda relation in the original paper x_i > x_j or (xi = xj and i > j). Here take itsopposite 58 | bool operator<(const CellCoord &rhs) const 59 | { 60 | if (_loc == rhs.loc()) 61 | { 62 | return _cellIdx < rhs.cellIdx(); 63 | } 64 | return _loc < rhs.loc(); 65 | } 66 | private: 67 | IndexType _cellIdx; ///< The cell index 68 | LocType _loc; ///< xLo or yLo 69 | }; 70 | 71 | /// @class Sweep line for generating constraints 72 | class SweeplineConstraintGraphGenerator 73 | { 74 | public: 75 | explicit SweeplineConstraintGraphGenerator(Database &db, Constraints &hC, Constraints &vC) 76 | : _db(db), _hC(hC), _vC(vC) 77 | {} 78 | /// @brief solve the sweep line 79 | void solve(); 80 | void setExemptFunc(std::function exexmptFunc) 81 | { 82 | _exemptFunc = exexmptFunc; 83 | _setExempted = true; 84 | } 85 | /// @brief the balance tree for containing the "D" in TCAD-1987. Using the std::set implementation 86 | class CellCoordTree 87 | { 88 | public: 89 | explicit CellCoordTree() = default; 90 | /// @brief insert a CellCoord 91 | void insert(const CellCoord &cellCoord) { _tree.insert(cellCoord); } 92 | /// @brief erase a CellCoord 93 | void erase(const CellCoord &cellCoord) { _tree.erase(cellCoord); } 94 | /// @brief find the right cell index in the tree 95 | /// @param a CellCoord, this object should already inside the tree 96 | /// @return the cell index. -1 if nil 97 | IntType right(const CellCoord &cellCoord) 98 | { 99 | auto findIter = _tree.find(cellCoord); 100 | Assert(findIter != _tree.end()); 101 | findIter++; 102 | if (findIter == _tree.end()) 103 | { 104 | return -1; 105 | } 106 | else 107 | { 108 | return static_cast(findIter->cellIdx()); 109 | } 110 | } 111 | /// @brief find the left cell index in the tree 112 | /// @param a CellCoord, this object should already inside the tree 113 | /// @return the cell index. -1 if nil 114 | IntType left(const CellCoord &cellCoord) 115 | { 116 | auto findIter = _tree.find(cellCoord); 117 | Assert(findIter != _tree.end()); 118 | if (findIter == _tree.begin()) 119 | { 120 | return -1; // This cellCoord is the leftmost in the tree 121 | } 122 | else 123 | { 124 | findIter --; 125 | return static_cast(findIter->cellIdx()); 126 | } 127 | } 128 | private: 129 | std::set _tree; ///< std::set to act as the balanced tree 130 | }; 131 | private: 132 | /// @brief generate the events. 133 | /// @param first: the referece to a vector of events. The vector will be cleared first. 134 | /// @param second: true: generating horizontal edges. false: generating vertical edges 135 | void generateEvents(std::vector &events, bool isHor); 136 | /// @brief original TCAD-87 algorithm 137 | void originalSweepLine(); 138 | /// @brief record all the cell coordinates 139 | /// @param first: A reference to the vector of cell coordinates. The vector will be cleared in the beginning 140 | /// @param second: true: if generating horizontal edges. false if vertical 141 | void recordCellCoords(std::vector &cellCords, bool isHor); 142 | /// @brief generate the constraint edges with TCAD-1987 compact ver. 1 143 | /// @param first: the constraints to save results in 144 | /// @param second: the sorted events 145 | /// @param third: the recorded cell coordinates 146 | //void originalConstraintGeneration(Constraints &cs, std::vector &events, std::vector &cellCoords); 147 | void originalDelete(const CellCoord &cellCoord, CellCoordTree &dTree, std::vector &cand, Constraints &cs); 148 | void originalConstraintGeneration(Constraints &cs, std::vector &events, std::vector &cellCoords); 149 | bool isExempted(IndexType cell1, IndexType cell2) const 150 | { 151 | if (!_setExempted) 152 | { 153 | return false; 154 | } 155 | else 156 | { 157 | return _exemptFunc(cell1, cell2); 158 | } 159 | } 160 | 161 | private: 162 | Database &_db; ///< The placement database 163 | Constraints &_hC; ///< The horizontal edges 164 | Constraints &_vC; ///< The vertical edges 165 | std::function _exemptFunc; ///< exempt pair of cells to be add constraints 166 | bool _setExempted = false; 167 | }; 168 | 169 | PROJECT_NAMESPACE_END 170 | 171 | #endif //IDEAPLACE_CONSTRAINT_GRAPH_GENERATION_H_ 172 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | # This file is NOT licensed under the GPLv4, which is the license for the rest 2 | # of YouCompleteMe. 3 | # 4 | # Here's the license text for this file: 5 | # 6 | # This is free and unencumbered software released into the public domain. 7 | # 8 | # Anyone is free to copy, modify, publish, use, compile, sell, or 9 | # distribute this software, either in source code form or as a compiled 10 | # binary, for any purpose, commercial or non-commercial, and by any 11 | # means. 12 | # 13 | # In jurisdictions that recognize copyright laws, the author or authors 14 | # of this software dedicate any and all copyright interest in the 15 | # software to the public domain. We make this dedication for the benefit 16 | # of the public at large and to the detriment of our heirs and 17 | # successors. We intend this dedication to be an overt act of 18 | # relinquishment in perpetuity of all present and future rights to this 19 | # software under copyright law. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | # OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # For more information, please refer to 30 | 31 | from distutils.sysconfig import get_python_inc 32 | import platform 33 | import os 34 | import ycm_core 35 | import glob 36 | 37 | # These are the compilation flags that will be used in case there's no 38 | # compilation database set (by default, one is not set). 39 | # CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. 40 | 41 | sparseHash = os.environ['SPARSE_HASH_DIR'] + "/include" 42 | limbo = os.environ['LIMBO_DIR'] + "/include" 43 | pybind11 = os.environ['PYBIND11_DIR'] + "/include" 44 | gtest = os.environ['GTEST_DIR'] + '/googletest/include' 45 | wnlib = os.environ['WNLIB_DIR'] + '/acc/h' 46 | lpsolve = os.environ['LPSOLVE_DIR'] 47 | lemon = os.environ['LEMON_DIR'] + "/include" 48 | eigen = os.environ['EIGEN_INC'] 49 | gurobi = os.environ['GUROBI_INC'] 50 | cpp_taskflow = os.environ['CPP_TASKFLOW_DIR'] 51 | flags = [ 52 | '-Wall', 53 | '-Wextra', 54 | '-Werror', 55 | '-Wno-long-long', 56 | '-Wno-variadic-macros', 57 | '-fexceptions', 58 | '-DNDEBUG', 59 | # You 100% do NOT need -DUSE_CLANG_COMPLETER and/or -DYCM_EXPORT in your flags; 60 | # only the YCM source code needs it. 61 | #'-DUSE_CLANG_COMPLETER', 62 | #'-DYCM_EXPORT=', 63 | # THIS IS IMPORTANT! Without the '-x' flag, Clang won't know which language to 64 | # use when compiling headers. So it will guess. Badly. So C++ headers will be 65 | # compiled as C headers. You don't want that so ALWAYS specify the '-x' flag. 66 | # For a C project, you would set this to 'c' instead of 'c++'. 67 | '-x', 68 | 'c++', 69 | #'-isystem', 70 | #'../BoostParts', 71 | '-isystem', 72 | get_python_inc(), 73 | '-I', 74 | '.', 75 | '-I', './include', 76 | '-I', './src', 77 | 78 | #Added 79 | '-I', lemon, 80 | '-I', sparseHash, 81 | '-I', limbo, 82 | '-I', pybind11, 83 | '-I', gtest, 84 | '-I', wnlib, 85 | '-I', lpsolve, 86 | '-I', eigen, 87 | '-I', gurobi, 88 | '-I', cpp_taskflow, 89 | '-isystem', 90 | '/home/local/eda09/keren/common/libs/boost_1_67_0/boost' 91 | ] 92 | 93 | # Clang automatically sets the '-std=' flag to 'c++14' for MSVC 2015 or later, 94 | # which is required for compiling the standard library, and to 'c++11' for older 95 | # versions. 96 | if platform.system() != 'Windows': 97 | flags.append( '-std=c++14' ) 98 | 99 | 100 | # Set this to the absolute path to the folder (NOT the file!) containing the 101 | # compile_commands.json file to use that instead of 'flags'. See here for 102 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 103 | # 104 | # You can get CMake to generate this file for you by adding: 105 | # set( CMAKE_EXPORT_COMPILE_COMMANDS 1 ) 106 | # to your CMakeLists.txt file. 107 | # 108 | # Most projects will NOT need to set this to anything; you can just change the 109 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach. 110 | compilation_database_folder = '' 111 | 112 | if os.path.exists( compilation_database_folder ): 113 | database = ycm_core.CompilationDatabase( compilation_database_folder ) 114 | else: 115 | database = None 116 | 117 | SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] 118 | 119 | def DirectoryOfThisScript(): 120 | return os.path.dirname( os.path.abspath( __file__ ) ) 121 | 122 | 123 | def IsHeaderFile( filename ): 124 | extension = os.path.splitext( filename )[ 1 ] 125 | return extension in [ '.h', '.hxx', '.hpp', '.hh' ] 126 | 127 | 128 | def GetCompilationInfoForFile( filename ): 129 | # The compilation_commands.json file generated by CMake does not have entries 130 | # for header files. So we do our best by asking the db for flags for a 131 | # corresponding source file, if any. If one exists, the flags for that file 132 | # should be good enough. 133 | if IsHeaderFile( filename ): 134 | basename = os.path.splitext( filename )[ 0 ] 135 | for extension in SOURCE_EXTENSIONS: 136 | replacement_file = basename + extension 137 | if os.path.exists( replacement_file ): 138 | compilation_info = database.GetCompilationInfoForFile( 139 | replacement_file ) 140 | if compilation_info.compiler_flags_: 141 | return compilation_info 142 | return None 143 | return database.GetCompilationInfoForFile( filename ) 144 | 145 | 146 | def FlagsForFile( filename, **kwargs ): 147 | if not database: 148 | return { 149 | 'flags': flags, 150 | 'include_paths_relative_to_dir': DirectoryOfThisScript() 151 | } 152 | 153 | compilation_info = GetCompilationInfoForFile( filename ) 154 | if not compilation_info: 155 | return None 156 | 157 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a 158 | # python list, but a "list-like" StringVec object. 159 | final_flags = list( compilation_info.compiler_flags_ ) 160 | 161 | # NOTE: This is just for YouCompleteMe; it's highly likely that your project 162 | # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR 163 | # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT. 164 | try: 165 | final_flags.remove( '-stdlib=libc++' ) 166 | except ValueError: 167 | pass 168 | 169 | return { 170 | 'flags': final_flags, 171 | 'include_paths_relative_to_dir': compilation_info.compiler_working_dir_ 172 | } 173 | 174 | def Subdirectories(directory): 175 | res = [] 176 | for path, subdirs, files in os.walk(directory): 177 | for name in subdirs: 178 | item = os.path.join(path, name) 179 | res.append(item) 180 | return res 181 | 182 | def IncludeFlagsOfSubdirectory( flags, working_directory ): 183 | if not working_directory: 184 | return list( flags ) 185 | new_flags = [] 186 | make_next_include_subdir = False 187 | path_flags = [ '-ISUB'] 188 | for flag in flags: 189 | # include the directory of flag as well 190 | new_flag = [flag.replace('-ISUB', '-I')] 191 | 192 | if make_next_include_subdir: 193 | make_next_include_subdir = False 194 | for subdir in Subdirectories(os.path.join(working_directory, flag)): 195 | new_flag.append('-I') 196 | new_flag.append(subdir) 197 | 198 | for path_flag in path_flags: 199 | if flag == path_flag: 200 | make_next_include_subdir = True 201 | break 202 | 203 | if flag.startswith( path_flag ): 204 | path = flag[ len( path_flag ): ] 205 | for subdir in Subdirectories(os.path.join(working_directory, path)): 206 | new_flag.append('-I' + subdir) 207 | break 208 | 209 | new_flags =new_flags + new_flag 210 | return new_flags 211 | -------------------------------------------------------------------------------- /src/place/nlp/nlpSecondOrderKernels.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file nlpSecondOrderKernel.hpp 3 | * @brief The non-lnear programming second order optimization kernel for global plaement 4 | * @author Keren Zhu 5 | * @date 04/24/2020 6 | */ 7 | 8 | #pragma once 9 | 10 | #include "global/global.h" 11 | #include "nlpOptmKernels.hpp" 12 | #include "nlpFirstOrderKernel.hpp" 13 | 14 | PROJECT_NAMESPACE_BEGIN 15 | 16 | namespace nlp 17 | { 18 | namespace optm 19 | { 20 | namespace second_order 21 | { 22 | /// @brief Naive gradient descent. It will stop if maxIter reaches or the improvement 23 | template 24 | struct naive_gradient_descent 25 | { 26 | typedef converge_criteria_type converge_type; 27 | static constexpr RealType _stepSize = 0.001; 28 | converge_criteria_type _converge; 29 | }; 30 | /// @brief adam 31 | template 32 | struct adam 33 | { 34 | typedef converge_criteria_type converge_type; 35 | converge_criteria_type _converge; 36 | static constexpr nlp_numerical_type alpha = 0.005; 37 | static constexpr nlp_numerical_type beta1 = 0.9; 38 | static constexpr nlp_numerical_type beta2 = 0.999; 39 | static constexpr nlp_numerical_type epsilon = 1e-8; 40 | 41 | }; 42 | /// @brief nesterov accelerated gradient 43 | template 44 | struct nesterov 45 | { 46 | typedef converge_criteria_type converge_type; 47 | converge_criteria_type _converge; 48 | static constexpr nlp_numerical_type eta = 0.003; 49 | 50 | }; 51 | } // namspace second_order 52 | template 53 | struct optm_trait> 54 | { 55 | typedef second_order::naive_gradient_descent optm_type; 56 | typedef typename optm_type::converge_type converge_type; 57 | typedef nlp::converge::converge_criteria_trait converge_trait; 58 | template::value, void>* = nullptr> 59 | static void optimize(nlp_type &n, optm_type &o) 60 | { 61 | converge_trait::clear(o._converge); 62 | IndexType iter = 0; 63 | do 64 | { 65 | n.calcGrad(); 66 | n.calcHessian();; 67 | n._pl -= optm_type::_stepSize * n.inverseHessian() * n._grad; 68 | ++iter; 69 | } while (!converge_trait::stopCriteria(n, o, o._converge) ); 70 | n.calcObj(); 71 | DBG("converge at iter %d \n", iter); 72 | DBG("norm %f \n", n._gradOvl.norm()); 73 | DBG("naive gradiend descent: %f hpwl %f cos %f ovl %f oob %f asym %f \n", n._obj, n._objHpwl, n._objCos, n._objOvl, n._objOob, n._objAsym); 74 | } 75 | }; 76 | template 77 | struct optm_trait> 78 | { 79 | typedef second_order::adam optm_type; 80 | typedef typename optm_type::converge_type converge_type; 81 | typedef nlp::converge::converge_criteria_trait converge_trait; 82 | template::value, void>* = nullptr> 83 | static void optimize(nlp_type &n, optm_type &o) 84 | { 85 | converge_trait::clear(o._converge); 86 | const IndexType numVars = n._numVariables; 87 | typename nlp_type::EigenVector m, v; 88 | m.resize(numVars); m.setZero(); 89 | v.resize(numVars); v.setZero(); 90 | IndexType iter = 0; 91 | do 92 | { 93 | ++iter; 94 | n.calcGrad(); 95 | n.calcHessian(); 96 | auto grad = n.inverseHessian() * n._grad; 97 | m = o.beta1 * m + (1 - o.beta1) * grad; 98 | v = o.beta2 * v + (1 - o.beta2) * grad.cwiseProduct(grad); 99 | auto mt = m / (1 - pow(o.beta1, iter)); 100 | auto vt = v / (1 - pow(o.beta2, iter)); 101 | auto bot = vt.array().sqrt() + o.epsilon; 102 | n._pl = n._pl - o.alpha * ( mt.array() / bot).matrix(); 103 | //n.calcObj(); 104 | //DBG("norm %f \n", n._grad.norm()); 105 | //DBG("adam: %f hpwl %f cos %f ovl %f oob %f asym %f \n", n._obj, n._objHpwl, n._objCos, n._objOvl, n._objOob, n._objAsym); 106 | } while (!converge_trait::stopCriteria(n, o, o._converge) ); 107 | n.calcObj(); 108 | DBG("adam: %f hpwl %f cos %f ovl %f oob %f asym %f \n", n._obj, n._objHpwl, n._objCos, n._objOvl, n._objOob, n._objAsym); 109 | DBG("gradient norm %f \n", n._grad.norm()); 110 | DBG("converge at iter %d \n", iter); 111 | } 112 | }; 113 | 114 | 115 | template 116 | struct optm_trait> 117 | { 118 | typedef second_order::nesterov optm_type; 119 | typedef typename optm_type::converge_type converge_type; 120 | typedef nlp::converge::converge_criteria_trait converge_trait; 121 | template::value, void>* = nullptr> 122 | static void optimize(nlp_type &n, optm_type &o) 123 | { 124 | converge_trait::clear(o._converge); 125 | const IndexType numVars = n._numVariables; 126 | IndexType iter = 0; 127 | nlp_numerical_type lambdaPrev = 0; 128 | nlp_numerical_type lambdaCurr = 1; 129 | nlp_numerical_type gamma = 1; 130 | typename nlp_type::EigenVector yCurr, yPrev; 131 | yCurr.resize(numVars); yCurr.setZero(); 132 | yPrev.resize(numVars); yPrev = n._pl; 133 | do 134 | { 135 | ++iter; 136 | n.calcGrad(); 137 | n.calcHessian(); 138 | yCurr = n._pl - o.eta * n.inverseHessian() * n._grad; 139 | n._pl = (1 - gamma) * yCurr + gamma * yPrev; 140 | 141 | yPrev = yCurr; 142 | 143 | const auto lambdaTemp = lambdaCurr; 144 | lambdaCurr = (1 + std::sqrt(1 + 4 * lambdaPrev * lambdaPrev)) * 0.5; 145 | lambdaPrev = lambdaTemp; 146 | 147 | gamma = (1 - lambdaPrev) / lambdaCurr; 148 | gamma = std::min(gamma, 0.999999999); 149 | gamma = std::max(gamma, 1e-8); 150 | } while (!converge_trait::stopCriteria(n, o, o._converge) ); 151 | n.calcObj(); 152 | DBG("nesterov: %f hpwl %f cos %f ovl %f oob %f asym %f \n", n._obj, n._objHpwl, n._objCos, n._objOvl, n._objOob, n._objAsym); 153 | DBG("gradient norm %f \n", n._grad.norm()); 154 | DBG("converge at iter %d \n", iter); 155 | } 156 | }; 157 | } // namespace optm 158 | } // namespace nlp 159 | 160 | PROJECT_NAMESPACE_END 161 | -------------------------------------------------------------------------------- /src/util/lp_limbo.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file lp_limbo.h 3 | * @brief The linear programming implementation using limbo::LPSolveApi and limbo::GurobiLinearApi 4 | * @author Keren Zhu 5 | * @date 03/10/2020 6 | */ 7 | 8 | #ifndef KLIB_LP_LIMBO_H_ 9 | #define KLIB_LP_LIMBO_H_ 10 | 11 | #include 12 | #ifndef LP_NOT_USE_LPSOLVE 13 | #include 14 | #endif 15 | #ifndef LP_NOT_USE_GUROBI 16 | #include 17 | #endif 18 | #include "linear_programming_trait.h" 19 | 20 | namespace klib { 21 | 22 | namespace _lp 23 | { 24 | 25 | template 26 | struct _limbo_lp_api_trait 27 | { 28 | typedef typename limbo_lp_api::param_type param_type; 29 | typedef typename limbo_lp_api::limbo_solver_type limbo_solver_type; 30 | typedef typename limbo_lp_api::value_type value_type; 31 | 32 | static void setDefaultParams(param_type & param); 33 | static void setNumThreads(param_type ¶m, std::uint32_t numThreads); 34 | }; 35 | 36 | template 37 | class _limbo_lp_solver 38 | { 39 | friend linear_programming_trait<_limbo_lp_solver>; 40 | public: 41 | typedef typename _limbo_lp_api_trait::value_type value_type; 42 | typedef typename limbo::solvers::LinearModel model_type; 43 | typedef typename model_type::variable_type variable_type; 44 | typedef typename model_type::expression_type expr_type; 45 | typedef typename model_type::constraint_type constr_type; 46 | typedef limbo::solvers::SolverProperty status_type; 47 | typedef typename _limbo_lp_api_trait::param_type param_type; 48 | typedef typename _limbo_lp_api_trait::limbo_solver_type limbo_solver_type; 49 | private: 50 | model_type _model; ///< The LP problem model 51 | status_type _status; ///< The result status. e.g. OPTIMAL 52 | param_type _params; ///< The parameters for LIMBO solver 53 | }; 54 | 55 | #ifndef LP_NOT_USE_LPSOLVE 56 | 57 | 58 | template 59 | struct _limbo_lp_api_lpsove 60 | { 61 | }; 62 | 63 | template 64 | struct _limbo_lp_api_trait<_limbo_lp_api_lpsove> 65 | { 66 | typedef coe_value_type value_type; 67 | typedef typename limbo::solvers::LPSolveParameters param_type; 68 | typedef limbo::solvers::LPSolveLinearApi limbo_solver_type; 69 | 70 | static void setDefaultParams(param_type & param) 71 | { 72 | param.setVerbose(2); // SERVE 73 | } 74 | static void setNumThreads(param_type &, std::uint32_t) {} 75 | }; 76 | 77 | #endif 78 | 79 | #ifndef LP_NOT_USE_GUROBI 80 | 81 | 82 | template 83 | struct _limbo_lp_api_gurobi 84 | { 85 | }; 86 | 87 | template 88 | struct _limbo_lp_api_trait<_limbo_lp_api_gurobi> 89 | { 90 | typedef coe_value_type value_type; 91 | typedef typename limbo::solvers::GurobiParameters param_type; 92 | typedef limbo::solvers::GurobiLinearApi limbo_solver_type; 93 | 94 | static void setDefaultParams(param_type &) {} 95 | static void setNumThreads(param_type ¶m, std::uint32_t numThreads) { param.setNumThreads(numThreads); } 96 | }; 97 | 98 | #endif 99 | 100 | template 101 | struct linear_programming_trait<_limbo_lp_solver> 102 | { 103 | typedef _limbo_lp_solver solver_type; 104 | typedef typename _limbo_lp_api_trait::value_type value_type; 105 | typedef typename solver_type::variable_type variable_type; 106 | typedef typename solver_type::expr_type expr_type; 107 | typedef typename solver_type::constr_type constr_type; 108 | typedef typename solver_type::status_type status_type; 109 | 110 | 111 | 112 | static variable_type addVar(solver_type &solver) 113 | { 114 | return solver._model.addVariable(0, 1e20, 115 | limbo::solvers::CONTINUOUS, 116 | "x" + solver._model.numVariables()); 117 | } 118 | static void addConstr(solver_type &solver, const constr_type &constr) 119 | { 120 | bool success = solver._model.addConstraint(constr, "CONSTR"); 121 | AssertMsg(success, "Limbo lib LP solver add constraint failed\n"); 122 | } 123 | static void setVarLowerBound(solver_type &solver, const variable_type &var, const value_type &val) 124 | { 125 | solver._model.updateVariableLowerBound(var, val); 126 | } 127 | static void setVarUpperBound(solver_type &solver, const variable_type &var, const value_type &val) 128 | { 129 | solver._model.updateVariableUpperBound(var, val); 130 | } 131 | static void setVarInteger(solver_type &solver, const variable_type &var) 132 | { 133 | solver._model.setVariableNumericType(var, limbo::solvers::INTEGER); 134 | } 135 | static void setVarContinuous(solver_type &solver, const variable_type &var) 136 | { 137 | solver._model.setVariableNumericType(var, limbo::solvers::CONTINUOUS); 138 | } 139 | static void setObjectiveMaximize(solver_type &solver) 140 | { 141 | solver._model.setOptimizeType(limbo::solvers::MAX); 142 | } 143 | static void setObjectiveMinimize(solver_type &solver) 144 | { 145 | solver._model.setOptimizeType(limbo::solvers::MIN); 146 | } 147 | static void setObjective(solver_type &solver, const expr_type &expr) 148 | { 149 | solver._model.setObjective(expr); 150 | } 151 | static void solve(solver_type &solver) 152 | { 153 | _limbo_lp_api_trait::setDefaultParams(solver._params); 154 | typename solver_type::limbo_solver_type sol(&solver._model); 155 | solver._status = sol(&solver._params); 156 | } 157 | static status_type status(solver_type &solver) 158 | { 159 | return solver._status; 160 | } 161 | static bool isOptimal(solver_type &solver) 162 | { 163 | return solver._status == limbo::solvers::OPTIMAL; 164 | } 165 | static bool isSuboptimal(solver_type &solver) 166 | { 167 | return solver._status == limbo::solvers::SUBOPTIMAL; 168 | } 169 | static bool isUnbounded(solver_type &solver) 170 | { 171 | return solver._status == limbo::solvers::UNBOUNDED; 172 | } 173 | static bool isInfeasible(solver_type &solver) 174 | { 175 | return solver._status == limbo::solvers::INFEASIBLE; 176 | } 177 | static value_type evaluateExpr(const solver_type &solver, const expr_type &expr) 178 | { 179 | return solver._model.evaluateExpression(expr, solver._model.variableSolutions()); 180 | } 181 | static value_type solution(const solver_type &solver, const variable_type &var) 182 | { 183 | return solver._model.variableSolution(var); 184 | } 185 | static std::string statusStr(const solver_type &solver) 186 | { 187 | return limbo::solvers::toString(solver._status); 188 | } 189 | static void setNumThreads(solver_type &solver, std::uint32_t numThreads) 190 | { 191 | _limbo_lp_api_trait::setNumThreads(solver._params, numThreads); 192 | } 193 | }; 194 | 195 | } //namespace _lp 196 | 197 | namespace _lp 198 | { 199 | #ifndef LP_NOT_USE_LPSOLVE 200 | typedef _lp::_limbo_lp_solver<_lp::_limbo_lp_api_lpsove> LimboLpsolve; ///< The lpsolve using limbo api. This one need to be constructed 201 | typedef _lp::linear_programming_trait LimboLpsolveTrait; ///< The lpsolve using limbo api. Don't construct it. Use its static methods as interface 202 | #endif 203 | #ifndef LP_NOT_USE_GUROBI 204 | typedef _lp::_limbo_lp_solver<_lp::_limbo_lp_api_gurobi> LimboLpGurobi; ///< The Gurobi using limbo api. This one need to be constructed 205 | typedef _lp::linear_programming_trait LimboLpGurobiTrait; ///< The Gurobi using limbo api. Don't construct it. Use its static methods as interface 206 | #endif 207 | } // namespace _lp 208 | 209 | } //namespace klib 210 | 211 | 212 | #endif //KLIB_LP_LIMBO_H_ 213 | --------------------------------------------------------------------------------