HAL
simplification_abc.cpp
Go to the documentation of this file.
2 
3 #include <boost/fusion/include/at_c.hpp>
4 #include <boost/fusion/sequence/intrinsic/at_c.hpp>
5 #include <boost/spirit/home/x3.hpp>
6 #include <mutex>
7 #include <sstream>
8 #include <string>
9 
10 extern "C" {
25 
27 // Type Defintions
29 
31 typedef enum
32 {
33  ABC_FUNC_NONE = 0, // 0: unknown
34  ABC_FUNC_SOP, // 1: sum-of-products
35  ABC_FUNC_BDD, // 2: binary decision diagrams
36  ABC_FUNC_AIG, // 3: and-inverter graphs
37  ABC_FUNC_MAP, // 4: standard cell library
38  ABC_FUNC_BLIFMV, // 5: BLIF-MV node functions
39  ABC_FUNC_BLACKBOX, // 6: black box about which nothing is known
40  ABC_FUNC_OTHER // 7: unused
42 
44 typedef enum
45 {
46  ABC_NTK_NONE = 0, // 0: unknown
47  ABC_NTK_NETLIST, // 1: network with PIs/POs, latches, nodes, and nets
48  ABC_NTK_LOGIC, // 2: network with PIs/POs, latches, and nodes
49  ABC_NTK_STRASH, // 3: structurally hashed AIG (two input AND gates with c-attributes on edges)
50  ABC_NTK_OTHER // 4: unused
52 
54 typedef enum
55 {
56  ABC_OBJ_NONE = 0, // 0: unknown
57  ABC_OBJ_CONST1, // 1: constant 1 node (AIG only)
58  ABC_OBJ_PI, // 2: primary input terminal
59  ABC_OBJ_PO, // 3: primary output terminal
60  ABC_OBJ_BI, // 4: box input terminal
61  ABC_OBJ_BO, // 5: box output terminal
62  ABC_OBJ_NET, // 6: net
63  ABC_OBJ_NODE, // 7: node
64  ABC_OBJ_LATCH, // 8: latch
65  ABC_OBJ_WHITEBOX, // 9: box with known contents
66  ABC_OBJ_BLACKBOX, // 10: box with unknown contents
67  ABC_OBJ_NUMBER // 11: unused
69 
71 typedef enum
72 {
73  AIG_NONE, // 0: non-existent object
74  AIG_CONST1, // 1: constant 1
75  AIG_PI, // 2: primary input
76  AIG_PO, // 3: primary output
77  AIG_AND, // 4: AND node
78  AIG_EXOR, // 5: EXOR node
79  AIG_VOID // 6: unused object
81 
83 typedef struct Vec_Ptr_t_ Vec_Ptr_t;
84 struct Vec_Ptr_t_
85 {
86  int nCap;
87  int nSize;
88  void** pArray;
89 };
90 
92 typedef struct Vec_Int_t_ Vec_Int_t;
93 struct Vec_Int_t_
94 {
95  int nCap;
96  int nSize;
97  int* pArray;
98 };
99 
101 typedef struct Vec_Vec_t_ Vec_Vec_t;
103 {
104  int nCap;
105  int nSize;
106  void** pArray;
107 };
108 
111 typedef struct Nm_Man_t_ Nm_Man_t;
112 typedef struct Abc_Des_t_ Abc_Des_t;
113 typedef struct Mem_Fixed_t_ Mem_Fixed_t;
114 typedef struct Mem_Step_t_ Mem_Step_t;
115 typedef struct Abc_ManTime_t_ Abc_ManTime_t;
116 typedef struct Abc_Aig_t_ Abc_Aig_t;
117 typedef struct Abc_Cex_t_ Abc_Cex_t;
118 typedef struct st__table st__table;
119 typedef struct Gia_Man_t_ Gia_Man_t;
120 typedef struct Abc_Nam_t_ Abc_Nam_t;
121 typedef struct Dsd_Manager_t_ DdManager;
122 typedef void (*Abc_Frame_Callback_BmcFrameDone_Func)(int, int, int);
123 typedef struct Vec_Wec_t_ Vec_Wec_t;
124 typedef int64_t abctime;
125 
127 typedef struct Hop_Obj_t_ Hop_Obj_t;
128 struct Hop_Obj_t_ // 6 words
129 {
130  union
131  {
132  void* pData; // misc
133  int iData; // misc
134  };
135  union
136  {
137  Hop_Obj_t* pNext; // strashing table
138  int PioNum; // the number of PI/PO
139  };
140  Hop_Obj_t* pFanin0; // fanin
141  Hop_Obj_t* pFanin1; // fanin
142  unsigned int Type : 3; // object type
143  unsigned int fPhase : 1; // value under 000...0 pattern
144  unsigned int fMarkA : 1; // multipurpose mask
145  unsigned int fMarkB : 1; // multipurpose mask
146  unsigned int nRefs : 26; // reference count (level)
147  int Id; // unique ID of the node
148 };
149 
151 typedef struct Hop_Man_t_ Hop_Man_t;
153 {
154  // AIG nodes
155  Vec_Ptr_t* vPis; // the array of PIs
156  Vec_Ptr_t* vPos; // the array of POs
157  Vec_Ptr_t* vObjs; // the array of all nodes (optional)
158  Hop_Obj_t* pConst1; // the constant 1 node
159  Hop_Obj_t Ghost; // the ghost node
160  // AIG node counters
161  int nObjs[AIG_VOID]; // the number of objects by type
162  int nCreated; // the number of created objects
163  int nDeleted; // the number of deleted objects
164  // stuctural hash table
165  Hop_Obj_t** pTable; // structural hash table
166  int nTableSize; // structural hash table size
167  // various data members
168  void* pData; // the temporary data
169  int nTravIds; // the current traversal ID
170  int fRefCount; // enables reference counting
171  int fCatchExor; // enables EXOR nodes
172  // memory management
173  Vec_Ptr_t* vChunks; // allocated memory pieces
174  Vec_Ptr_t* vPages; // memory pages used by nodes
175  Hop_Obj_t* pListFree; // the list of free nodes
176  // timing statistics
179 };
180 
182 typedef struct Abc_Ntk_t_ Abc_Ntk_t;
184 {
185  // general information
186  Abc_NtkType_t ntkType; // type of the network
187  Abc_NtkFunc_t ntkFunc; // functionality of the network
188  char* pName; // the network name
189  char* pSpec; // the name of the spec file if present
190  Nm_Man_t* pManName; // name manager (stores names of objects)
191  // components of the network
192  Vec_Ptr_t* vObjs; // the array of all objects (net, nodes, latches, etc)
193  Vec_Ptr_t* vPis; // the array of primary inputs
194  Vec_Ptr_t* vPos; // the array of primary outputs
195  Vec_Ptr_t* vCis; // the array of combinational inputs (PIs, latches)
196  Vec_Ptr_t* vCos; // the array of combinational outputs (POs, asserts, latches)
197  Vec_Ptr_t* vPios; // the array of PIOs
198  Vec_Ptr_t* vBoxes; // the array of boxes
200  // the number of living objects
201  int nObjCounts[ABC_OBJ_NUMBER]; // the number of objects by type
202  int nObjs; // the number of live objs
203  int nConstrs; // the number of constraints
204  int nBarBufs; // the number of barrier buffers
205  int nBarBufs2; // the number of barrier buffers
206  // the backup network and the step number
207  Abc_Ntk_t* pNetBackup; // the pointer to the previous backup network
208  int iStep; // the generation number for the given network
209  // hierarchy
210  Abc_Des_t* pDesign; // design (hierarchical networks only)
211  Abc_Ntk_t* pAltView; // alternative structural view of the network
212  int fHieVisited; // flag to mark the visited network
213  int fHiePath; // flag to mark the network on the path
214  int Id; // model ID
215  double dTemp; // temporary value
216  // miscellaneous data members
217  int nTravIds; // the unique traversal IDs of nodes
218  Vec_Int_t vTravIds; // trav IDs of the objects
219  Mem_Fixed_t* pMmObj; // memory manager for objects
220  Mem_Step_t* pMmStep; // memory manager for arrays
221  void* pManFunc; // functionality manager (AIG manager, BDD manager, or memory manager for SOPs)
222  Abc_ManTime_t* pManTime; // the timing manager (for mapped networks) stores arrival/required times for all nodes
223  void* pManCut; // the cut manager (for AIGs) stores information about the cuts computed for the nodes
224  float AndGateDelay; // an average estimated delay of one AND gate
225  int LevelMax; // maximum number of levels
226  Vec_Int_t* vLevelsR; // level in the reverse topological order (for AIGs)
227  Vec_Ptr_t* vSupps; // CO support information
228  int* pModel; // counter-example (for miters)
229  Abc_Cex_t* pSeqModel; // counter-example (for sequential miters)
230  Vec_Ptr_t* vSeqModelVec; // vector of counter-examples (for sequential miters)
231  Abc_Ntk_t* pExdc; // the EXDC network (if given)
232  void* pExcare; // the EXDC network (if given)
233  void* pData; // misc
234  Abc_Ntk_t* pCopy; // copy of this network
235  void* pBSMan; // application manager
236  void* pSCLib; // SC library
237  Vec_Int_t* vGates; // SC library gates
238  Vec_Int_t* vPhases; // fanins phases in the mapped netlist
239  char* pWLoadUsed; // wire load model used
240  float* pLutTimes; // arrivals/requireds/slacks using LUT-delay model
241  Vec_Ptr_t* vOnehots; // names of one-hot-encoded registers
242  Vec_Int_t* vObjPerm; // permutation saved
244  Vec_Ptr_t* vAttrs; // managers of various node attributes (node functionality, global BDDs, etc)
245  Vec_Int_t* vNameIds; // name IDs
246  Vec_Int_t* vFins; // obj/type info
247 };
248 
250 typedef struct Abc_Obj_t_ Abc_Obj_t;
251 struct Abc_Obj_t_ // 48/72 bytes (32-bits/64-bits)
252 {
253  Abc_Ntk_t* pNtk; // the host network
254  Abc_Obj_t* pNext; // the next pointer in the hash table
255  int Id; // the object ID
256  unsigned Type : 4; // the object type
257  unsigned fMarkA : 1; // the multipurpose mark
258  unsigned fMarkB : 1; // the multipurpose mark
259  unsigned fMarkC : 1; // the multipurpose mark
260  unsigned fPhase : 1; // the flag to mark the phase of equivalent node
261  unsigned fExor : 1; // marks AIG node that is a root of EXOR
262  unsigned fPersist : 1; // marks the persistant AIG node
263  unsigned fCompl0 : 1; // complemented attribute of the first fanin in the AIG
264  unsigned fCompl1 : 1; // complemented attribute of the second fanin in the AIG
265  unsigned Level : 20; // the level of the node
266  Vec_Int_t vFanins; // the array of fanins
267  Vec_Int_t vFanouts; // the array of fanouts
268  union
269  {
270  void* pData; // the network specific data
271  int iData;
272  }; // (SOP, BDD, gate, equiv class, etc)
273  union
274  {
275  void* pTemp; // temporary store for user's data
276  Abc_Obj_t* pCopy; // the copy of this object
277  int iTemp;
278  float dTemp;
279  };
280 };
281 
283 typedef struct Abc_Frame_t_ Abc_Frame_t;
285 {
286  // general info
287  char* sVersion; // the name of the current version
288  char* sBinary; // the name of the binary running
289  // commands, aliases, etc
290  st__table* tCommands; // the command table
291  st__table* tAliases; // the alias table
292  st__table* tFlags; // the flag table
293  Vec_Ptr_t* aHistory; // the command history
294  // the functionality
295  Abc_Ntk_t* pNtkCur; // the current network
296  Abc_Ntk_t* pNtkBestDelay; // the current network
297  Abc_Ntk_t* pNtkBestArea; // the current network
298  Abc_Ntk_t* pNtkBackup; // the current network
299  int nSteps; // the counter of different network processed
300  int fSource; // marks the source mode
301  int fAutoexac; // marks the autoexec mode
302  int fBatchMode; // batch mode flag
303  int fBridgeMode; // bridge mode flag
304  // save/load
305  Abc_Ntk_t* pNtkBest; // the current network
306  float nBestNtkArea; // best area
307  float nBestNtkDelay; // best delay
308  int nBestNtkNodes; // best nodes
309  int nBestNtkLevels; // best levels
310 
311  // output streams
312  FILE* Out;
313  FILE* Err;
314  FILE* Hst;
315  // used for runtime measurement
316  double TimeCommand; // the runtime of the last command
317  double TimeTotal; // the total runtime of all commands
318  // temporary storage for structural choices
319  Vec_Ptr_t* vStore; // networks to be used by choice
320  // decomposition package
321  void* pManDec; // decomposition manager
322  void* pManDsd; // decomposition manager
323  void* pManDsd2; // decomposition manager
324  // libraries for mapping
325  void* pLibLut; // the current LUT library
326  void* pLibBox; // the current box library
327  void* pLibGen; // the current genlib
328  void* pLibGen2; // the current genlib
329  void* pLibSuper; // the current supergate library
330  void* pLibScl; // the current Liberty library
331  void* pAbcCon; // constraint manager
332  // timing constraints
333  char* pDrivingCell; // name of the driving cell
334  float MaxLoad; // maximum output load
335  // inductive don't-cares
338 
339  // new code
340  Gia_Man_t* pGia; // alternative current network as a light-weight AIG
341  Gia_Man_t* pGia2; // copy of the above
342  Gia_Man_t* pGiaBest; // copy of the above
343  Gia_Man_t* pGiaBest2; // copy of the above
344  Gia_Man_t* pGiaSaved; // copy of the above
345  int nBestLuts; // best LUT count
346  int nBestEdges; // best edge count
347  int nBestLevels; // best level count
348  int nBestLuts2; // best LUT count
349  int nBestEdges2; // best edge count
350  int nBestLevels2; // best level count
351  Abc_Cex_t* pCex; // a counter-example to fail the current network
352  Abc_Cex_t* pCex2; // copy of the above
353  Vec_Ptr_t* vCexVec; // a vector of counter-examples if more than one PO fails
354  Vec_Ptr_t* vPoEquivs; // equivalence classes of isomorphic primary outputs
355  Vec_Int_t* vStatuses; // problem status for each output
356  Vec_Int_t* vAbcObjIds; // object IDs
357  int Status; // the status of verification problem (proved=1, disproved=0, undecided=-1)
358  int nFrames; // the number of time frames completed by BMC
359  Vec_Ptr_t* vPlugInComBinPairs; // pairs of command and its binary name
360  Vec_Ptr_t* vLTLProperties_global; // related to LTL
361  Vec_Ptr_t* vSignalNames; // temporary storage for signal names
362  char* pSpecName;
363  void* pSave1;
364  void* pSave2;
365  void* pSave3;
366  void* pSave4;
367  void* pAbc85Ntl;
368  void* pAbc85Ntl2;
369  void* pAbc85Best;
370  void* pAbc85Delay;
371  void* pAbcWlc;
373  void* pAbcBac;
374  void* pAbcCba;
375  void* pAbcPla;
378 #ifdef ABC_USE_CUDD
379  DdManager* dd; // temporary BDD package
380 #endif
385  int* pArray;
386  int* pBoxes;
387  void* pNdr;
388  int* pNdrArray;
389 
391 };
392 
394 // Function Forwared Declarations for ABC interface
396 
397 void Abc_Start();
398 void Abc_Stop();
399 
401 
404 
406 
407 char* Abc_ObjAssignName(Abc_Obj_t*, char*, char*);
408 
413 
416 
418 
419 int Cmd_CommandExecute(Abc_Frame_t*, const char*);
422 
427 char* Extra_UtilStrsav(const char*);
428 void Hop_ObjPrintVerilog(FILE*, Hop_Obj_t*, Vec_Vec_t*, int, int);
429 }
430 
431 namespace hal
432 {
433  namespace
434  {
442  class ContextABC final
443  {
444  public:
446  ContextABC()
447  {
448  Abc_Start();
449  }
450 
452  ~ContextABC()
453  {
454  Abc_Stop();
455  }
456  };
457 
459  Abc_Obj_t* Abc_ObjFanin(Abc_Obj_t* pObj, int i)
460  {
461  return (Abc_Obj_t*)pObj->pNtk->vObjs->pArray[pObj->vFanins.pArray[i]];
462  }
463 
465  char* Io_WriteVerilogGetName(char* pName)
466  {
467  static char Buffer[500];
468  int i, Length = strlen(pName);
469  if (pName[0] < '0' || pName[0] > '9')
470  {
471  for (i = 0; i < Length; i++)
472  {
473  if (!((pName[i] >= 'a' && pName[i] <= 'z') || (pName[i] >= 'A' && pName[i] <= 'Z') || (pName[i] >= '0' && pName[i] <= '9') || pName[i] == '_'))
474  {
475  break;
476  }
477  }
478  if (i == Length)
479  {
480  return pName;
481  }
482  }
483  // create Verilog style name
484  Buffer[0] = '\\';
485  for (i = 0; i < Length; i++)
486  {
487  Buffer[i + 1] = pName[i];
488  }
489  Buffer[Length + 1] = ' ';
490  Buffer[Length + 2] = 0;
491  return Buffer;
492  }
493 
495  Vec_Vec_t* Vec_VecAlloc(int nCap)
496  {
497  Vec_Vec_t* p;
498  p = ((Vec_Vec_t*)malloc(sizeof(Vec_Vec_t) * (1)));
499  if (nCap > 0 && nCap < 8)
500  {
501  nCap = 8;
502  }
503  p->nSize = 0;
504  p->nCap = nCap;
505  p->pArray = p->nCap ? (void**)malloc(sizeof(void*) * p->nCap) : NULL;
506  return p;
507  }
508 
515  void Vec_PtrFree(Vec_Ptr_t* p)
516  {
517 #define ABC_FREE(obj) ((obj) ? (free((char*)(obj)), (obj) = 0) : 0)
518  ABC_FREE(p->pArray);
519  ABC_FREE(p);
520 #undef ABC_FREE
521  }
522 
524  void Vec_VecFree(Vec_Vec_t* p)
525  {
526  Vec_Ptr_t* vVec;
527  int i;
528  for (i = 0; (i < p->nSize) && (((vVec) = (Vec_Ptr_t*)p->pArray[i]), 1); i++)
529  {
530  if (vVec)
531  {
532  Vec_PtrFree(vVec);
533  }
534  }
535 
536  Vec_PtrFree((Vec_Ptr_t*)p);
537  }
538 
546  std::vector<std::string> get_output_variables(const BooleanFunction& function)
547  {
548  std::vector<std::string> outputs;
549  outputs.reserve(function.size());
550  for (auto bit = 0u; bit < function.size(); bit++)
551  {
552  outputs.emplace_back("output_" + std::to_string(bit));
553  }
554  return outputs;
555  }
556 
564  Result<BooleanFunction> slice_at(const BooleanFunction& function, const u16 index)
565  {
566  // (1) setup the sliced Boolean function
567  if (auto res =
568  BooleanFunction::Slice(function.clone(), BooleanFunction::Index(index, function.size()), BooleanFunction::Index(index, function.size()), 1).map<BooleanFunction>([](const auto& f) {
569  // (2) perform a local simplification in order to remove unnecessary slices
571  });
572  res.is_error())
573  {
574  return ERR(res.get_error());
575  }
576  else
577  {
578  return res;
579  }
580  }
581 
588  Result<Abc_Ntk_t*> translate_to_abc(const BooleanFunction& function)
589  {
599  auto translate = [](const auto& node, auto&& operands, const auto& input2abc, auto network) -> Result<Abc_Obj_t*> {
600  // (1) short-hand check that we read correct operand data below
601  if (node.get_arity() != operands.size())
602  {
603  return ERR("could not translate Boolean function to ABC notation: invalid number of parameters");
604  }
605 
615  switch (node.type)
616  {
618  return OK(input2abc.at(node.variable));
619 
621  return OK(Abc_AigAnd((Abc_Aig_t*)network->pManFunc, operands[0], operands[1]));
623  return OK(Abc_AigXor((Abc_Aig_t*)network->pManFunc, operands[0], Abc_AigConst1(network)));
625  return OK(Abc_AigOr((Abc_Aig_t*)network->pManFunc, operands[0], operands[1]));
627  return OK(Abc_AigXor((Abc_Aig_t*)network->pManFunc, operands[0], operands[1]));
628 
629  default:
630  return ERR("could not translate Boolean function to ABC notation: not implemented for given node type " + std::to_string(node.type));
631  }
632  };
633 
634  // (1) initialze a new ABC network with structured hashing
635  auto network = Abc_NtkAlloc(ABC_NTK_STRASH, ABC_FUNC_AIG, 1);
636 
637  // (2) initialize Boolean function input variables as ABC network objects
638  std::map<std::string, Abc_Obj_t*> input2abc;
639  for (auto variable : function.get_variable_names())
640  {
641  auto object = Abc_NtkCreateObj(network, ABC_OBJ_PI);
642  Abc_ObjAssignName(object, variable.data(), NULL);
643 
644  input2abc[variable] = object;
645  }
646 
647  const auto output_variables = get_output_variables(function);
648  for (auto i = 0u; i < output_variables.size(); i++)
649  {
650  auto status = slice_at(function, i);
651  if (status.is_error())
652  {
653  return ERR_APPEND(status.get_error(),
654  "could not translate Boolean function to ABC notation: unable to slice Boolean function'" + function.to_string() + "' at index " + std::to_string(i));
655  }
656 
657  // (3) translation from Boolean function nodes to ABC network objects
658  std::vector<Abc_Obj_t*> stack;
659  for (const auto& node : status.get().get_nodes())
660  {
661  std::vector<Abc_Obj_t*> operands;
662  std::move(stack.end() - static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
663  stack.erase(stack.end() - static_cast<i64>(node.get_arity()), stack.end());
664 
665  auto translation = translate(node, std::move(operands), input2abc, network);
666  if (translation.is_ok())
667  {
668  stack.emplace_back(translation.get());
669  }
670  else
671  {
672  return ERR(translation.get_error());
673  }
674  }
675 
676  // (4) check that we have exactely one remaining entry on the stack
677  if (stack.size() != 1)
678  {
679  return ERR("could not translate Boolean function to ABC notation: number of elements remaining on the stack is not 1");
680  }
681 
682  // (5) define an output variable to the network
683  auto output = Abc_NtkCreateObj(network, ABC_OBJ_PO);
684  Abc_ObjAssignName(output, strdup(output_variables[i].data()), NULL);
685  Abc_ObjAddFanin(output, stack.back());
686  }
687 
688  // (6) internal ABC cleanup to remove any dangling object
689  Abc_AigCleanup((Abc_Aig_t*)network->pManFunc);
690 
691  // (7) check whether the network construction is successful
692  if (!Abc_NtkCheck(network))
693  {
694  Abc_NtkDelete(network);
695  return ERR("could not translate Boolean function to ABC notation: AbcNtkCheck() failed");
696  }
697 
698  return OK(network);
699  }
700 
707  Result<std::monostate> simplify(Abc_Ntk_t* network)
708  {
709  // (1) since we apply the ABC simplification using the command dispatch
710  // functionality, we have to set the network within the global frame
711  auto abc = Abc_FrameGetGlobalFrame();
712 
713  Abc_FrameReplaceCurrentNetwork(abc, network);
715 
716  // (2) perform the Boolean function simplification using a series of ABC
717  // simplification transformations on the internal graph
718 
719  // TODO(@nalbartus):
720  // Analyze which number of calls are minimal to achieve a "good enough"
721  // simplification / optimization result for further analysis
722  Cmd_CommandExecute(abc, R"#(
723  fraig;
724  balance;
725  rewrite -l;
726  refactor -l;
727  balance;
728  rewrite -l;
729  rewrite -lz;
730  balance;
731  refactor -lz;
732  rewrite -lz;
733  balance;
734  rewrite -lz;
735  )#");
736 
737  return OK({});
738  }
739 
754  Result<std::string> translate_from_abc()
755  {
756  std::stringstream ss;
757 
758  // (1) translate the simplified network back to a netlist
759  auto network = Abc_NtkToNetlist(Abc_FrameGetGlobalFrame()->pNtkCur);
760  if (!(network->ntkFunc == ABC_FUNC_AIG) && !(network->ntkFunc == ABC_FUNC_MAP))
761  {
762  Abc_NtkToAig(network);
763  }
764 
765  // (2) iterate each the ABC graph to assemble a list of structured
766  // Verilog assignments that implement the simplfied function
767  auto vLevels = Vec_VecAlloc(10);
768  for (int i = 0; i < network->vObjs->nSize; i++)
769  {
777 
778  auto node = (Abc_Obj_t*)network->vObjs->pArray[i];
779  if ((node == NULL) || !(node->Type == ABC_OBJ_NODE))
780  {
781  continue;
782  }
783  if (node->fPersist)
784  {
785  return ERR("could not translate Boolean function from ABC notation: 'node->fPersist' is set within ABC context");
786  }
787 
788  Abc_Obj_t* pFanin = nullptr;
789  for (int j = 0; (j < node->vFanins.nSize) && (((pFanin) = Abc_ObjFanin(node, j)), 1); j++)
790  {
791  Hop_IthVar((Hop_Man_t*)network->pManFunc, j)->pData = Extra_UtilStrsav(Io_WriteVerilogGetName(Abc_ObjName(pFanin)));
792  }
793 
794  // (2.1) compute the left-hand side variable name
795  const auto lhs = std::string(Io_WriteVerilogGetName(Abc_ObjName((Abc_Obj_t*)node->pNtk->vObjs->pArray[node->vFanouts.pArray[0]])));
796 
797  // (2.2) compute the right-hand side Boolean function expression via
798  // in-memory FILE* to mimic the original interface without the
799  // use of an actual file read/write operation
800  char* rhs{};
801  size_t len{};
802 
803  auto stream = open_memstream(&rhs, &len);
804  Hop_ObjPrintVerilog(stream, (Hop_Obj_t*)node->pData, vLevels, 0, 0);
805  fflush(stream);
806 
807  // (2.3) assemble "assign $(LHS) = $(RHS);"
808  ss << "assign " << lhs << " = " << rhs << ";" << std::endl;
809 
810  fclose(stream);
811  }
812  Vec_VecFree(vLevels);
813 
814  return OK(ss.str());
815  }
816 
824  Result<BooleanFunction> translate_from_verilog(const std::string& verilog, const BooleanFunction& function)
825  {
833  auto parse_assignment = [](const auto& assignment) -> Result<std::tuple<BooleanFunction, BooleanFunction>> {
834  Result<BooleanFunction> lhs = ERR(""), rhs = ERR("");
835 
836  namespace x3 = boost::spirit::x3;
837 
839  // Actions
841 
842  const auto LHSAction = [&lhs](auto& ctx) { lhs = BooleanFunction::from_string(_attr(ctx)); };
843  const auto RHSAction = [&rhs](auto& ctx) { rhs = BooleanFunction::from_string(_attr(ctx)); };
844 
846  // Rules
848 
849  const auto EndOfLineRule = x3::lit(";") >> *x3::space;
850  const auto RHSRule = x3::lexeme[*x3::char_("a-zA-Z0-9_+*~|&!'()[]\\ ")][RHSAction];
851  const auto EqualSignRule = *x3::space >> x3::lit("=") >> *x3::space;
852  const auto LHSRule = x3::lexeme[*x3::char_("a-zA-Z0-9_")][LHSAction];
853  const auto AssignRule = *x3::space >> x3::lit("assign") >> *x3::space;
854 
855  // (1) parse the assignment to left-hand and right-hand side
856  auto iter = assignment.begin();
857  const auto ok = x3::phrase_parse(iter,
858  assignment.end(),
860  // Parsing Expression Grammar
862  AssignRule >> LHSRule >> EqualSignRule >> RHSRule >> EndOfLineRule,
863  // we use an invalid a.k.a. non-printable ASCII character in order
864  // to prevent the skipping of space characters as they are defined
865  // as skipper within a Boolean function and operation
866  x3::char_(0x00));
867 
868  if (!ok || (iter != assignment.end()))
869  {
870  return ERR("could not parse assignment from Verilog notation: '" + assignment + "' (remaining '" + std::string(iter, assignment.end()) + "')");
871  }
872 
873  if (lhs.is_error())
874  {
875  return ERR_APPEND(lhs.get_error(), "cannot parse assignment from Verilog notation: unable to translate left side of assignment '" + assignment + "' into a Boolean function");
876  }
877  if (rhs.is_error())
878  {
879  return ERR_APPEND(rhs.get_error(), "cannot parse assignment from Verilog notation: unable to translate right side of assignment '" + assignment + "' into a Boolean function");
880  }
881 
882  return OK({lhs.get(), rhs.get()});
883  };
884 
885  std::map<BooleanFunction, BooleanFunction> assignments;
886 
887  // (1) translate each Verilog assignment of the form "assign ... = ...;"
888  std::istringstream data(verilog);
889  std::string line;
890  while (std::getline(data, line))
891  {
892  if (auto assignment = parse_assignment(line); assignment.is_ok())
893  {
894  auto [lhs, rhs] = assignment.get();
895  assignments[lhs] = rhs;
896  }
897  }
898 
899  // (2) check that each output variable is defined within the assignments
900  const auto output_variables = get_output_variables(function);
901  for (const auto& output_variable : output_variables)
902  {
903  if (assignments.find(BooleanFunction::Var(output_variable)) == assignments.end())
904  {
905  return ERR("could not parse assignment from Verilog notation: unable to simplify Boolean function'" + function.to_string() + "' as output variable is not defined in Verilog");
906  }
907  }
908 
909  // (3) recursively replace the variables for each output Boolean function
910  // until only input variables of the original function are present in
911  // the function
912  const auto inputs = function.get_variable_names();
913  for (const auto& output_variable : output_variables)
914  {
915  auto output = BooleanFunction::Var(output_variable);
916 
917  // in order to prevent infinite-loops by unsupported inputs such as
918  // cyclic replacement dependencies, we only replace |assignments| times
919  auto counter = 0u;
920  while ((assignments[output].get_variable_names() != inputs) && (counter++ < assignments.size()))
921  {
922  for (const auto& tmp : assignments[output].get_variable_names())
923  {
924  if (inputs.find(tmp) != inputs.end())
925  {
926  continue;
927  }
928  auto simplified = assignments[output].substitute(tmp, assignments[BooleanFunction::Var(tmp)]);
929  if (simplified.is_error())
930  {
931  return ERR(simplified.get_error());
932  }
933 
934  assignments[output] = simplified.get();
935  }
936  }
937  }
938 
939  // (4) validate the all outputs only contain input variables
940  for (const auto& output_variable : output_variables)
941  {
942  for (const auto& input : assignments[BooleanFunction::Var(output_variable)].get_variable_names())
943  {
944  if (inputs.find(input) == inputs.end())
945  {
946  return ERR("could not parse assignment from Verilog notation: unable to replace output variable '" + output_variable + "' as it contains temporary variable '" + input + "'");
947  }
948  }
949  }
950 
951  // (5) concatenate all output Boolean functions into a single function
952  auto state = assignments[BooleanFunction::Var(output_variables[0])];
953  for (auto i = 1u; i < function.size(); i++)
954  {
955  auto concat = BooleanFunction::Concat(assignments[BooleanFunction::Var(output_variables[i])].clone(), state.clone(), state.size() + 1);
956 
957  if (concat.is_ok())
958  {
959  state = concat.get();
960  }
961  else
962  {
963  return concat;
964  }
965  }
966  return OK(state);
967  }
968  } // namespace
969 
971  {
972  // # Developer Note
973  // In order to apply a global optimization to the Boolean function, we
974  // leverage the rich-featured and robust implementations of ABC [1]. To
975  // this end, we first translate the Boolean function into a subset of
976  // ABC's and-inverter graph structures (e.g., ABC cannot handle arith-
977  // metic such as '+' and we have to translate multi-bit vectors into
978  // single bit-vectors). We then use the rewriting, balancing and re-
979  // factoring in order to minimize the Boolean function and then read-
980  // back the graph back into our Boolean function representation.
981  //
982  // [1] https://people.eecs.berkeley.edu/~alanmi/abc/
983  static ContextABC context;
984 
985  // (1) check whether the Boolean function can be simplified using ABC
986  using NodeType = BooleanFunction::NodeType;
987 
988  static const std::set<u16> valid_abc_node_types({
991  NodeType::Or,
993  NodeType::Variable,
994  });
995 
996  if (function.get_variable_names().empty())
997  {
998  return OK(function.clone());
999  }
1000 
1001  if (auto nodes = function.get_nodes(); std::any_of(
1002  nodes.begin(), nodes.end(), [](auto node) { return (valid_abc_node_types.find(node.type) == valid_abc_node_types.end()) || (node.type = NodeType::Variable && node.size != 1); }))
1003  {
1004  return OK(function.clone());
1005  }
1006 
1007  // (2) since the simplification and translations require access to the
1008  // ABC global frame, we have to ensure an exclusive access in case
1009  // Boolean function simplifications are executed in parallel
1010  static std::mutex mutex;
1011  mutex.lock();
1012 
1013  auto status = translate_to_abc(function).map<std::monostate>([](const auto& network) { return simplify(network); });
1014 
1015  if (status.is_error())
1016  {
1017  return ERR_APPEND(status.get_error(), "could not simplyfy Boolean function using ABC: unable to translate & simplify Boolean function '" + function.to_string() + "'");
1018  }
1019 
1020  // (3) translate the ABC graph back into a Boolean function
1021  auto translated_function = translate_from_abc().map<BooleanFunction>([&function](const auto& verilog) { return translate_from_verilog(verilog, function); });
1022 
1023  mutex.unlock();
1024 
1025  if (translated_function.is_ok())
1026  {
1027  return translated_function;
1028  }
1029  else
1030  {
1031  return OK(function.clone());
1032  }
1033  }
1034 } // namespace hal
static BooleanFunction Var(const std::string &name, u16 size=1)
static Result< BooleanFunction > Concat(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Index(u16 index, u16 size)
static Result< BooleanFunction > from_string(const std::string &expression)
static Result< BooleanFunction > Slice(BooleanFunction &&p0, BooleanFunction &&p1, BooleanFunction &&p2, u16 size)
uint16_t u16
Definition: defines.h:40
int64_t i64
Definition: defines.h:37
#define ERR(message)
Definition: result.h:53
#define OK(...)
Definition: result.h:49
#define ERR_APPEND(prev_error, message)
Definition: result.h:57
Result< BooleanFunction > translate(std::vector< Token > &&tokens, const std::string &expression)
BooleanFunction Or(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction Not(const std::vector< BooleanFunction::Value > &p)
BooleanFunction Xor(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction And(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
Result< BooleanFunction > local_simplification(const BooleanFunction &function)
Result< BooleanFunction > abc_simplification(const BooleanFunction &function)
if(BUILD_TESTS) include_directories($
Definition: CMakeLists.txt:1
struct Abc_ManTime_t_ Abc_ManTime_t
void Hop_ObjPrintVerilog(FILE *, Hop_Obj_t *, Vec_Vec_t *, int, int)
char * Abc_ObjAssignName(Abc_Obj_t *, char *, char *)
Abc_Obj_t * Abc_AigConst1(Abc_Ntk_t *)
struct Mem_Fixed_t_ Mem_Fixed_t
void Abc_FrameReplaceCurrentNetwork(Abc_Frame_t *, Abc_Ntk_t *)
void Abc_NtkDelete(Abc_Ntk_t *)
int64_t abctime
struct Mem_Step_t_ Mem_Step_t
struct Abc_Cex_t_ Abc_Cex_t
Abc_ObjType_t
Copied from "src/base/abc/abc.h", see above for link to ABC's repository.
@ ABC_OBJ_NET
@ ABC_OBJ_NONE
@ ABC_OBJ_NODE
@ ABC_OBJ_BLACKBOX
@ ABC_OBJ_BI
@ ABC_OBJ_NUMBER
@ ABC_OBJ_BO
@ ABC_OBJ_WHITEBOX
@ ABC_OBJ_PI
@ ABC_OBJ_LATCH
@ ABC_OBJ_PO
@ ABC_OBJ_CONST1
void(* Abc_Frame_Callback_BmcFrameDone_Func)(int, int, int)
struct Abc_Nam_t_ Abc_Nam_t
struct Dsd_Manager_t_ DdManager
struct Abc_Aig_t_ Abc_Aig_t
Abc_Ntk_t * Abc_NtkToNetlist(Abc_Ntk_t *)
Abc_NtkType_t
Copied from "src/base/abc/abc.h", see above for link to ABC's repository.
@ ABC_NTK_NONE
@ ABC_NTK_LOGIC
@ ABC_NTK_STRASH
@ ABC_NTK_NETLIST
@ ABC_NTK_OTHER
int Abc_AigCleanup(Abc_Aig_t *)
struct Gia_Man_t_ Gia_Man_t
struct Abc_Des_t_ Abc_Des_t
Hop_Obj_t * Hop_IthVar(Hop_Man_t *p, int i)
Abc_Obj_t * Abc_AigOr(Abc_Aig_t *, Abc_Obj_t *, Abc_Obj_t *)
Abc_Ntk_t * Abc_NtkAlloc(Abc_NtkType_t, Abc_NtkFunc_t, int)
Abc_Obj_t * Abc_AigXor(Abc_Aig_t *, Abc_Obj_t *, Abc_Obj_t *)
Hop_Type_t
Copied from "src/aig/hop/hop.h", see above for link to ABC's repository.
@ AIG_VOID
@ AIG_CONST1
@ AIG_EXOR
@ AIG_NONE
char * Abc_ObjName(Abc_Obj_t *)
Abc_Obj_t * Abc_NtkCreateObj(Abc_Ntk_t *, Abc_ObjType_t)
struct Nm_Man_t_ Nm_Man_t
void Abc_Start()
int Abc_NtkCheck(Abc_Ntk_t *)
void Abc_ObjAddFanin(Abc_Obj_t *, Abc_Obj_t *)
struct Vec_Wec_t_ Vec_Wec_t
Abc_Frame_t * Abc_FrameGetGlobalFrame()
char * Extra_UtilStrsav(const char *)
Abc_NtkFunc_t
Copied from "src/base/abc/abc.h", see above for link to ABC's repository.
@ ABC_FUNC_OTHER
@ ABC_FUNC_NONE
@ ABC_FUNC_BLIFMV
@ ABC_FUNC_BLACKBOX
@ ABC_FUNC_SOP
@ ABC_FUNC_BDD
@ ABC_FUNC_AIG
@ ABC_FUNC_MAP
int Abc_NtkToAig(Abc_Ntk_t *)
void Abc_FrameClearVerifStatus(Abc_Frame_t *)
int Cmd_CommandExecute(Abc_Frame_t *, const char *)
struct st__table st__table
#define ABC_FREE(obj)
void Abc_Stop()
Abc_Obj_t * Abc_AigAnd(Abc_Aig_t *, Abc_Obj_t *, Abc_Obj_t *)
Vec_Int_t * vCopyMiniLut
Abc_Nam_t * pJsonStrs
st__table * tCommands
Vec_Int_t * pAbcWlcInv
Vec_Ptr_t * vLTLProperties_global
Abc_Ntk_t * pNtkBestArea
Vec_Int_t * vIndFlops
Vec_Ptr_t * aHistory
Vec_Int_t * vCopyMiniAig
Gia_Man_t * pGiaBest2
Gia_Man_t * pGiaMiniAig
Vec_Int_t * vStatuses
Vec_Int_t * vAbcObjIds
Vec_Ptr_t * vSignalNames
Gia_Man_t * pGiaBest
st__table * tAliases
Abc_Frame_Callback_BmcFrameDone_Func pFuncOnFrameDone
Abc_Ntk_t * pNtkBest
Abc_Ntk_t * pNtkBackup
Vec_Ptr_t * vPoEquivs
Vec_Ptr_t * vPlugInComBinPairs
Gia_Man_t * pGiaSaved
Gia_Man_t * pGiaMiniLut
Vec_Wec_t * vJsonObjs
Abc_Ntk_t * pNtkBestDelay
Abc_NtkType_t ntkType
Vec_Ptr_t * vAttrs
Vec_Ptr_t * vCis
Vec_Int_t * vLevelsR
Vec_Ptr_t * vCos
Abc_Cex_t * pSeqModel
Abc_Ntk_t * pNetBackup
Abc_Des_t * pDesign
Vec_Int_t * vGates
Vec_Ptr_t * vPos
Vec_Ptr_t * vBoxes
Mem_Step_t * pMmStep
Vec_Int_t * vNameIds
Abc_Ntk_t * pExdc
int nObjCounts[ABC_OBJ_NUMBER]
Vec_Int_t * vFins
Vec_Int_t * vTopo
Vec_Ptr_t * vPios
Mem_Fixed_t * pMmObj
Vec_Ptr_t * vOnehots
Abc_ManTime_t * pManTime
Nm_Man_t * pManName
Abc_Ntk_t * pCopy
Abc_Ntk_t * pAltView
Vec_Ptr_t * vSupps
Vec_Int_t * vObjPerm
Vec_Ptr_t * vPis
Vec_Ptr_t * vObjs
Vec_Int_t * vPhases
Vec_Ptr_t * vSeqModelVec
Vec_Ptr_t * vLtlProperties
Abc_NtkFunc_t ntkFunc
Abc_Ntk_t * pNtk
Abc_Obj_t * pCopy
Abc_Obj_t * pNext
Vec_Ptr_t * vPages
Hop_Obj_t * pConst1
Vec_Ptr_t * vChunks
Hop_Obj_t * pListFree
Hop_Obj_t ** pTable
Vec_Ptr_t * vPos
int nObjs[AIG_VOID]
Vec_Ptr_t * vObjs
Vec_Ptr_t * vPis
unsigned int Type
unsigned int nRefs
unsigned int fPhase
Hop_Obj_t * pNext
unsigned int fMarkA
Hop_Obj_t * pFanin1
Hop_Obj_t * pFanin0
unsigned int fMarkB