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