1 // OpenSTA, Static Timing Analyzer
2 // Copyright (c) 2021, Parallax Software, Inc.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
16 
17 #include "InputDrive.hh"
18 
19 namespace sta {
20 
InputDrive()21 InputDrive::InputDrive()
22 {
23   for (auto tr_index : RiseFall::rangeIndex()) {
24     for (auto mm_index : MinMax::rangeIndex())
25       drive_cells_[tr_index][mm_index] = nullptr;
26   }
27 }
28 
~InputDrive()29 InputDrive::~InputDrive()
30 {
31   for (auto tr_index : RiseFall::rangeIndex()) {
32     for (auto mm_index : MinMax::rangeIndex()) {
33       InputDriveCell *drive_cell = drive_cells_[tr_index][mm_index];
34       delete drive_cell;
35     }
36   }
37 }
38 
39 void
setSlew(const RiseFallBoth * rf,const MinMaxAll * min_max,float slew)40 InputDrive::setSlew(const RiseFallBoth *rf,
41 		    const MinMaxAll *min_max,
42 		    float slew)
43 {
44   slews_.setValue(rf, min_max, slew);
45 }
46 
47 void
setDriveResistance(const RiseFallBoth * rf,const MinMaxAll * min_max,float res)48 InputDrive::setDriveResistance(const RiseFallBoth *rf,
49 			       const MinMaxAll *min_max,
50 			       float res)
51 {
52   drive_resistances_.setValue(rf, min_max, res);
53 }
54 
55 void
driveResistance(const RiseFall * rf,const MinMax * min_max,float & res,bool & exists)56 InputDrive::driveResistance(const RiseFall *rf,
57 			    const MinMax *min_max,
58 			    float &res,
59 			    bool &exists)
60 {
61   drive_resistances_.value(rf, min_max, res, exists);
62 }
63 
64 bool
hasDriveResistance(const RiseFall * rf,const MinMax * min_max)65 InputDrive::hasDriveResistance(const RiseFall *rf, const MinMax *min_max)
66 {
67   return drive_resistances_.hasValue(rf, min_max);
68 }
69 
70 bool
driveResistanceMinMaxEqual(const RiseFall * rf)71 InputDrive::driveResistanceMinMaxEqual(const RiseFall *rf)
72 {
73   float min_res, max_res;
74   bool min_exists, max_exists;
75   drive_resistances_.value(rf, MinMax::min(), min_res, min_exists);
76   drive_resistances_.value(rf, MinMax::max(), max_res, max_exists);
77   return min_exists && max_exists && min_res == max_res;
78 }
79 
80 void
setDriveCell(LibertyLibrary * library,LibertyCell * cell,LibertyPort * from_port,float * from_slews,LibertyPort * to_port,const RiseFallBoth * rf,const MinMaxAll * min_max)81 InputDrive::setDriveCell(LibertyLibrary *library,
82 			 LibertyCell *cell,
83 			 LibertyPort *from_port,
84 			 float *from_slews,
85 			 LibertyPort *to_port,
86 			 const RiseFallBoth *rf,
87 			 const MinMaxAll *min_max)
88 {
89   for (auto rf_index : rf->rangeIndex()) {
90     for (auto mm_index : min_max->rangeIndex()) {
91       InputDriveCell *drive = drive_cells_[rf_index][mm_index];
92       if (drive) {
93 	drive->setLibrary(library);
94 	drive->setCell(cell);
95 	drive->setFromPort(from_port);
96 	drive->setFromSlews(from_slews);
97 	drive->setToPort(to_port);
98       }
99       else {
100 	drive = new InputDriveCell(library, cell, from_port,
101 				   from_slews, to_port);
102 	drive_cells_[rf_index][mm_index] = drive;
103       }
104     }
105   }
106 }
107 
108 void
driveCell(const RiseFall * rf,const MinMax * min_max,LibertyCell * & cell,LibertyPort * & from_port,float * & from_slews,LibertyPort * & to_port)109 InputDrive::driveCell(const RiseFall *rf,
110 		      const MinMax *min_max,
111 		      LibertyCell *&cell,
112 		      LibertyPort *&from_port,
113 		      float *&from_slews,
114 		      LibertyPort *&to_port)
115 {
116   InputDriveCell *drive = drive_cells_[rf->index()][min_max->index()];
117   if (drive) {
118     cell = drive->cell();
119     from_port = drive->fromPort();
120     from_slews = drive->fromSlews();
121     to_port = drive->toPort();
122   }
123   else
124     cell = nullptr;
125 }
126 
127 InputDriveCell *
driveCell(const RiseFall * rf,const MinMax * min_max)128 InputDrive::driveCell(const RiseFall *rf,
129 		      const MinMax *min_max)
130 {
131   return drive_cells_[rf->index()][min_max->index()];
132 }
133 
134 bool
hasDriveCell(const RiseFall * rf,const MinMax * min_max)135 InputDrive::hasDriveCell(const RiseFall *rf,
136 			 const MinMax *min_max)
137 {
138   return drive_cells_[rf->index()][min_max->index()] != nullptr;
139 }
140 
141 bool
driveCellsEqual()142 InputDrive::driveCellsEqual()
143 {
144   int rise_index = RiseFall::riseIndex();
145   int fall_index = RiseFall::fallIndex();
146   int min_index = MinMax::minIndex();
147   int max_index = MinMax::maxIndex();
148   InputDriveCell *drive1 = drive_cells_[rise_index][min_index];
149   InputDriveCell *drive2 = drive_cells_[rise_index][max_index];
150   InputDriveCell *drive3 = drive_cells_[fall_index][min_index];
151   InputDriveCell *drive4 = drive_cells_[fall_index][max_index];
152   return drive1->equal(drive2)
153     && drive1->equal(drive3)
154     && drive1->equal(drive4);
155 }
156 
157 void
slew(const RiseFall * rf,const MinMax * min_max,float & slew,bool & exists)158 InputDrive::slew(const RiseFall *rf,
159 		 const MinMax *min_max,
160 		 float &slew,
161 		 bool &exists)
162 {
163   slews_.value(rf, min_max, slew, exists);
164 }
165 
166 ////////////////////////////////////////////////////////////////
167 
InputDriveCell(LibertyLibrary * library,LibertyCell * cell,LibertyPort * from_port,float * from_slews,LibertyPort * to_port)168 InputDriveCell::InputDriveCell(LibertyLibrary *library,
169 			       LibertyCell *cell,
170 			       LibertyPort *from_port,
171 			       float *from_slews,
172 			       LibertyPort *to_port) :
173   library_(library),
174   cell_(cell),
175   from_port_(from_port),
176   to_port_(to_port)
177 {
178   setFromSlews(from_slews);
179 }
180 
181 void
setLibrary(LibertyLibrary * library)182 InputDriveCell::setLibrary(LibertyLibrary *library)
183 {
184   library_ = library;
185 }
186 
187 void
setCell(LibertyCell * cell)188 InputDriveCell::setCell(LibertyCell *cell)
189 {
190   cell_ = cell;
191 }
192 
193 void
setFromPort(LibertyPort * from_port)194 InputDriveCell::setFromPort(LibertyPort *from_port)
195 {
196   from_port_ = from_port;
197 }
198 
199 void
setToPort(LibertyPort * to_port)200 InputDriveCell::setToPort(LibertyPort *to_port)
201 {
202   to_port_ = to_port;
203 }
204 
205 void
setFromSlews(float * from_slews)206 InputDriveCell::setFromSlews(float *from_slews)
207 {
208   for (auto tr_index : RiseFall::rangeIndex())
209     from_slews_[tr_index] = from_slews[tr_index];
210 }
211 
212 bool
equal(InputDriveCell * drive) const213 InputDriveCell::equal(InputDriveCell *drive) const
214 {
215   int rise_index = RiseFall::riseIndex();
216   int fall_index = RiseFall::fallIndex();
217   return cell_ == drive->cell_
218     && from_port_ == drive->from_port_
219     && from_slews_[rise_index] == drive->from_slews_[rise_index]
220     && from_slews_[fall_index] == drive->from_slews_[fall_index]
221     && to_port_ == drive->to_port_;
222 }
223 
224 } // namespace
225