μHAL (v2.6.5)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
NodeTreeBuilder.cpp
Go to the documentation of this file.
1 /*
2 ---------------------------------------------------------------------------
3 
4  This file is part of uHAL.
5 
6  uHAL is a hardware access library and programming framework
7  originally developed for upgrades of the Level-1 trigger of the CMS
8  experiment at CERN.
9 
10  uHAL is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  uHAL is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with uHAL. If not, see <http://www.gnu.org/licenses/>.
22 
23 
24  Andrew Rose, Imperial College, London
25  email: awr01 <AT> imperial.ac.uk
26 
27  Marc Magrans de Abril, CERN
28  email: marc.magrans.de.abril <AT> cern.ch
29 
30 ---------------------------------------------------------------------------
31 */
32 
33 #include "uhal/NodeTreeBuilder.hpp"
34 
35 
36 #include <fstream>
37 
39 #include "uhal/utilities/files.hpp"
40 #include "uhal/utilities/xml.hpp"
41 #include "uhal/log/log.hpp"
42 
43 #include <boost/bind.hpp>
44 #include <boost/spirit/include/qi.hpp>
45 #include <boost/date_time/posix_time/posix_time.hpp>
46 #include <boost/algorithm/string/replace.hpp>
47 #include <boost/filesystem.hpp>
48 
49 
50 #if BOOST_VERSION >= 106000
51 // Resolve boost bind placeholders (_1, _2, ...) that moved within boost::laceholders namespace from v1.60
52 using boost::placeholders::_1;
53 using boost::placeholders::_2;
54 using boost::placeholders::_3;
55 #endif
56 
57 
58 namespace uhal
59 {
60 
61  const char* NodeTreeBuilder::mIdAttribute = "id";
62  const char* NodeTreeBuilder::mAddressAttribute = "address";
63  const char* NodeTreeBuilder::mParametersAttribute = "parameters";
64  const char* NodeTreeBuilder::mTagsAttribute = "tags";
65  const char* NodeTreeBuilder::mDescriptionAttribute = "description";
66  const char* NodeTreeBuilder::mPermissionsAttribute = "permission";
67  const char* NodeTreeBuilder::mMaskAttribute = "mask";
68  const char* NodeTreeBuilder::mModeAttribute = "mode";
69  const char* NodeTreeBuilder::mSizeAttribute = "size";
70  const char* NodeTreeBuilder::mClassAttribute = "class";
71  const char* NodeTreeBuilder::mModuleAttribute = "module";
72  const char* NodeTreeBuilder::mFirmwareInfo = "fwinfo";
73 
74 
75 
76  NodeTreeBuilder* NodeTreeBuilder::mInstance = NULL;
77 
78 
80  {
81  //------------------------------------------------------------------------------------------------------------------------
82  Rule<Node*> lPlainNode;
83  lPlainNode.optional ( NodeTreeBuilder::mClassAttribute ) //.forbid ( NodeTreeBuilder::mClassAttribute ) //see https://svnweb.cern.ch/trac/cactus/ticket/452
84  .forbid ( NodeTreeBuilder::mModuleAttribute )
85  .forbid ( NodeTreeBuilder::mMaskAttribute )
86  .optional ( NodeTreeBuilder::mIdAttribute )
87  .optional ( NodeTreeBuilder::mAddressAttribute )
88  .optional ( NodeTreeBuilder::mParametersAttribute )
89  .optional ( NodeTreeBuilder::mFirmwareInfo )
90  .optional ( NodeTreeBuilder::mPermissionsAttribute )
91  .optional ( NodeTreeBuilder::mModeAttribute )
92  .optional ( NodeTreeBuilder::mSizeAttribute )
93  .optional ( NodeTreeBuilder::mTagsAttribute )
94  .optional ( NodeTreeBuilder::mDescriptionAttribute );
95  //------------------------------------------------------------------------------------------------------------------------
96  Rule<Node*> lBitMask;
97  lBitMask.require ( NodeTreeBuilder::mMaskAttribute )
98  .forbid ( NodeTreeBuilder::mClassAttribute )
99  .forbid ( NodeTreeBuilder::mModuleAttribute )
100  .optional ( NodeTreeBuilder::mAddressAttribute ) // .forbid ( NodeTreeBuilder::mAddressAttribute ) //see https://svnweb.cern.ch/trac/cactus/ticket/92
101  .forbid ( NodeTreeBuilder::mModeAttribute )
102  .forbid ( NodeTreeBuilder::mSizeAttribute )
103  .optional ( NodeTreeBuilder::mParametersAttribute )
104  .optional ( NodeTreeBuilder::mFirmwareInfo )
105  .optional ( NodeTreeBuilder::mPermissionsAttribute )
106  .optional ( NodeTreeBuilder::mTagsAttribute )
107  .optional ( NodeTreeBuilder::mDescriptionAttribute );
108  //------------------------------------------------------------------------------------------------------------------------
109  Rule<Node*> lModule;
110  lModule.optional ( NodeTreeBuilder::mIdAttribute )
111  .require ( NodeTreeBuilder::mModuleAttribute )
112  .forbid ( NodeTreeBuilder::mMaskAttribute )
113  .optional ( NodeTreeBuilder::mClassAttribute ) //.forbid ( NodeTreeBuilder::mClassAttribute ) //see https://svnweb.cern.ch/trac/cactus/ticket/452
114  .forbid ( NodeTreeBuilder::mModeAttribute )
115  .forbid ( NodeTreeBuilder::mSizeAttribute )
116  .forbid ( NodeTreeBuilder::mPermissionsAttribute )
117  .optional ( NodeTreeBuilder::mAddressAttribute )
118  .optional ( NodeTreeBuilder::mParametersAttribute )
119  .optional ( NodeTreeBuilder::mFirmwareInfo )
120  .optional ( NodeTreeBuilder::mTagsAttribute )
121  .optional ( NodeTreeBuilder::mDescriptionAttribute );
122  //------------------------------------------------------------------------------------------------------------------------
123  mTopLevelNodeParser.addRule ( lPlainNode , boost::bind ( &NodeTreeBuilder::plainNodeCreator , this , false , _1 ) );
124  mTopLevelNodeParser.addRule ( lBitMask , boost::bind ( &NodeTreeBuilder::bitmaskNodeCreator , this , false , _1 ) );
125  mTopLevelNodeParser.addRule ( lModule , boost::bind ( &NodeTreeBuilder::moduleNodeCreator , this , false , _1 ) );
126  //------------------------------------------------------------------------------------------------------------------------
127  lPlainNode.require ( NodeTreeBuilder::mIdAttribute );
128  lBitMask.require ( NodeTreeBuilder::mIdAttribute );
129  lModule.require ( NodeTreeBuilder::mIdAttribute );
130  //------------------------------------------------------------------------------------------------------------------------
131  mNodeParser.addRule ( lPlainNode , boost::bind ( &NodeTreeBuilder::plainNodeCreator , this , true , _1 ) );
132  mNodeParser.addRule ( lBitMask , boost::bind ( &NodeTreeBuilder::bitmaskNodeCreator , this , true , _1 ) );
133  mNodeParser.addRule ( lModule , boost::bind ( &NodeTreeBuilder::moduleNodeCreator , this , true , _1 ) );
134  //------------------------------------------------------------------------------------------------------------------------
135  }
137  {
138  }
139 
140 
141 
143  {
144  if ( mInstance == NULL )
145  {
146  mInstance = new NodeTreeBuilder();
147  }
148 
149  return *mInstance;
150  }
151 
152  Node* NodeTreeBuilder::getNodeTree ( const std::string& aFilenameExpr , const boost::filesystem::path& aPath )
153  {
154  std::vector< std::pair<std::string, std::string> > lAddressFiles;
155  uhal::utilities::ParseSemicolonDelimitedUriList ( aFilenameExpr , lAddressFiles );
156 
157  if ( lAddressFiles.size() != 1 )
158  {
159  exception::IncorrectAddressTableFileCount lExc;
160  log ( lExc , "Exactly one address table file must be specified. The expression " , Quote ( aFilenameExpr ) , " contains " , Integer ( lAddressFiles.size() ) , " valid file expressions." );
161  throw lExc;
162  }
163 
164  std::vector< const Node* > lNodes;
165  uhal::utilities::OpenFile ( lAddressFiles[0].first , lAddressFiles[0].second , aPath.parent_path() , boost::bind ( &NodeTreeBuilder::CallBack, boost::ref ( *this ) , _1 , _2 , _3 , boost::ref ( lNodes ) ) );
166 
167  if ( lNodes.size() != 1 )
168  {
169  exception::IncorrectAddressTableFileCount lExc;
170  log ( lExc , "Exactly one address table file must be specified. The expression " , Quote ( lAddressFiles[0].second ) , " refers to " , Integer ( lNodes.size() ) , " valid files." );
171  throw lExc;
172  }
173 
174  Node* lNode ( lNodes[0]->clone() );
175  return lNode;
176  }
177 
178 
180  {
181  for(boost::unordered_map<std::string, const Node*>::const_iterator it=mNodes.begin(); it != mNodes.end(); it++)
182  {
183  delete it->second;
184  }
185  mNodes.clear();
186  }
187 
188 
189  void NodeTreeBuilder::CallBack ( const std::string& aProtocol , const boost::filesystem::path& aPath , std::vector<uint8_t>& aFile , std::vector< const Node* >& aNodes )
190  {
191  std::string lName ( aProtocol + ( aPath.string() ) );
192  boost::unordered_map< std::string , const Node* >::iterator lNodeIt = mNodes.find ( lName );
193 
194  if ( lNodeIt != mNodes.end() )
195  {
196  aNodes.push_back ( lNodeIt->second );
197  return;
198  }
199 
200  std::string lExtension ( aPath.extension().string().substr ( 0,4 ) );
201  boost::to_lower ( lExtension ); //just in case someone decides to use capitals in their file extensions.
202 
203  if ( lExtension == ".xml" )
204  {
205  log ( Info() , "Reading XML address file " , Quote( aPath.c_str() ) );
206  pugi::xml_document lXmlDocument;
207  pugi::xml_parse_result lLoadResult = lXmlDocument.load_buffer_inplace ( & ( aFile[0] ) , aFile.size() );
208 
209  if ( !lLoadResult )
210  {
211  uhal::utilities::PugiXMLParseResultPrettifier ( lLoadResult , aPath , aFile );
212  return;
213  }
214 
215  pugi::xml_node lXmlNode = lXmlDocument.child ( "node" );
216 
217  if ( !lXmlNode )
218  {
219  log ( Error() , "No XML node called ", Quote ( "node" ) , " in file " , aPath.c_str() );
220  return;
221  }
222 
223  mFileCallStack.push_back ( aPath );
224  Node* lNode ( mTopLevelNodeParser ( lXmlNode ) );
225  mFileCallStack.pop_back( );
226  calculateHierarchicalAddresses ( lNode , 0x00000000 );
227  checkForAddressCollisions ( lNode , aPath ); // Needs further investigation - disabled for now as it causes exceptions with valid tables.
228  mNodes.insert ( std::make_pair ( lName , lNode ) );
229  aNodes.push_back ( lNode );
230  return;
231  }
232  else if ( lExtension == ".txt" )
233  {
234  log ( Info() , "TXT file" );
235  log ( Error() , "Parser problems mean that this method has been disabled." );
236  log ( Error() , "At " , ThisLocation() );
237  return;
238  }
239  else
240  {
241  log ( Error() , "Extension " , Quote ( lExtension ) , " not known." );
242  return;
243  }
244  }
245 
246 
247  Node* NodeTreeBuilder::plainNodeCreator ( const bool& aRequireId , const pugi::xml_node& aXmlNode )
248  {
249  Node* lNode ( new Node() );
250  setUid ( aRequireId , aXmlNode , lNode );
251  setAddr ( aXmlNode , lNode );
252  setPars ( aXmlNode , lNode );
253  setFirmwareInfo ( aXmlNode , lNode );
254  setClassName ( aXmlNode , lNode );
255  setTags ( aXmlNode , lNode );
256  setDescription ( aXmlNode , lNode );
257  setModule ( aXmlNode , lNode );
258  setPermissions ( aXmlNode , lNode );
259  //setMask( aXmlNode , lNode );
260  setModeAndSize ( aXmlNode , lNode );
261  addChildren ( aXmlNode , lNode );
262  log ( Debug() , lNode->mUid , " built by " , __PRETTY_FUNCTION__ );
263 
264  if ( lNode->mClassName.size() )
265  {
267  }
268  else
269  {
270  return lNode;
271  }
272  }
273 
274  Node* NodeTreeBuilder::moduleNodeCreator ( const bool& aRequireId , const pugi::xml_node& aXmlNode )
275  {
276  std::string lModule;
278  Node* lNode ( getNodeTree ( lModule , mFileCallStack.back( ) ) );
279  setUid ( aRequireId , aXmlNode , lNode );
280  setAddr ( aXmlNode , lNode );
281  setClassName ( aXmlNode , lNode );
282  setPars ( aXmlNode , lNode );
283  setFirmwareInfo ( aXmlNode , lNode );
284  setTags ( aXmlNode , lNode );
285  setDescription ( aXmlNode , lNode );
286  setModule ( aXmlNode , lNode );
287  //setPermissions( aXmlNode , lNode );
288  //setMask( aXmlNode , lNode );
289  //setModeAndSize( aXmlNode , lNode );
290  //addChildren( aXmlNode , lNode );
291  log ( Debug() , lNode->mUid , " built by " , __PRETTY_FUNCTION__ );
292 
293  if ( lNode->mClassName.size() )
294  {
296  }
297  else
298  {
299  return lNode;
300  }
301  }
302 
303 
304  Node* NodeTreeBuilder::bitmaskNodeCreator ( const bool& aRequireId , const pugi::xml_node& aXmlNode )
305  {
306  if ( aXmlNode.child ( "node" ) )
307  {
308  exception::MaskedNodeCannotHaveChild lExc;
309  log ( lExc , "Bit-masked nodes are not allowed to have child nodes" );
310  throw lExc;
311  }
312 
313  Node* lNode ( new Node() );
314  setUid ( aRequireId , aXmlNode , lNode );
315  setAddr ( aXmlNode , lNode ); //was commented out, see https://svnweb.cern.ch/trac/cactus/ticket/92
316  setClassName ( aXmlNode , lNode );
317  setPars ( aXmlNode , lNode );
318  setFirmwareInfo ( aXmlNode , lNode );
319  setTags ( aXmlNode , lNode );
320  setDescription ( aXmlNode , lNode );
321  setModule ( aXmlNode , lNode );
322  setPermissions ( aXmlNode , lNode );
323  setMask ( aXmlNode , lNode );
324  //setModeAndSize( aXmlNode , lNode );
325  //addChildren( aXmlNode , lNode );
326  log ( Debug() , lNode->mUid , " built by " , __PRETTY_FUNCTION__ );
327  return lNode;
328  }
329 
330 
331 
332 
333  void NodeTreeBuilder::setUid ( const bool& aRequireId , const pugi::xml_node& aXmlNode , Node* aNode )
334  {
335  if ( aRequireId )
336  {
337  if ( ! uhal::utilities::GetXMLattribute<true> ( aXmlNode , NodeTreeBuilder::mIdAttribute , aNode->mUid ) )
338  {
339  //error description is given in the function itself so no more elaboration required
340  throw exception::NodeMustHaveUID();
341  }
342  }
343  else
344  {
346  }
347  }
348 
349  void NodeTreeBuilder::setAddr ( const pugi::xml_node& aXmlNode , Node* aNode )
350  {
351  //Address is an optional attribute for hierarchical addressing
352  uint32_t lAddr ( 0 );
354  aNode->mPartialAddr |= lAddr;
355  }
356 
357 
358  void NodeTreeBuilder::setClassName ( const pugi::xml_node& aXmlNode , Node* aNode )
359  {
360  //Address is an optional attribute for hierarchical addressing
361  std::string lClassStr;
363 
364  aNode->mClassName = lClassStr;
365  }
366 
367  void NodeTreeBuilder::setPars ( const pugi::xml_node& aXmlNode , Node* aNode )
368  {
369  std::string lParsStr;
370  //get attribute from xml file as string
372 
373  if ( lParsStr.size() )
374  {
375  //parse the string into a NodeTreeParameters object
376  std::string::const_iterator lBegin ( lParsStr.begin() );
377  std::string::const_iterator lEnd ( lParsStr.end() );
378  boost::unordered_map<std::string, std::string> lPars;
379  boost::spirit::qi::phrase_parse ( lBegin , lEnd , mNodeTreeParametersGrammar , boost::spirit::ascii::space , lPars );
380  // Update the parameters map
381  // Add to lPars those previously defined (module node)
382  lPars.insert ( aNode->mParameters.begin(), aNode->mParameters.end() );
383  // Swap the containers
384  aNode->mParameters.swap ( lPars );
385  }
386  }
387 
388  void NodeTreeBuilder::setTags ( const pugi::xml_node& aXmlNode , Node* aNode )
389  {
390  std::string lStr;
391  //Tags is an optional attribute to allow the user to add a description to a node
393 
394  if ( lStr.size() && aNode->mTags.size() )
395  {
396  aNode->mTags += "[";
397  aNode->mTags += lStr;
398  aNode->mTags += "]";
399  }
400  else if ( lStr.size() && !aNode->mTags.size() )
401  {
402  aNode->mTags = lStr;
403  }
404  }
405 
406 
407  void NodeTreeBuilder::setDescription ( const pugi::xml_node& aXmlNode , Node* aNode )
408  {
409  std::string lStr;
410  //Tags is an optional attribute to allow the user to add a description to a node
412 
413  if ( lStr.size() && aNode->mDescription.size() )
414  {
415  aNode->mDescription += "[";
416  aNode->mDescription += lStr;
417  aNode->mDescription += "]";
418  }
419  else if ( lStr.size() && !aNode->mDescription.size() )
420  {
421  aNode->mDescription = lStr;
422  }
423  }
424 
425  void NodeTreeBuilder::setModule ( const pugi::xml_node& aXmlNode , Node* aNode )
426  {
427  if ( mFileCallStack.size() )
428  {
429  aNode->mModule = mFileCallStack.back( ).string();
430  }
431  }
432 
433  void NodeTreeBuilder::setPermissions ( const pugi::xml_node& aXmlNode , Node* aNode )
434  {
435  //Permissions is an optional attribute for specifying read/write permissions
436  std::string lPermission;
437 
438  if ( uhal::utilities::GetXMLattribute<false> ( aXmlNode , "permission" , lPermission ) )
439  {
440  boost::spirit::qi::phrase_parse (
441  lPermission.begin(),
442  lPermission.end(),
444  boost::spirit::ascii::space,
445  aNode->mPermission
446  );
447  }
448  }
449 
450 
451  void NodeTreeBuilder::setMask ( const pugi::xml_node& aXmlNode , Node* aNode )
452  {
453  //Tags is an optional attribute to allow the user to add a description to a node
455  }
456 
457 
458  void NodeTreeBuilder::setModeAndSize ( const pugi::xml_node& aXmlNode , Node* aNode )
459  {
460  //Mode is an optional attribute for specifying whether a block is incremental, non-incremental or a single register
461  std::string lMode;
462 
463  if ( uhal::utilities::GetXMLattribute<false> ( aXmlNode , NodeTreeBuilder::mModeAttribute , lMode ) )
464  {
465  boost::spirit::qi::phrase_parse (
466  lMode.begin(),
467  lMode.end(),
469  boost::spirit::ascii::space,
470  aNode->mMode
471  );
472 
473  if ( aNode->mMode == defs::INCREMENTAL )
474  {
475  //If a block is incremental it requires a size attribute
476  if ( ! uhal::utilities::GetXMLattribute<false> ( aXmlNode , NodeTreeBuilder::mSizeAttribute , aNode->mSize ) )
477  {
478  exception::IncrementalNodeRequiresSizeAttribute lExc;
479  log ( lExc , "Node " , Quote ( aNode->mUid ) , " has type " , Quote ( "INCREMENTAL" ) , ", which requires a " , Quote ( NodeTreeBuilder::mSizeAttribute ) , " attribute" );
480  throw lExc;
481  }
482  }
483  else if ( aNode->mMode == defs::NON_INCREMENTAL )
484  {
485  //If a block is non-incremental, then a size attribute is recommended
486  if ( ! uhal::utilities::GetXMLattribute<false> ( aXmlNode , NodeTreeBuilder::mSizeAttribute , aNode->mSize ) )
487  {
488  log ( Notice() , "Node " , Quote ( aNode->mUid ) , " has type " , Quote ( "NON_INCREMENTAL" ) , " but does not have a " , Quote ( NodeTreeBuilder::mSizeAttribute ) , " attribute. This is not necessarily a problem, but if there is a limit to the size of the read/write operation from this port, then please consider adding this attribute for the sake of safety." );
489  }
490  }
491  }
492  }
493 
494  void NodeTreeBuilder::setFirmwareInfo ( const pugi::xml_node& aXmlNode , Node* aNode )
495  {
496  //Address is an optional attribute for hierarchical addressing
497  std::string lFwInfoStr;
499 
500  if ( lFwInfoStr.size() )
501  {
502  //parse the string into a NodeTreeFwInfoAttribute object
503  std::string::const_iterator lBegin ( lFwInfoStr.begin() );
504  std::string::const_iterator lEnd ( lFwInfoStr.end() );
506  boost::spirit::qi::phrase_parse ( lBegin , lEnd , mNodeTreeFirmwareInfoAttributeGrammar , boost::spirit::ascii::space , lFwInfo );
507  aNode->mFirmwareInfo.insert ( make_pair ( "type",lFwInfo.mType ) );
508 
509  if ( lFwInfo.mArguments.size() )
510  {
511  aNode->mFirmwareInfo.insert ( lFwInfo.mArguments.begin() , lFwInfo.mArguments.end() );
512  }
513  }
514  }
515 
516  bool NodeTreeBuilder::NodePtrCompare ( Node* aNodeL, Node* aNodeR )
517  {
518  return ( aNodeL->mAddr < aNodeR->mAddr );
519  }
520 
521 
522  void NodeTreeBuilder::addChildren ( const pugi::xml_node& aXmlNode , Node* aNode )
523  {
524  pugi::xml_node lXmlNode = aXmlNode.child ( "node" );
525 
526  if ( aNode->mMode == defs::NON_INCREMENTAL )
527  {
528  if ( lXmlNode )
529  {
530  exception::BlockAccessNodeCannotHaveChild lExc;
531  log ( lExc , "Block access nodes are not allowed to have child nodes, but the node " , Quote ( aNode->mUid ) , " has a child node in the address table" );
532  throw lExc;
533  }
534  }
535  else
536  {
537  for ( ; lXmlNode; lXmlNode = lXmlNode.next_sibling ( "node" ) )
538  {
539  aNode->mChildren.push_back ( mNodeParser ( lXmlNode ) );
540  }
541 
542  for ( std::deque< Node* >::iterator lIt = aNode->mChildren.begin(); lIt != aNode->mChildren.end(); ++lIt )
543  {
544  aNode->mChildrenMap.insert ( std::make_pair ( ( **lIt ).mUid , *lIt ) );
545 
546  for ( boost::unordered_map< std::string , Node* >::iterator lSubMapIt = ( **lIt ).mChildrenMap.begin() ; lSubMapIt != ( **lIt ).mChildrenMap.end() ; ++lSubMapIt )
547  {
548  aNode->mChildrenMap.insert ( std::make_pair ( ( **lIt ).mUid +'.'+ ( lSubMapIt->first ) , lSubMapIt->second ) );
549  }
550  }
551  }
552  }
553 
554  void NodeTreeBuilder::calculateHierarchicalAddresses ( Node* aNode , const uint32_t& aAddr )
555  {
556  if ( aNode->mMode == defs::HIERARCHICAL )
557  {
558  if ( aNode->mChildren.size() == 0 )
559  {
560  aNode->mMode = defs::SINGLE;
561  }
562  else
563  {
564  // bool lAnyMasked( false );
565  bool lAllMasked ( true );
566 
567  for ( std::deque< Node* >::iterator lIt = aNode->mChildren.begin(); lIt != aNode->mChildren.end(); ++lIt )
568  {
569  if ( ( **lIt ).mMask == defs::NOMASK )
570  {
571  lAllMasked = false;
572  }
573 
574  // else
575  // {
576  // lAnyMasked = true;
577  // }
578  }
579 
580  // if( lAnyMasked && !lAllMasked )
581  // {
582  // log ( Error() , "Both masked and unmasked children found in branch " , Quote ( aNode->mUid ) );
583  // throw exception::// BothMaskedAndUnmaskedChildren();
584  // }
585 
586  if ( lAllMasked )
587  {
588  aNode->mMode = defs::SINGLE;
589  }
590  }
591  }
592 
593  if ( aNode->mMode == defs::INCREMENTAL )
594  {
595  uint64_t lTopAddr ( ( uint64_t ) ( aNode->mPartialAddr ) + ( uint64_t ) ( aNode->mSize-1 ) );
596 
597  //Check that the requested block size does not extend outside register space
598  if ( lTopAddr >> 32 )
599  {
600  exception::ArraySizeExceedsRegisterBound lExc;
601  log ( lExc , "A block size of " , Integer ( aNode->mSize ) , " and a base address of " , Integer ( aNode->mAddr , IntFmt<hex,fixed>() ) , " exceeds bounds of address space" );
602  throw lExc;
603  }
604 
605  /*
606  //Test for overlap with parent
607  if ( ( uint32_t ) ( lTopAddr ) & aAddr ) //should set the most significant bit of the child address and then AND this with the parent address
608  {
609  log ( Warning() , "The partial address of the top register in the current branch, " , Quote ( aNode->mUid ) , " , (" , Integer ( ( uint32_t ) ( lTopAddr ) , IntFmt<hex,fixed>() ) , ") overlaps with the partial address of the parent branch (" , Integer ( aAddr , IntFmt<hex,fixed>() ) , "). This might contradict the hierarchical design principal. For now this is a warning, but in the future this may be upgraded to throw an exception." );
610  }
611 
612  }
613  else
614  {
615  //Test for overlap with parent
616  if ( aNode->mPartialAddr & aAddr ) //should set the most significant bit of the child address and then AND this with the parent address
617  {
618  log ( Warning() , "The partial address of the top register in the current branch, " , Quote ( aNode->mUid ) , " , (" , Integer ( aNode->mPartialAddr , IntFmt<hex,fixed>() ) , ") overlaps with the partial address of the parent branch (" , Integer ( aAddr , IntFmt<hex,fixed>() ) , "). This might contradict the hierarchical design principal. For now this is a warning, but in the future this may be upgraded to throw an exception." );
619  }
620  */
621  }
622 
623  aNode->mAddr = aNode->mPartialAddr + aAddr;
624 
625  for ( std::deque< Node* >::iterator lIt = aNode->mChildren.begin(); lIt != aNode->mChildren.end(); ++lIt )
626  {
627  ( **lIt ).mParent = aNode;
628  calculateHierarchicalAddresses ( *lIt , aNode->mAddr );
629  }
630 
631  std::sort ( aNode->mChildren.begin() , aNode->mChildren.end() , NodeTreeBuilder::NodePtrCompare );
632  }
633 
634 
635 
636  void NodeTreeBuilder::checkForAddressCollisions ( Node* aNode , const boost::filesystem::path& aPath )
637  {
638  std::stringstream lReport;
639  lReport << std::hex << std::setfill ( '0' );
640  boost::unordered_map< std::string , Node* >::iterator lIt, lIt2;
641  Node* lNode1, *lNode2;
642 
643  for ( lIt = aNode->mChildrenMap.begin() ; lIt != aNode->mChildrenMap.end() ; ++lIt )
644  {
645  lNode1 = lIt->second;
646  lIt2 = lIt;
647  lIt2++;
648 
649  if ( lNode1->mMode == defs::INCREMENTAL )
650  {
651  uint32_t lBottom1 ( lNode1->mAddr );
652  uint32_t lTop1 ( lNode1->mAddr + ( lNode1->mSize - 1 ) );
653 
654  for ( ; lIt2 != aNode->mChildrenMap.end() ; ++lIt2 )
655  {
656  lNode2 = lIt2->second;
657 
658  if ( lNode2->mMode == defs::INCREMENTAL )
659  {
660  //Node1 and Node2 are both incremental
661  uint32_t lBottom2 ( lNode2->mAddr );
662  uint32_t lTop2 ( lNode2->mAddr + ( lNode2->mSize - 1 ) );
663 
664  if ( ( ( lTop2 >= lBottom1 ) && ( lTop2 <= lTop1 ) ) || ( ( lTop1 >= lBottom2 ) && ( lTop1 <= lTop2 ) ) )
665  {
666  lReport << "Branch '" << lIt->first
667  << "' has address range [0x" << std::setw ( 8 ) << lBottom1 << " - 0x" << std::setw ( 8 ) << lTop1
668  << "] which overlaps with branch '" << lIt2->first
669  << "' which has address range [0x" << std::setw ( 8 ) << lBottom2 << " - 0x" << std::setw ( 8 ) << lTop2
670  << "]." << std::endl;
671 #ifdef THROW_ON_ADDRESS_SPACE_OVERLAP
672  throw exception::AddressSpaceOverlap();
673 #endif
674  }
675  }
676  else if ( lNode2->mMode != defs::HIERARCHICAL )
677  {
678  //Node1 is incremental and Node2 is single address
679  uint32_t lAddr2 ( lNode2->mAddr );
680 
681  if ( ( lAddr2 >= lBottom1 ) && ( lAddr2 <= lTop1 ) )
682  {
683  lReport << "Branch '" << lIt->first
684  << "' has address range [0x" << std::setw ( 8 ) << lBottom1 << " - 0x" << std::setw ( 8 ) << lTop1
685  << "] which overlaps with branch '" << lIt2->first
686  << "' which has address 0x" << std::setw ( 8 ) << lAddr2
687  << "." << std::endl;
688 #ifdef THROW_ON_ADDRESS_SPACE_OVERLAP
689  throw exception::AddressSpaceOverlap();
690 #endif
691  }
692  }
693  }
694  }
695  else if ( lNode1->mMode != defs::HIERARCHICAL )
696  {
697  uint32_t lAddr1 ( lNode1->mAddr );
698 
699  for ( ; lIt2 != aNode->mChildrenMap.end() ; ++lIt2 )
700  {
701  lNode2 = lIt2->second;
702 
703  if ( lNode2->mMode == defs::INCREMENTAL )
704  {
705  //Node1 is single address and Node2 is incremental
706  uint32_t lBottom2 ( lNode2->mAddr );
707  uint32_t lTop2 ( lNode2->mAddr + ( lNode2->mSize - 1 ) );
708 
709  if ( ( lAddr1 >= lBottom2 ) && ( lAddr1 <= lTop2 ) )
710  {
711  lReport << "Branch '" << lIt->first
712  <<"' has address 0x" << std::setw ( 8 ) << lAddr1
713  <<" which overlaps with branch '" << lIt2->first
714  <<"' which has address range [0x" << std::setw ( 8 ) << lBottom2 << " - 0x" << std::setw ( 8 ) << lTop2
715  << "]."<< std::endl;
716 #ifdef THROW_ON_ADDRESS_SPACE_OVERLAP
717  throw exception::AddressSpaceOverlap();
718 #endif
719  }
720  }
721  else if ( lNode2->mMode != defs::HIERARCHICAL )
722  {
723  //Node1 and Node2 are both single addresses
724  uint32_t lAddr2 ( lNode2->mAddr );
725 
726  if ( lAddr1 == lAddr2 )
727  {
728  if ( lNode1->mMask & lNode2->mMask )
729  {
730  bool lShouldThrow ( true );
731 
732  if ( lNode1->mMask == 0xFFFFFFFF )
733  {
734  // Node 1 is a full register, Node 2 is a masked region. Check if Node 2 is a child of Node 1 and, if not, then throw
735  for ( std::deque< Node* >::iterator lIt = lNode1->mChildren.begin() ; lIt != lNode1->mChildren.end() ; ++lIt )
736  {
737  if ( *lIt == lNode2 )
738  {
739  lShouldThrow = false;
740  break;
741  }
742  }
743  }
744 
745  if ( lShouldThrow && ( lNode2->mMask == 0xFFFFFFFF ) )
746  {
747  // Node 2 is a full register, Node 1 is a masked region. Check if Node 1 is a child of Node 2 and, if not, then throw
748  for ( std::deque< Node* >::iterator lIt = lNode2->mChildren.begin() ; lIt != lNode2->mChildren.end() ; ++lIt )
749  {
750  if ( *lIt == lNode1 )
751  {
752  lShouldThrow = false;
753  break;
754  }
755  }
756  }
757 
758  if ( lShouldThrow )
759  {
760  lReport << "Branch '" << lIt->first
761  << "' has address 0x" << std::setw ( 8 ) << lAddr1
762  << " and mask 0x" << std::setw ( 8 ) << lNode1->mMask
763  << " which overlaps with branch '" << lIt2->first
764  << "' which has address 0x" << std::setw ( 8 ) << lAddr2
765  << " and mask 0x" << std::setw ( 8 ) << lNode2->mMask
766  << "." << std::endl;
767 #ifdef THROW_ON_ADDRESS_SPACE_OVERLAP
768  throw exception::AddressSpaceOverlap();
769 #endif
770  }
771  }
772  }
773  }
774  }
775  }
776  }
777 
778  if ( lReport.tellp() )
779  {
780  // Add username to the collisions report filepath if environment variable USER is defined
781  std::string lDirName("/tmp");
782  if (char* lUsername = std::getenv("USER"))
783  {
784  lDirName += "/" + std::string(lUsername);
785  }
786  lDirName += "/uhal";
787 
788  boost::filesystem::path lDir ( lDirName );
789  lDir.make_preferred();
790 
791  try{
792  if ( !boost::filesystem::is_directory ( lDir ) )
793  {
794  if ( !boost::filesystem::create_directories ( lDir ) )
795  {
796  log ( Error() , "Address overlaps observed - attempted and failed to create directory " , Quote ( lDirName ) );
797  return;
798  }
799  }
800  }
801  catch(const boost::filesystem::filesystem_error& e)
802  {
803  log ( Error() , "Address overlaps observed - failed to create directory " , Quote ( lDirName ) , " for report file; caught filesystem_error exception with what returning: ", e.what() );
804  return;
805  }
806 
807  std::string lFilename ( aPath.string() );
808  boost::replace_all ( lFilename , "/" , "-" );
809  lDir /= ( "OverlapReport" + lFilename + ".txt" );
810  std::ofstream lReportFile ( lDir.c_str() );
811 
812  if ( lReportFile.is_open() )
813  {
814  lReportFile << "Overlap report for " << aPath << "." << std::endl;
815  lReportFile << "Written at " << boost::posix_time::microsec_clock::local_time() << "." << std::endl;
816  lReportFile << std::endl;
817  lReportFile << lReport.rdbuf();
818  lReportFile.close();
819  log ( Warning() , "Address overlaps observed - report file written at " , Quote ( lDir.string() ) );
820  }
821  else
822  {
823  log ( Error() , "Address overlaps observed - failed to create report file " , Quote ( lDir.string() ) );
824  }
825  }
826  }
827 
828 
829 
830 
831 
832 
834  {
835  add
836  ( "r" , defs::READ )
837  ( "w" , defs::WRITE )
838  ( "read" , defs::READ )
839  ( "write" , defs::WRITE )
840  ( "rw" , defs::READWRITE )
841  ( "wr" , defs::READWRITE )
842  ( "readwrite" , defs::READWRITE )
843  ( "writeread" , defs::READWRITE )
844  ;
845  }
846 
848 
849 
851  {
852  add
853  ( "single" , defs::SINGLE )
854  ( "block" , defs::INCREMENTAL )
855  ( "port" , defs::NON_INCREMENTAL )
856  ( "incremental" , defs::INCREMENTAL )
857  ( "non-incremental" , defs::NON_INCREMENTAL )
858  ( "inc" , defs::INCREMENTAL )
859  ( "non-inc" , defs::NON_INCREMENTAL )
860  ;
861  }
862 
864 
865 }
NoticeLevel Notice
Definition: LogLevels.cpp:96
A class to build a node tree from an Address table file NOTE! This is a factory method and must be Mu...
void ParseSemicolonDelimitedUriList(const std::string &aSemicolonDelimitedUriList, std::vector< std::pair< std::string, std::string > > &aUriList)
Parse a semicolon delimited list of URIs into a vector of protocol/address pairs. ...
Definition: files.cpp:46
void setTags(const pugi::xml_node &aXmlNode, Node *aNode)
A look-up table that the boost qi parser uses for associating strings ("r","w","rw","wr","read","write","readwrite","writeread") with enumerated permissions types.
boost::unordered_map< std::string, std::string > mFirmwareInfo
parameters to infer the VHDL address decoding
Definition: Node.hpp:372
grammars::NodeTreeFirmwareinfoAttributeGrammar mNodeTreeFirmwareInfoAttributeGrammar
Node * bitmaskNodeCreator(const bool &aRequireId, const pugi::xml_node &aXmlNode)
std::string mClassName
Class name used to construct the derived node type.
Definition: Node.hpp:366
boost::unordered_map< std::string, const Node *> mNodes
Hash map associating a Node tree with a file name so that we do not need to repeatedly parse the xml ...
static const char * mParametersAttribute
static NodeTreeBuilder * mInstance
The single instance of the class.
Rule< R > & optional(const std::string &aStr)
Add an optional attribute to the rule.
Definition: XmlParser.hxx:128
uhal::NodeTreeBuilder::mode_lut mModeLut
An instance of a look-up table that the boost qi parser uses for associating strings with enumerated ...
static const char * mModeAttribute
void setModeAndSize(const pugi::xml_node &aXmlNode, Node *aNode)
static bool NodePtrCompare(Node *aNodeL, Node *aNodeR)
defs::NodePermission mPermission
The read/write access permissions of this node.
Definition: Node.hpp:350
static const char * mAddressAttribute
void clearAddressFileCache()
Clears address filename -> Node tree cache. NOT thread safe; for tread-safety, use ConnectionManager ...
permissions_lut()
The actual function that the boost qi parser uses for associating strings with enumerated permissions...
void setUid(const bool &aRequireId, const pugi::xml_node &aXmlNode, Node *aNode)
void CallBack(const std::string &aProtocol, const boost::filesystem::path &aPath, std::vector< uint8_t > &aFile, std::vector< const Node * > &aAddressTable)
Method called once the file specified in the call to getNodeTree( aFilenameExpr ) has been opened...
defs::BlockReadWriteMode mMode
Whether the node represents a single register, a block of registers or a block-read/write port...
Definition: Node.hpp:352
WarningLevel Warning
Definition: LogLevels.cpp:79
std::string mTags
Optional string which the user can specify.
Definition: Node.hpp:357
template bool GetXMLattribute< true >(const pugi::xml_node &aNode, const char *aAttrName, std::string &aTarget)
Parser< Node *> mNodeParser
uint32_t mSize
The maximum size available to a block read/write.
Definition: Node.hpp:354
uhal::NodeTreeBuilder::permissions_lut mPermissionsLut
An instance of a look-up table that the boost qi parser uses for associating strings with enumerated ...
Node * moduleNodeCreator(const bool &aRequireId, const pugi::xml_node &aXmlNode)
std::string mDescription
Optional string which the user can specify.
Definition: Node.hpp:360
const uint32_t NOMASK
define what it means to have no mask
Definition: definitions.hpp:56
void setFirmwareInfo(const pugi::xml_node &aXmlNode, Node *aNode)
static const char * mModuleAttribute
void addChildren(const pugi::xml_node &aXmlNode, Node *aNode)
Node * plainNodeCreator(const bool &aRequireId, const pugi::xml_node &aXmlNode)
void setClassName(const pugi::xml_node &aXmlNode, Node *aNode)
std::string mModule
The name of the module in which the current node resides.
Definition: Node.hpp:363
boost::unordered_map< std::string, std::string > mParameters
Additional parameters of the node.
Definition: Node.hpp:369
uint32_t mPartialAddr
The register address with which this node is associated.
Definition: Node.hpp:343
static const char * mMaskAttribute
std::deque< boost::filesystem::path > mFileCallStack
uint32_t mMask
The mask to be applied if this node is a sub-field, rather than an entire register.
Definition: Node.hpp:348
ErrorLevel Error
Definition: LogLevels.cpp:61
static const char * mSizeAttribute
void PugiXMLParseResultPrettifier(const pugi::xml_parse_result &aLoadResult, const boost::filesystem::path &aPath, const std::vector< uint8_t > &aFile)
Helper function to make debugging failures when parsing XML files easier.
Definition: xml.cpp:57
void setAddr(const pugi::xml_node &aXmlNode, Node *aNode)
static const char * mPermissionsAttribute
A heirarchical node for navigating heirarchical firmwares.
Definition: Node.hpp:83
Empty struct which acts as a dummy variable for passing the formatting information around...
_Quote< T > Quote(const T &aT)
Rule< R > & require(const std::string &aStr)
Add a required attribute to the rule.
Definition: XmlParser.hxx:100
Struct to store the name and member variables within a node endpoint attribute when parsed by boost s...
Node * convertToClassType(Node *aNode)
void setMask(const pugi::xml_node &aXmlNode, Node *aNode)
void checkForAddressCollisions(Node *aNode, const boost::filesystem::path &aPath)
std::deque< Node *> mChildren
The direct children of the node.
Definition: Node.hpp:378
static const char * mFirmwareInfo
static NodeTreeBuilder & getInstance()
Static method to retrieve the single instance of the class.
Rule for matching XML attributes.
Definition: XmlParser.hpp:146
static const char * mTagsAttribute
static const char * mDescriptionAttribute
static const char * mIdAttribute
uint32_t mAddr
The register address with which this node is associated.
Definition: Node.hpp:345
void setModule(const pugi::xml_node &aXmlNode, Node *aNode)
void calculateHierarchicalAddresses(Node *aNode, const uint32_t &aAddr)
Propagate the addresses down through the hierarchical structure.
#define ThisLocation()
void setPermissions(const pugi::xml_node &aXmlNode, Node *aNode)
std::string mUid
The Unique ID of this node.
Definition: Node.hpp:340
A look-up table that the boost qi parser uses for associating strings ("single","block","port","incremental","non-incremental","inc","non-inc") with enumerated mode types.
Hexadecimal.
DebugLevel Debug
Definition: LogLevels.cpp:133
void OpenFile(const std::string &aProtocol, const std::string &aFilenameExpr, const boost::filesystem::path &aParentPath, boost::_bi::bind_t< R, F, L > aBinder)
Given a protocol and either a URL or a linux shell expression, open the file and call the callback fu...
Definition: files.hpp:359
static DerivedNodeFactory & getInstance()
Static method to retrieve the single instance of the class.
Parser< Node *> mTopLevelNodeParser
grammars::NodeTreeParametersGrammar mNodeTreeParametersGrammar
boost::unordered_map< std::string, Node *> mChildrenMap
Helper to assist look-up of a particular child node, given a name.
Definition: Node.hpp:381
NodeTreeBuilder()
Default constructor This is private since only a single instance is to be created, using the getInstance method.
static const char * mClassAttribute
void setDescription(const pugi::xml_node &aXmlNode, Node *aNode)
InfoLevel Info
Definition: LogLevels.cpp:114
mode_lut()
The actual function that the boost qi parser uses for associating strings with enumerated permissions...
virtual ~NodeTreeBuilder()
Destructor.
template bool GetXMLattribute< false >(const pugi::xml_node &aNode, const char *aAttrName, std::string &aTarget)
void setPars(const pugi::xml_node &aXmlNode, Node *aNode)
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
Node * getNodeTree(const std::string &aFilenameExpr, const boost::filesystem::path &aPath)
Construct a node tree from file whose name is specified.