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