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 // This file illustratates how to customize the liberty file reader to
18 // read attributes that are not used by the STA.  In this example:
19 //  * code is called at the beginning of a library definition
20 //  * a string attribute named "thingy" is parsed
21 
22 #include <stdio.h>
23 #include "Machine.hh"
24 #include "StringUtil.hh"
25 #include "LibertyReader.hh"
26 #include "LibertyReaderPvt.hh"
27 #include "LibertyBuilder.hh"
28 #include "Network.hh"
29 #include "ConcreteNetwork.hh"
30 #include "Sta.hh"
31 
32 // Import symbols from sta package (this example is in the global package).
33 using sta::Report;
34 using sta::Debug;
35 using sta::Network;
36 using sta::LibertyReader;
37 using sta::LibertyAttr;
38 using sta::LibertyGroup;
39 using sta::TimingGroup;
40 using sta::LibertyCell;
41 using sta::LibertyPort;
42 using sta::LibertyLibrary;
43 using sta::TimingArcSet;
44 using sta::LibertyBuilder;
45 using sta::TimingRole;
46 using sta::TimingArcAttrs;
47 using sta::Sta;
48 using sta::stringCopy;
49 
50 // LibertyCell with Bigco thingy variable.
51 class BigcoCell : public LibertyCell
52 {
53 public:
54   BigcoCell(LibertyLibrary *library, const char *name, const char *filename);
55   void setThingy(const char *thingy);
56 
57 protected:
58   const char *thingy_;
59 };
60 
BigcoCell(LibertyLibrary * library,const char * name,const char * filename)61 BigcoCell::BigcoCell(LibertyLibrary *library, const char *name,
62 		     const char *filename) :
63   LibertyCell(library, name, filename),
64   thingy_(0)
65 {
66 }
67 
68 void
setThingy(const char * thingy)69 BigcoCell::setThingy(const char *thingy)
70 {
71   thingy_ = thingy;
72 }
73 
74 ////////////////////////////////////////////////////////////////
75 
76 class BigcoTimingGroup : public TimingGroup
77 {
78 public:
79   BigcoTimingGroup(int line);
frob() const80   const char *frob() const { return frob_; }
81   void setFrob(const char *frob);
82 
83 protected:
84   const char *frob_;
85 };
86 
BigcoTimingGroup(int line)87 BigcoTimingGroup::BigcoTimingGroup(int line) :
88   TimingGroup(line),
89   frob_(0)
90 {
91 }
92 
93 void
setFrob(const char * frob)94 BigcoTimingGroup::setFrob(const char *frob)
95 {
96   frob_ = frob;
97 }
98 
99 ////////////////////////////////////////////////////////////////
100 
101 class BigcoTimingArcSet : public TimingArcSet
102 {
103 public:
104   BigcoTimingArcSet(LibertyCell *cell, LibertyPort *from, LibertyPort *to,
105 		    LibertyPort *related_out, TimingRole *role,
106 		    TimingArcAttrs *attrs);
107 
108 protected:
109   const char *frob_;
110 };
111 
BigcoTimingArcSet(LibertyCell * cell,LibertyPort * from,LibertyPort * to,LibertyPort * related_out,TimingRole * role,TimingArcAttrs * attrs)112 BigcoTimingArcSet::BigcoTimingArcSet(LibertyCell *cell, LibertyPort *from,
113 				     LibertyPort *to,
114 				     LibertyPort *related_out, TimingRole *role,
115 				     TimingArcAttrs *attrs) :
116   TimingArcSet(cell, from, to, related_out, role, attrs)
117 {
118   const char *frob = static_cast<BigcoTimingGroup*>(attrs)->frob();
119   if (frob)
120     frob_ = stringCopy(frob);
121 }
122 
123 ////////////////////////////////////////////////////////////////
124 
125 // Make Bigco objects instead of Liberty objects.
126 class BigcoLibertyBuilder : public LibertyBuilder
127 {
128 public:
129   virtual LibertyCell *makeCell(LibertyLibrary *library, const char *name,
130 				const char *filename);
131 
132 protected:
133   virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell, LibertyPort *from,
134 					 LibertyPort *to,
135 					 LibertyPort *related_out,
136 					 TimingRole *role,
137 					 TimingArcAttrs *attrs);
138 };
139 
140 LibertyCell *
makeCell(LibertyLibrary * library,const char * name,const char * filename)141 BigcoLibertyBuilder::makeCell(LibertyLibrary *library, const char *name,
142 			      const char *filename)
143 {
144   LibertyCell *cell = new BigcoCell(library, name, filename);
145   library->addCell(cell);
146   return cell;
147 }
148 
149 TimingArcSet *
makeTimingArcSet(LibertyCell * cell,LibertyPort * from,LibertyPort * to,LibertyPort * related_out,TimingRole * role,TimingArcAttrs * attrs)150 BigcoLibertyBuilder::makeTimingArcSet(LibertyCell *cell, LibertyPort *from,
151 				      LibertyPort *to,
152 				      LibertyPort *related_out,
153 				      TimingRole *role,
154 				      TimingArcAttrs *attrs)
155 {
156   return new BigcoTimingArcSet(cell, from, to, related_out, role, attrs);
157 }
158 
159 ////////////////////////////////////////////////////////////////
160 
161 // Liberty reader to parse Bigco attributes.
162 class BigcoLibertyReader : public LibertyReader
163 {
164 public:
165   BigcoLibertyReader(LibertyBuilder *builder);
166 
167 protected:
168   virtual void visitAttr1(LibertyAttr *attr);
169   virtual void visitAttr2(LibertyAttr *attr);
170   virtual void beginLibrary(LibertyGroup *group);
171   virtual TimingGroup *makeTimingGroup(int line);
172   virtual void beginCell(LibertyGroup *group);
173 };
174 
BigcoLibertyReader(LibertyBuilder * builder)175 BigcoLibertyReader::BigcoLibertyReader(LibertyBuilder *builder) :
176   LibertyReader(builder)
177 {
178   // Define a visitor for the "thingy" attribute.
179   // Note that the function descriptor passed to defineAttrVisitor
180   // must be defined by the LibertyVisitor class, so a number of
181   // extra visitor functions are pre-defined for extensions.
182   defineAttrVisitor("thingy", &LibertyReader::visitAttr1);
183   defineAttrVisitor("frob", &LibertyReader::visitAttr2);
184 }
185 
186 bool
libertyCellRequired(const char *)187 libertyCellRequired(const char *)
188 {
189   // Predicate for cell names.
190   return true;
191 }
192 
193 // Prune cells from liberty file based on libertyCellRequired predicate.
194 void
beginCell(LibertyGroup * group)195 BigcoLibertyReader::beginCell(LibertyGroup *group)
196 {
197   const char *name = group->firstName();
198   if (name
199       && libertyCellRequired(name))
200     LibertyReader::beginCell(group);
201 }
202 
203 TimingGroup *
makeTimingGroup(int line)204 BigcoLibertyReader::makeTimingGroup(int line)
205 {
206   return new BigcoTimingGroup(line);
207 }
208 
209 // Called at the beginning of a library group.
210 void
beginLibrary(LibertyGroup * group)211 BigcoLibertyReader::beginLibrary(LibertyGroup *group)
212 {
213   LibertyReader::beginLibrary(group);
214   // Do Bigco stuff here.
215   printf("Bigco was here.\n");
216 }
217 
218 void
visitAttr1(LibertyAttr * attr)219 BigcoLibertyReader::visitAttr1(LibertyAttr *attr)
220 {
221   const char *thingy = getAttrString(attr);
222   if (thingy) {
223     printf("Bigco thingy attribute value is %s.\n", thingy);
224     if (cell_)
225       static_cast<BigcoCell*>(cell_)->setThingy(thingy);
226   }
227 }
228 
229 void
visitAttr2(LibertyAttr * attr)230 BigcoLibertyReader::visitAttr2(LibertyAttr *attr)
231 {
232   const char *frob = getAttrString(attr);
233   if (frob) {
234     if (timing_)
235       static_cast<BigcoTimingGroup*>(timing_)->setFrob(frob);
236   }
237 }
238 
239 ////////////////////////////////////////////////////////////////
240 
241 // Define a BigcoSta class derived from the Sta class to install the
242 // new liberty reader/visitor in BigcoSta::makeLibertyReader.
243 class BigcoSta : public Sta
244 {
245 public:
246   BigcoSta();
247 
248 protected:
249   virtual LibertyLibrary *readLibertyFile(const char *filename,
250 					  bool infer_latches,
251 					  Network *network);
252 };
253 
BigcoSta()254 BigcoSta::BigcoSta() :
255   Sta()
256 {
257 }
258 
259 // Replace Sta liberty file reader with Bigco's very own.
260 LibertyLibrary *
readLibertyFile(const char * filename,bool infer_latches,Network * network)261 Sta::readLibertyFile(const char *filename,
262 		bool infer_latches,
263 		     Network *network)
264 {
265   BigcoLibertyBuilder builder;
266   BigcoLibertyReader reader(&builder);
267   return reader.readLibertyFile(filename, infer_latches, network);
268 }
269