1 ///////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (c) 2020, The Regents of the University of California 4 // All rights reserved. 5 // 6 // BSD 3-Clause License 7 // 8 // Redistribution and use in source and binary forms, with or without 9 // modification, are permitted provided that the following conditions are met: 10 // 11 // * Redistributions of source code must retain the above copyright notice, this 12 // list of conditions and the following disclaimer. 13 // 14 // * Redistributions in binary form must reproduce the above copyright notice, 15 // this list of conditions and the following disclaimer in the documentation 16 // and/or other materials provided with the distribution. 17 // 18 // * Neither the name of the copyright holder nor the names of its 19 // contributors may be used to endorse or promote products derived from 20 // this software without specific prior written permission. 21 // 22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 26 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 // POSSIBILITY OF SUCH DAMAGE. 33 // 34 /////////////////////////////////////////////////////////////////////////////// 35 36 #pragma once 37 38 #include <QAbstractTableModel> 39 40 #include "gui/gui.h" 41 #include "opendb/db.h" 42 #include "opendb/dbBlockCallBackObj.h" 43 #include "sta/PathExpanded.hh" 44 #include "sta/PathRef.hh" 45 #include "sta/Sta.hh" 46 namespace odb { 47 class dbBlock; 48 class dbFill; 49 class dbInst; 50 class dbMaster; 51 class dbNet; 52 class dbITerm; 53 class dbWire; 54 class dbBTerm; 55 class dbBPin; 56 class dbBlockage; 57 class dbObstruction; 58 class dbRegion; 59 class dbRow; 60 class dbSWire; 61 } // namespace odb 62 namespace ord { 63 class OpenRoad; 64 } 65 namespace sta { 66 class Instance; 67 class Net; 68 class Pin; 69 } // namespace sta 70 namespace gui { 71 class TimingPathsModel; 72 class TimingPathNode; 73 class TimingPath; 74 class TimingPathDetailModel; 75 class GuiDBChangeListener; 76 77 class TimingPathsModel : public QAbstractTableModel 78 { 79 public: 80 TimingPathsModel(bool get_max = true, int path_count = 100); 81 ~TimingPathsModel(); 82 83 int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE; 84 int columnCount(const QModelIndex& parent 85 = QModelIndex()) const Q_DECL_OVERRIDE; 86 87 QVariant data(const QModelIndex& index, 88 int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; 89 QVariant headerData(int section, 90 Qt::Orientation orientation, 91 int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; 92 getPathAt(int index)93 TimingPath* getPathAt(int index) const { return timing_paths_[index]; } 94 95 void resetModel(); 96 void sort(int col_index, Qt::SortOrder sort_order) override; 97 void populateModel(bool get_max = true, int path_count = 100); 98 99 private: 100 bool populatePaths(bool get_max = true, int path_count = 100, bool clockExpanded = false); 101 102 ord::OpenRoad* openroad_; 103 std::vector<TimingPath*> timing_paths_; 104 105 static const std::vector<std::string> _path_columns; 106 enum Column : int; 107 }; 108 109 struct TimingPathNode 110 { TimingPathNodeTimingPathNode111 TimingPathNode(odb::dbObject* pin, 112 bool is_rising, 113 float arrival, 114 float required, 115 float delay, 116 float slack, 117 float slew, 118 float load) 119 : pin_(pin), 120 is_rising_(is_rising), 121 arrival_(arrival), 122 required_(required), 123 delay_(delay), 124 slack_(slack), 125 slew_(slew), 126 load_(load) 127 { 128 } 129 130 std::string getNodeName(bool include_master = false) const; 131 std::string getNetName() const; 132 133 odb::dbObject* pin_; 134 bool is_rising_; 135 float arrival_; 136 float required_; 137 float delay_; 138 float slack_; 139 float slew_; 140 float load_; 141 }; 142 143 class TimingPath 144 { 145 public: TimingPath(int path_index)146 TimingPath(int path_index) 147 : path_nodes_(), 148 start_clk_(), 149 end_clk_(), 150 slack_(0), 151 path_delay_(0), 152 arr_time_(0), 153 req_time_(0), 154 path_index_(path_index) 155 { 156 } 157 appendNode(const TimingPathNode & node)158 void appendNode(const TimingPathNode& node) { path_nodes_.push_back(node); } levelsCount()159 int levelsCount() const { return path_nodes_.size(); } setStartClock(const char * name)160 void setStartClock(const char* name) { start_clk_ = name; } getStartClock()161 std::string getStartClock() const { return start_clk_; } setEndClock(const char * name)162 void setEndClock(const char* name) { end_clk_ = name; } getEndClock()163 std::string getEndClock() const { return end_clk_; } 164 getPathArrivalTime()165 float getPathArrivalTime() const { return arr_time_; } setPathArrivalTime(float arr)166 void setPathArrivalTime(float arr) { arr_time_ = arr; } getPathRequiredTime()167 float getPathRequiredTime() const { return req_time_; } setPathRequiredTime(float req)168 void setPathRequiredTime(float req) { req_time_ = req; } getSlack()169 float getSlack() const { return slack_; } setSlack(float slack)170 void setSlack(float slack) { slack_ = slack; } getPathDelay()171 float getPathDelay() const { return path_delay_; } setPathDelay(float del)172 void setPathDelay(float del) { path_delay_ = del; } 173 getPathIndex()174 int getPathIndex() const { return path_index_; } 175 getNodeAt(int index)176 TimingPathNode getNodeAt(int index) const { return path_nodes_[index]; } 177 178 std::string getStartStageName() const; 179 std::string getEndStageName() const; 180 181 private: 182 std::vector<TimingPathNode> path_nodes_; 183 std::string start_clk_; 184 std::string end_clk_; 185 float slack_; 186 float path_delay_; 187 float arr_time_; 188 float req_time_; 189 int path_index_; 190 }; 191 192 class TimingPathDetailModel : public QAbstractTableModel 193 { 194 public: TimingPathDetailModel()195 TimingPathDetailModel() {} ~TimingPathDetailModel()196 ~TimingPathDetailModel() {} 197 198 int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE; 199 int columnCount(const QModelIndex& parent 200 = QModelIndex()) const Q_DECL_OVERRIDE; 201 202 QVariant data(const QModelIndex& index, 203 int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; 204 QVariant headerData(int section, 205 Qt::Orientation orientation, 206 int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; 207 208 void populateModel(TimingPath* path); 209 210 private: 211 TimingPath* path_; 212 // Unicode symbols 213 static const char* up_down_arrows; 214 static const char* up_arrow; 215 static const char* down_arrow; 216 static const std::vector<std::string> _path_details_columns; 217 enum Column : int; 218 }; 219 220 class TimingPathRenderer : public gui::Renderer 221 { 222 public: 223 TimingPathRenderer(); 224 ~TimingPathRenderer(); 225 void highlight(TimingPath* path); 226 227 void highlightNode(int node_id); 228 virtual void drawObjects(gui::Painter& /* painter */) override; 229 getPathToRender()230 TimingPath* getPathToRender() { return path_; } 231 232 private: 233 void highlightInst(odb::dbInst* inst, 234 gui::Painter& painter, 235 const gui::Painter::Color& color); 236 void highlightStage(gui::Painter& painter); 237 void highlightTerm(odb::dbBTerm* term, gui::Painter& painter); 238 void highlightNet(odb::dbNet* net, 239 odb::dbObject* source_node, 240 odb::dbObject* sink_node, 241 gui::Painter& painter); 242 243 // Expanded path is owned by PathRenderer. 244 TimingPath* path_; 245 246 int highlight_node_; 247 248 static gui::Painter::Color inst_highlight_color_; 249 static gui::Painter::Color path_inst_color_; 250 static gui::Painter::Color term_color_; 251 static gui::Painter::Color signal_color_; 252 static gui::Painter::Color clock_color_; 253 }; 254 255 class GuiDBChangeListener : public QObject, public odb::dbBlockCallBackObj 256 { 257 Q_OBJECT 258 public: GuiDBChangeListener()259 GuiDBChangeListener() : isDirty_(false) {} 260 inDbInstCreate(odb::dbInst * inst)261 void inDbInstCreate(odb::dbInst* inst) override 262 { 263 callback("inDbInstCreate", inst); 264 } inDbInstDestroy(odb::dbInst * inst)265 void inDbInstDestroy(odb::dbInst* inst) override 266 { 267 callback("inDbInstDestroy", inst); 268 } inDbInstSwapMasterBefore(odb::dbInst * inst,odb::dbMaster * master)269 void inDbInstSwapMasterBefore(odb::dbInst* inst, 270 odb::dbMaster* master) override 271 { 272 callback("inDbInstSwapMasterBefore", inst, master); 273 } inDbInstSwapMasterAfter(odb::dbInst * inst)274 void inDbInstSwapMasterAfter(odb::dbInst* inst) override 275 { 276 callback("inDbInstSwapMasterAfter", inst); 277 } inDbNetCreate(odb::dbNet * net)278 void inDbNetCreate(odb::dbNet* net) override 279 { 280 callback("inDbNetCreate", net); 281 } inDbNetDestroy(odb::dbNet * net)282 void inDbNetDestroy(odb::dbNet* net) override 283 { 284 callback("inDbNetDestroy", net); 285 } inDbITermPostConnect(odb::dbITerm * iterm)286 void inDbITermPostConnect(odb::dbITerm* iterm) override 287 { 288 callback("inDbITermPostConnect", iterm); 289 } inDbITermPreDisconnect(odb::dbITerm * iterm)290 void inDbITermPreDisconnect(odb::dbITerm* iterm) override 291 { 292 callback("inDbITermPreDisconnect", iterm); 293 } inDbITermDestroy(odb::dbITerm * iterm)294 void inDbITermDestroy(odb::dbITerm* iterm) override 295 { 296 callback("inDbITermDestroy", iterm); 297 } inDbBTermPostConnect(odb::dbBTerm * bterm)298 void inDbBTermPostConnect(odb::dbBTerm* bterm) override 299 { 300 callback("inDbBTermPostConnect", bterm); 301 } inDbBTermPreDisconnect(odb::dbBTerm * bterm)302 void inDbBTermPreDisconnect(odb::dbBTerm* bterm) override 303 { 304 callback("inDbBTermPreDisconnect", bterm); 305 } inDbBTermDestroy(odb::dbBTerm * bterm)306 void inDbBTermDestroy(odb::dbBTerm* bterm) override 307 { 308 callback("inDbBTermDestroy", bterm); 309 } inDbWireCreate(odb::dbWire * wire)310 void inDbWireCreate(odb::dbWire* wire) override 311 { 312 callback("inDbWireCreate", wire); 313 } inDbWireDestroy(odb::dbWire * wire)314 void inDbWireDestroy(odb::dbWire* wire) override 315 { 316 callback("inDbWireDestroy", wire); 317 } inDbBlockageCreate(odb::dbBlockage * blockage)318 void inDbBlockageCreate(odb::dbBlockage* blockage) override 319 { 320 callback("inDbBlockageCreate", blockage); 321 } inDbObstructionCreate(odb::dbObstruction * obstr)322 void inDbObstructionCreate(odb::dbObstruction* obstr) override 323 { 324 callback("inDbObstructionCreate", obstr); 325 } inDbObstructionDestroy(odb::dbObstruction * obstr)326 void inDbObstructionDestroy(odb::dbObstruction* obstr) override 327 { 328 callback("inDbObstructionDestroy", obstr); 329 } inDbBlockStreamOutAfter(odb::dbBlock * block)330 void inDbBlockStreamOutAfter(odb::dbBlock* block) override 331 { 332 callback("inDbBlockStreamOutAfter", block); 333 } inDbFillCreate(odb::dbFill * fill)334 void inDbFillCreate(odb::dbFill* fill) override 335 { 336 callback("inDbFillCreate", fill); 337 } 338 339 signals: 340 void dbUpdated(const QString& update_type, 341 const std::vector<odb::dbObject*>& update_objects); 342 public slots: reset()343 void reset() 344 { 345 isDirty_ = false; 346 // call reset after gui refresh 347 } 348 349 private: 350 void callback(QString update_type, 351 odb::dbObject* obj1 = nullptr, 352 odb::dbObject* obj2 = nullptr) 353 { 354 if (isDirty_ == false) { 355 // send signal if dirty was false 356 std::vector<odb::dbObject*> objects{obj1, obj2}; 357 emit dbUpdated(update_type, objects); 358 isDirty_ = true; 359 } 360 } 361 bool isDirty_; 362 }; 363 364 } // namespace gui 365