OdbDesignLib
OdbDesign ODB++ Parsing Library
 
Loading...
Searching...
No Matches
NetlistFile.cpp
1#include "NetlistFile.h"
2#include "NetlistFile.h"
3#include <Logger.h>
4#include "../parse_error.h"
5#include "../invalid_odb_error.h"
6#include <climits>
7#include <filesystem>
8#include <ostream>
9#include "../../Constants.h"
10#include <exception>
11#include <cctype>
12#include <iosfwd>
13#include <memory>
14#include <string>
15#include "../parse_info.h"
16#include "netlistfile.pb.h"
17
18using namespace std::filesystem;
19
20namespace Odb::Lib::FileModel::Design
21{
22 NetlistFile::NetlistFile(std::filesystem::path path)
23 : m_path(path)
24 , m_optimized(false)
25 , m_staggered(Staggered::Unknown)
26 {
27 }
28
29 NetlistFile::~NetlistFile()
30 {
31 m_netRecords.clear();
32 m_netRecordsByName.clear();
33 m_netPointRecords.clear();
34 }
35
36 std::filesystem::path NetlistFile::GetPath() const
37 {
38 return m_path;
39 }
40
41 std::string NetlistFile::GetName() const
42 {
43 return m_name;
44 }
45
46 std::string NetlistFile::GetUnits() const
47 {
48 return m_units;
49 }
50
51 bool NetlistFile::GetOptimized() const
52 {
53 return m_optimized;
54 }
55
56 NetlistFile::Staggered NetlistFile::GetStaggered() const
57 {
58 return m_staggered;
59 }
60
61 const NetlistFile::NetRecord::Vector& NetlistFile::GetNetRecords() const
62 {
63 return m_netRecords;
64 }
65
66 const NetlistFile::NetRecord::StringMap& NetlistFile::GetNetRecordsByName() const
67 {
68 return m_netRecordsByName;
69 }
70
71 const NetlistFile::NetPointRecord::Vector& NetlistFile::GetNetPointRecords() const
72 {
73 return m_netPointRecords;
74 }
75
76 bool NetlistFile::Parse()
77 {
78 std::ifstream netlistFile;
79 int lineNumber = 0;
80 std::string line;
81
82 try
83 {
84 m_name = std::filesystem::path(m_path).filename().string();
85
86 loginfo("Parsing netlist: " + m_name + "...");
87
88 auto netlistFilePath = m_path / "netlist";
89
90 if (!std::filesystem::exists(netlistFilePath))
91 {
92 auto message = "netlist file does not exist: [" + m_path.string() + "]";
93 throw invalid_odb_error(message.c_str());
94 }
95
96 else if (!std::filesystem::is_regular_file(netlistFilePath))
97 {
98 auto message = "netlist file is not a file: [" + m_path.string() + "]";
99 throw invalid_odb_error(message.c_str());
100 }
101
102 netlistFile.open(netlistFilePath.string(), std::ios::in);
103 if (!netlistFile.is_open())
104 {
105 auto message = "unable to open netlist file: [" + m_path.string() + "]";
106 throw invalid_odb_error(message.c_str());
107 }
108
109 while (std::getline(netlistFile, line))
110 {
111 lineNumber++;
112 if (!line.empty())
113 {
114 std::stringstream lineStream(line);
115
116 if (line.find(Constants::COMMENT_TOKEN) == 0)
117 {
118 // comment line
119 }
120 else if (line.find(Constants::UNITS_TOKEN) == 0)
121 {
122 // units line
123 std::string token;
124 if (!std::getline(lineStream, token, '='))
125 {
126 throw_parse_error(m_path, line, token, lineNumber);
127 }
128 else if (!std::getline(lineStream, token, '='))
129 {
130 throw_parse_error(m_path, line, token, lineNumber);
131 }
132 m_units = token;
133 }
134 else if (line.find(HEADER_TOKEN) == 0)
135 {
136 // header line
137 std::string token;
138
139 // H (throw away
140 lineStream >> token;
141
142 // optimize(d)
143 lineStream >> token;
144 if (token != "optimize")
145 {
146 throw_parse_error(m_path, line, token, lineNumber);
147 }
148
149 char optimized;
150 if (!(lineStream >> optimized))
151 {
152 throw_parse_error(m_path, line, token, lineNumber);
153 }
154
155 if (optimized == 'Y' || std::tolower(optimized) == 'y')
156 {
157 m_optimized = true;
158 }
159 else if (optimized == 'N' || std::tolower(optimized) == 'n')
160 {
161 m_optimized = false;
162 }
163 else
164 {
165 throw_parse_error(m_path, line, token, lineNumber);
166 }
167
168 // staggered (optional)
169 if (lineStream >> token && token == STAGGERED_KEY)
170 {
171 char staggered;
172 if (!(lineStream >> staggered))
173 {
174 throw_parse_error(m_path, line, token, lineNumber);
175 }
176
177 if (staggered == 'Y' || std::tolower(staggered) == 'y')
178 {
179 m_staggered = Staggered::Yes;
180 }
181 else if (staggered == 'N' || std::tolower(staggered) == 'n')
182 {
183 m_staggered = Staggered::No;
184 }
185 else
186 {
187 throw_parse_error(m_path, line, token, lineNumber);
188 }
189 }
190 else
191 {
192 m_staggered = Staggered::Unknown;
193 }
194 }
195 else if (line.find(NetRecord::FIELD_TOKEN) == 0)
196 {
197 // net record line
198
199 // net serial number
200 std::string token;
201 if (!(lineStream >> token))
202 {
203 throw_parse_error(m_path, line, token, lineNumber);
204 }
205
206 auto strSerialNumber = token;
207 strSerialNumber.erase(0, 1); // remove leading '$'
208 auto ulSerialNumber = std::stoul(strSerialNumber);
209 if (ulSerialNumber > UINT_MAX)
210 {
211 throw_parse_error(m_path, line, token, lineNumber);
212 }
213
214 auto unSerialNumber = static_cast<unsigned int>(ulSerialNumber);
215
216 // net name
217 if (!(lineStream >> token))
218 {
219 throw_parse_error(m_path, line, token, lineNumber);
220 }
221
222 auto& netName = token;
223
224 auto pNetRecord = std::make_shared<NetRecord>();
225 pNetRecord->serialNumber = unSerialNumber;
226 pNetRecord->netName = netName;
227 m_netRecords.push_back(pNetRecord);
228 //m_netRecordsByName[pNetRecord->netName] = pNetRecord;
229 }
230 else // NetPointRecord (starts with an unsigned int, netNumber)
231 {
232 std::string token;
233 if (!(lineStream >> token))
234 {
235 throw_parse_error(m_path, line, token, lineNumber);
236 }
237
238 auto ulNetNumber = std::stoul(token);
239 if (ulNetNumber >= UINT_MAX)
240 {
241 throw_parse_error(m_path, line, token, lineNumber);
242 }
243
244 auto unNetNumber = static_cast<unsigned int>(ulNetNumber);
245
246 auto pNetPointRecord = std::make_shared<NetPointRecord>();
247 pNetPointRecord->netNumber = unNetNumber;
248
249 if (!(lineStream >> pNetPointRecord->radius))
250 {
251 throw_parse_error(m_path, line, token, lineNumber);
252 }
253
254 if (!(lineStream >> pNetPointRecord->x))
255 {
256 throw_parse_error(m_path, line, token, lineNumber);
257 }
258
259 if (!(lineStream >> pNetPointRecord->y))
260 {
261 throw_parse_error(m_path, line, token, lineNumber);
262 }
263
264 // TODO: parse the rest of the NetPointRecord fields
265
266 m_netPointRecords.push_back(pNetPointRecord);
267 }
268 }
269 }
270
271 loginfo("Parsing netlist: " + m_name + " complete");
272
273 netlistFile.close();
274 }
275 catch (parse_error& pe)
276 {
277 auto m = pe.toString("Parse Error:");
278 logerror(m);
279 // cleanup file
280 netlistFile.close();
281 throw pe;
282
283 }
284 catch (std::exception& e)
285 {
286 parse_info pi(m_path, line, lineNumber);
287 const auto m = pi.toString();
288 logexception_msg(e, m);
289 netlistFile.close();
290 throw e;
291 }
292
293 return true;
294 }
295
296 std::unique_ptr<Protobuf::NetlistFile> NetlistFile::to_protobuf() const
297 {
298 std::unique_ptr<Protobuf::NetlistFile> pNetlistFileMessage(new Protobuf::NetlistFile);
299 pNetlistFileMessage->set_units(m_units);
300 pNetlistFileMessage->set_path(m_path.string());
301 pNetlistFileMessage->set_name(m_name);
302 pNetlistFileMessage->set_optimized(m_optimized);
303 pNetlistFileMessage->set_staggered(static_cast<Protobuf::NetlistFile::Staggered>(m_staggered));
304
305 for (const auto& pNetRecord : m_netRecords)
306 {
307 auto pNetRecordMessage = pNetRecord->to_protobuf();
308 pNetlistFileMessage->add_netrecordss()->CopyFrom(*pNetRecordMessage);
309 }
310
311 for (const auto& kvNetRecord : m_netRecordsByName)
312 {
313 (*pNetlistFileMessage->mutable_netrecordsbyname())[kvNetRecord.first] = *kvNetRecord.second->to_protobuf();
314 }
315
316 for (const auto& pNetPointRecord : m_netPointRecords)
317 {
318 auto pNetPointRecordMessage = pNetPointRecord->to_protobuf();
319 pNetlistFileMessage->add_netpointrecords()->CopyFrom(*pNetPointRecordMessage);
320 }
321
322 return pNetlistFileMessage;
323 }
324
325 void NetlistFile::from_protobuf(const Protobuf::NetlistFile& message)
326 {
327 m_name = message.name();
328 m_path = message.path();
329 m_units = message.units();
330 m_optimized = message.optimized();
331 m_staggered = static_cast<Staggered>(message.staggered());
332
333 for (const auto& netRecordMessage : message.netrecordss())
334 {
335 auto pNetRecord = std::make_shared<NetRecord>();
336 pNetRecord->from_protobuf(netRecordMessage);
337 m_netRecords.push_back(pNetRecord);
338 }
339
340 for (const auto& kvNetRecord : message.netrecordsbyname())
341 {
342 auto pNetRecord = std::make_shared<NetRecord>();
343 pNetRecord->from_protobuf(kvNetRecord.second);
344 m_netRecordsByName[pNetRecord->netName] = pNetRecord;
345 }
346
347 for (const auto& netPointRecordMessage : message.netpointrecords())
348 {
349 auto pNetPointRecord = std::make_shared<NetPointRecord>();
350 pNetPointRecord->from_protobuf(netPointRecordMessage);
351 m_netPointRecords.push_back(pNetPointRecord);
352 }
353 }
354
355 bool NetlistFile::Save(std::ostream& os)
356 {
357 os << 'H' << " optimize " << (m_optimized ? 'Y' : 'N') << "staggered " << (m_staggered == Staggered::Yes ? 'Y' : 'N') << std::endl;
358 os << Constants::UNITS_TOKEN << " = " << m_units << std::endl;
359
360 for (const auto& netRecord : m_netRecords)
361 {
362 os << NetRecord::FIELD_TOKEN << netRecord->serialNumber << " " << netRecord->netName << std::endl;
363 }
364
365 for (const auto& netPointRecord : m_netPointRecords)
366 {
367 netPointRecord->Save(os);
368 os << std::endl;
369 }
370
371 return true;
372 }
373
374 bool NetlistFile::Save(const std::filesystem::path& directory)
375 {
376 auto netlistDir = directory / m_name;
377 if (!create_directory(netlistDir)) return false;
378
379 std::ofstream netlistFile(netlistDir / "netlist");
380 if (!netlistFile.is_open()) return false;
381 if (! Save(netlistFile)) return false;
382 netlistFile.close();
383
384 return true;
385 }
386
387 std::unique_ptr<Protobuf::NetlistFile::NetRecord> NetlistFile::NetRecord::to_protobuf() const
388 {
389 std::unique_ptr<Protobuf::NetlistFile::NetRecord> pNetRecordMessage(new Protobuf::NetlistFile::NetRecord);
390 pNetRecordMessage->set_serialnumber(serialNumber);
391 pNetRecordMessage->set_netname(netName);
392 return pNetRecordMessage;
393 }
394
395 void NetlistFile::NetRecord::from_protobuf(const Protobuf::NetlistFile::NetRecord& message)
396 {
397 serialNumber = message.serialnumber();
398 netName = message.netname();
399 }
400
401 std::unique_ptr<Protobuf::NetlistFile::NetPointRecord> NetlistFile::NetPointRecord::to_protobuf() const
402 {
403 std::unique_ptr<Protobuf::NetlistFile::NetPointRecord> pNetPointRecordMessage(new Protobuf::NetlistFile::NetPointRecord);
404 pNetPointRecordMessage->set_netnumber(netNumber);
405 pNetPointRecordMessage->set_radius(radius);
406 pNetPointRecordMessage->set_x(x);
407 pNetPointRecordMessage->set_y(y);
408 pNetPointRecordMessage->set_epoint(std::to_string(epoint));
409 pNetPointRecordMessage->set_width(width);
410 pNetPointRecordMessage->set_exp(std::to_string(exp));
411 pNetPointRecordMessage->set_fiducialpoint(fiducialPoint);
412 pNetPointRecordMessage->set_height(height);
413 pNetPointRecordMessage->set_commentpoint(commentPoint);
414 pNetPointRecordMessage->set_netnumber(netNumber);
415 pNetPointRecordMessage->set_side(static_cast<Protobuf::NetlistFile::NetPointRecord::AccessSide>(side));
416 pNetPointRecordMessage->set_staggeredradius(staggeredRadius);
417 pNetPointRecordMessage->set_staggeredx(staggeredX);
418 pNetPointRecordMessage->set_staggeredy(staggeredY);
419 pNetPointRecordMessage->set_testexecutionside(std::to_string(testExecutionSide));
420 pNetPointRecordMessage->set_testpoint(testPoint);
421 pNetPointRecordMessage->set_viapoint(viaPoint);
422 pNetPointRecordMessage->set_fiducialpoint(fiducialPoint);
423 return pNetPointRecordMessage;
424 }
425
426 void NetlistFile::NetPointRecord::from_protobuf(const Protobuf::NetlistFile::NetPointRecord& message)
427 {
428 netNumber = message.netnumber();
429 radius = message.radius();
430 x = message.x();
431 y = message.y();
432 if (message.epoint().empty())
433 {
434 epoint = message.epoint()[0];
435 }
436 width = message.width();
437 if (!message.exp().empty())
438 {
439 exp = message.exp()[0];
440 }
441 fiducialPoint = message.fiducialpoint();
442 height = message.height();
443 commentPoint = message.commentpoint();
444 netNumber = message.netnumber();
445 side = static_cast<AccessSide>(message.side());
446 staggeredRadius = message.staggeredradius();
447 staggeredX = message.staggeredx();
448 staggeredY = message.staggeredy();
449 if (!message.testexecutionside().empty())
450 {
451 testExecutionSide = message.testexecutionside()[0];
452 }
453 testPoint = message.testpoint();
454 viaPoint = message.viapoint();
455 fiducialPoint = message.fiducialpoint();
456 }
457
458 bool NetlistFile::NetPointRecord::Save(std::ostream& os)
459 {
460 return false;
461 }
462
463} // namespace Odb::Lib::FileModel::Design