OdbDesignLib
OdbDesign ODB++ Parsing Library
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 "../../ProtoBuf/netlistfile.pb.h"
17 
18 using namespace std::filesystem;
19 
20 namespace 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