μHAL (v2.7.9)
Part of the IPbus software repository
test_nodes.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  Tom Williams, Rutherford Appleton Laboratory, Oxfordshire
24  email: tom.williams <AT> cern.ch
25 
26 ---------------------------------------------------------------------------
27 */
28 
29 #include <iomanip>
30 #include <typeinfo>
31 
32 #include "uhal/NodeTreeBuilder.hpp"
33 #include "uhal/utilities/xml.hpp"
34 #include "uhal/uhal.hpp"
35 
38 #include "uhal/tests/fixtures.hpp"
39 
40 #include <boost/filesystem.hpp>
41 #include <boost/test/unit_test.hpp>
42 
43 
44 
45 namespace uhal {
46 
47 
48 std::ostream& operator<< (std::ostream& aStream, const std::pair<const Node*, const Node*>& aNodes)
49 {
50  aStream << "{";
51  if (aNodes.first != NULL)
52  aStream << "'" << aNodes.first->getPath() << "'";
53  else
54  aStream << "NULL";
55 
56  aStream << ", ";
57  if (aNodes.second != NULL)
58  aStream << "'" << aNodes.second->getPath() << "'";
59  else
60  aStream << "NULL";
61 
62  aStream << "}";
63  return aStream;
64 }
65 
66 
67 namespace tests {
68 
70  NodeProperties(const std::string& aIdPath, const uint32_t aAddress, const defs::BlockReadWriteMode aMode, const defs::NodePermission aPermission, const size_t aSize, const std::string& aModule, const size_t aNrDescendants);
72 
73  std::string path;
74  std::string id;
75  uint32_t address;
78  size_t size;
79  uint32_t mask;
80  std::string description;
81  std::string module;
82  std::vector<std::string> descendantIds;
83  std::map<std::string, const std::type_info*> descendantTypes;
84  std::string tags;
85  boost::unordered_map<std::string,std::string> parameters;
86  boost::unordered_map<std::string,std::string> fwInfo;
87  const std::type_info* type;
88 };
89 
90 
92 public:
95 
96  const std::string addrTableStr;
98 
99  std::vector<NodeProperties> nodeProperties;
100 };
101 
102 
104 public:
107 
108  const std::string addrTableStr;
110 
111  std::vector<NodeProperties> nodeProperties;
112 };
113 
114 
117 public:
120 
121  std::string getAddrFileAbsPath(const std::string& aSuffix)
122  {
123  std::string lResult(addrFileAbsPath);
124  lResult.replace(addrFileAbsPath.size() - 11, 7, aSuffix);
125  return lResult;
126  }
127 
128  const std::string addrFileURI;
129  const std::string addrFileAbsPath;
132  std::vector<NodeProperties> nodeProperties;
133 };
134 
135 
136 
137 NodeProperties::NodeProperties(const std::string& aIdPath, const uint32_t aAddress, const defs::BlockReadWriteMode aMode, const defs::NodePermission aPermission, const size_t aSize, const std::string& aModule, const size_t aNrDescendants) :
138  path(aIdPath),
139  id((aIdPath.rfind('.') == std::string::npos) ? aIdPath : aIdPath.substr(aIdPath.rfind('.') + 1)),
140  address(aAddress),
141  mode(aMode),
142  permission(aPermission),
143  size(aSize),
144  mask(defs::NOMASK),
145  module(aModule),
146  descendantIds(aNrDescendants),
147  type(&typeid(Node))
148 {
149 }
150 
151 
153  addrTableStr("<node>"
154  "<node id='regA' address='0x0' />"
155  "<node id='regB' address='0x1' />"
156  "<node id='ram1' address='0x100' mode='block' size='256' />"
157  "<node id='ram2' address='0x210' mode='block' size='16' />"
158  "<node id='aPort' address='0x300' mode='port' size='1024' />"
159  "</node>")
160 {
161  BOOST_REQUIRE(addrTableDoc.load(addrTableStr.c_str()));
162 
163  nodeProperties.push_back(NodeProperties("regA", 0, defs::SINGLE, defs::READWRITE, 1, "", 0));
164  nodeProperties.push_back(NodeProperties("regB", 1, defs::SINGLE, defs::READWRITE, 1, "", 0));
165  nodeProperties.push_back(NodeProperties("ram1", 256, defs::INCREMENTAL, defs::READWRITE, 256, "", 0));
166  nodeProperties.push_back(NodeProperties("ram2", 528, defs::INCREMENTAL, defs::READWRITE, 16, "", 0));
167  nodeProperties.push_back(NodeProperties("aPort", 768, defs::NON_INCREMENTAL, defs::READWRITE, 1024, "", 0));
168 }
169 
170 
172  addrTableStr("<node>"
173  "<node id='reg1' address='0x0'/>"
174  "<node id='reg2' address='0x1'/>"
175 
176  "<node id='reg3' address='0x2'>"
177  " <node id='A' mask='0x0000ffff'/>"
178  " <node id='B' mask='0xffff0000'/>"
179  "</node>"
180  "<node id='reg4' address='0x3'>"
181  " <node id='A' mask='0x000000ff'/>"
182  " <node id='B' mask='0x0000ff00'/>"
183  " <node id='C' mask='0x00ff0000'/>"
184  " <node id='D' mask='0xff000000'/>"
185  "</node>"
186 
187  "<node id='port1' address='0x4' mode='port' size='256'/>"
188  "<node id='port2' address='0x5' mode='port' size='1024'/>"
189  "<node id='ram1' address='0x08' mode='block' size='8'/>"
190  "<node id='ram2' address='0x10' mode='block' size='16'/>"
191 
192  "<node id='module1' address='0x40'>"
193  " <node id='reg1' address='0x0'/>"
194  " <node id='reg2' address='0x1'>"
195  " <node id='mask1' mask='0x00000fff'/>"
196  " <node id='mask2' mask='0x00fff000'/>"
197  " <node id='mask3' mask='0xff000000'/>"
198  " </node>"
199  " <node id='port' address='0x2' mode='port' size='256'/>"
200  " <node id='ram' address='0x10' mode='block' size='16'/>"
201  "</node>"
202 
203  "<node id='module2' address='0x60'>"
204  " <node id='regA' address='0x0'/>"
205  " <node id='regB' address='0x1'>"
206  " <node id='A' mask='0x00000fff'/>"
207  " <node id='B' mask='0x00fff000'/>"
208  " <node id='C' mask='0xff000000'/>"
209  " </node>"
210  " <node id='fifo' address='0x2' mode='port' size='256'/>"
211  " <node id='block' address='0x10' mode='block' size='16'/>"
212  "</node>"
213  "</node>")
214 {
215  BOOST_REQUIRE(addrTableDoc.load(addrTableStr.c_str()));
216 
217  nodeProperties.push_back(NodeProperties("reg1", 0, defs::SINGLE, defs::READWRITE, 1, "", 0));
218  nodeProperties.push_back(NodeProperties("reg2", 1, defs::SINGLE, defs::READWRITE, 1, "", 0));
219  nodeProperties.push_back(NodeProperties("reg3", 2, defs::SINGLE, defs::READWRITE, 1, "", 2));
220  nodeProperties.push_back(NodeProperties("reg3.A", 2, defs::SINGLE, defs::READWRITE, 1, "", 0));
221  nodeProperties.back().mask = 0xffff;
222  nodeProperties.push_back(NodeProperties("reg3.B", 2, defs::SINGLE, defs::READWRITE, 1, "", 0));
223  nodeProperties.back().mask = 0xffff0000;
224  nodeProperties.push_back(NodeProperties("reg4", 3, defs::SINGLE, defs::READWRITE, 1, "", 4));
225  nodeProperties.push_back(NodeProperties("reg4.A", 3, defs::SINGLE, defs::READWRITE, 1, "", 0));
226  nodeProperties.back().mask = 0xff;
227  nodeProperties.push_back(NodeProperties("reg4.B", 3, defs::SINGLE, defs::READWRITE, 1, "", 0));
228  nodeProperties.back().mask = 0xff00;
229  nodeProperties.push_back(NodeProperties("reg4.C", 3, defs::SINGLE, defs::READWRITE, 1, "", 0));
230  nodeProperties.back().mask = 0xff0000;
231  nodeProperties.push_back(NodeProperties("reg4.D", 3, defs::SINGLE, defs::READWRITE, 1, "", 0));
232  nodeProperties.back().mask = 0xff000000;
233 
234  nodeProperties.push_back(NodeProperties("port1", 4, defs::NON_INCREMENTAL, defs::READWRITE, 256, "", 0));
235  nodeProperties.push_back(NodeProperties("port2", 5, defs::NON_INCREMENTAL, defs::READWRITE, 1024, "", 0));
236  nodeProperties.push_back(NodeProperties("ram1", 8, defs::INCREMENTAL, defs::READWRITE, 8, "", 0));
237  nodeProperties.push_back(NodeProperties("ram2", 16, defs::INCREMENTAL, defs::READWRITE, 16, "", 0));
238 
239  nodeProperties.push_back(NodeProperties("module1", 64, defs::HIERARCHICAL, defs::READWRITE, 1, "", 7));
240  nodeProperties.push_back(NodeProperties("module1.reg1", 64, defs::SINGLE, defs::READWRITE, 1, "", 0));
241  nodeProperties.push_back(NodeProperties("module1.reg2", 65, defs::SINGLE, defs::READWRITE, 1, "", 3));
242  nodeProperties.push_back(NodeProperties("module1.reg2.mask1", 65, defs::SINGLE, defs::READWRITE, 1, "", 0));
243  nodeProperties.back().mask = 0xfff;
244  nodeProperties.push_back(NodeProperties("module1.reg2.mask2", 65, defs::SINGLE, defs::READWRITE, 1, "", 0));
245  nodeProperties.back().mask = 0xfff000;
246  nodeProperties.push_back(NodeProperties("module1.reg2.mask3", 65, defs::SINGLE, defs::READWRITE, 1, "", 0));
247  nodeProperties.back().mask = 0xff000000;
248  nodeProperties.push_back(NodeProperties("module1.port", 66, defs::NON_INCREMENTAL, defs::READWRITE, 256, "", 0));
249  nodeProperties.push_back(NodeProperties("module1.ram", 80, defs::INCREMENTAL, defs::READWRITE, 16, "", 0));
250 
251  nodeProperties.push_back(NodeProperties("module2", 96, defs::HIERARCHICAL, defs::READWRITE, 1, "", 7));
252  nodeProperties.push_back(NodeProperties("module2.regA", 96, defs::SINGLE, defs::READWRITE, 1, "", 0));
253  nodeProperties.push_back(NodeProperties("module2.regB", 97, defs::SINGLE, defs::READWRITE, 1, "", 3));
254  nodeProperties.push_back(NodeProperties("module2.regB.A", 97, defs::SINGLE, defs::READWRITE, 1, "", 0));
255  nodeProperties.back().mask = 0xfff;
256  nodeProperties.push_back(NodeProperties("module2.regB.B", 97, defs::SINGLE, defs::READWRITE, 1, "", 0));
257  nodeProperties.back().mask = 0xfff000;
258  nodeProperties.push_back(NodeProperties("module2.regB.C", 97, defs::SINGLE, defs::READWRITE, 1, "", 0));
259  nodeProperties.back().mask = 0xff000000;
260  nodeProperties.push_back(NodeProperties("module2.fifo", 98, defs::NON_INCREMENTAL, defs::READWRITE, 256, "", 0));
261  nodeProperties.push_back(NodeProperties("module2.block", 112, defs::INCREMENTAL, defs::READWRITE, 16, "", 0));
262 
263  for (size_t i=0; i < nodeProperties.size(); i++) {
264  BOOST_REQUIRE_LE(nodeProperties.at(i).descendantIds.size(), (nodeProperties.size() - i - 1));
265  for (size_t j=0; j < nodeProperties.at(i).descendantIds.size(); j++) {
266  std::string lRelativePath = nodeProperties.at(i+j+1).path.substr(nodeProperties.at(i).path.empty() ? 0 : nodeProperties.at(i).path.size() + 1);
267  nodeProperties.at(i).descendantIds.at(j) = lRelativePath;
268  nodeProperties.at(i).descendantTypes[lRelativePath] = nodeProperties.at(i+j+1).type;
269  }
270  }
271 }
272 
273 
275  AbstractFixture(),
276  addrFileURI(getAddressFileURI()),
277  addrFileAbsPath(boost::filesystem::absolute(boost::filesystem::path(addrFileURI.substr(7))).native()),
278  addrFileLevel2AbsPath(addrFileAbsPath),
279  addrFileLevel3AbsPath(addrFileAbsPath)
280 {
281  addrFileLevel2AbsPath.replace(addrFileAbsPath.size() - 11, 0, "level2_");
282  addrFileLevel3AbsPath.replace(addrFileAbsPath.size() - 11, 0, "level3_");
283 
285 
287  nodeProperties.back().tags = "test";
288  nodeProperties.push_back(NodeProperties("REG_READ_ONLY", 2, defs::SINGLE, defs::READ, 1, addrFileAbsPath, 0));
289  nodeProperties.push_back(NodeProperties("REG_WRITE_ONLY", 3, defs::SINGLE, defs::WRITE, 1, addrFileAbsPath, 0));
290  nodeProperties.push_back(NodeProperties("REG_UPPER_MASK", 4, defs::SINGLE, defs::READWRITE, 1, addrFileAbsPath, 0));
291  nodeProperties.back().mask = 0xffff0000;
292  nodeProperties.push_back(NodeProperties("REG_LOWER_MASK", 4, defs::SINGLE, defs::READWRITE, 1, addrFileAbsPath, 0));
293  nodeProperties.back().mask = 0xffff;
294  nodeProperties.push_back(NodeProperties("REG_MASKED_READ_ONLY", 5, defs::SINGLE, defs::READ, 1, addrFileAbsPath, 0));
295  nodeProperties.back().mask = 0xffff0000;
296  nodeProperties.push_back(NodeProperties("REG_MASKED_WRITE_ONLY", 5, defs::SINGLE, defs::WRITE, 1, addrFileAbsPath, 0));
297  nodeProperties.back().mask = 0xffff;
298  nodeProperties.push_back(NodeProperties("REG_PARS", 6, defs::SINGLE, defs::READWRITE, 1, addrFileAbsPath, 0));
299  nodeProperties.back().parameters["arg0"] = "val100";
300  nodeProperties.back().parameters["arg1"] = "val101";
301  nodeProperties.push_back(NodeProperties("FIFO", 0x100, defs::NON_INCREMENTAL, defs::READWRITE, 268435456, addrFileAbsPath, 0));
302  nodeProperties.back().tags = "test";
303  nodeProperties.push_back(NodeProperties("REG_OUT_OF_ORDER", 6, defs::SINGLE, defs::READWRITE, 1, addrFileAbsPath, 0));
304  nodeProperties.push_back(NodeProperties("MEM", 0x100000, defs::INCREMENTAL, defs::READWRITE, 262144, addrFileAbsPath, 0));
305  nodeProperties.back().description = "A block memory in an example XML file";
306 
307  nodeProperties.push_back(NodeProperties("SUBSYSTEM1", 0x210001, defs::HIERARCHICAL, defs::READWRITE, 1, addrFileAbsPath, 5));
308  nodeProperties.back().parameters["arg0"] = "val200";
309  nodeProperties.back().parameters["arg1"] = "val201";
310  nodeProperties.back().parameters["arg2"] = "val202";
311  nodeProperties.push_back(NodeProperties("SUBSYSTEM1.REG", 0x210002, defs::SINGLE, defs::READWRITE, 1, addrFileLevel2AbsPath, 0));
312  nodeProperties.back().tags = "test";
313  nodeProperties.push_back(NodeProperties("SUBSYSTEM1.MEM", 0x210003, defs::INCREMENTAL, defs::READWRITE, 262144, addrFileLevel2AbsPath, 0));
314  nodeProperties.back().tags = "test";
315  nodeProperties.push_back(NodeProperties("SUBSYSTEM1.SUBMODULE", 0x270001, defs::HIERARCHICAL, defs::READWRITE, 1, addrFileLevel2AbsPath, 2));
316  nodeProperties.back().parameters["arg0"] = "val300";
317  nodeProperties.back().parameters["arg1"] = "val301";
318  nodeProperties.back().parameters["arg2"] = "val10302";
319  nodeProperties.back().parameters["arg3"] = "val10303";
320  nodeProperties.push_back(NodeProperties("SUBSYSTEM1.SUBMODULE.REG", 0x270002, defs::SINGLE, defs::READWRITE, 1, addrFileLevel3AbsPath, 0));
321  nodeProperties.back().tags = "test";
322  nodeProperties.push_back(NodeProperties("SUBSYSTEM1.SUBMODULE.MEM", 0x270003, defs::INCREMENTAL, defs::READWRITE, 256, addrFileLevel3AbsPath, 0));
323  nodeProperties.back().tags = "test";
324 
325  nodeProperties.push_back(NodeProperties("SUBSYSTEM2", 0x310001, defs::HIERARCHICAL, defs::READWRITE, 1, addrFileAbsPath, 5));
326  nodeProperties.back().parameters["arg0"] = "val10000";
327  nodeProperties.back().parameters["arg1"] = "val201";
328  nodeProperties.back().parameters["arg2"] = "val202";
329  nodeProperties.back().parameters["arg5"] = "val10005";
330  nodeProperties.push_back(NodeProperties("SUBSYSTEM2.REG", 0x310002, defs::SINGLE, defs::READWRITE, 1, addrFileLevel2AbsPath, 0));
331  nodeProperties.back().tags = "test";
332  nodeProperties.push_back(NodeProperties("SUBSYSTEM2.MEM", 0x310003, defs::INCREMENTAL, defs::READWRITE, 262144, addrFileLevel2AbsPath, 0));
333  nodeProperties.back().tags = "test";
334  nodeProperties.push_back(NodeProperties("SUBSYSTEM2.SUBMODULE", 0x370001, defs::HIERARCHICAL, defs::READWRITE, 1, addrFileLevel2AbsPath, 2));
335  nodeProperties.back().parameters["arg0"] = "val300";
336  nodeProperties.back().parameters["arg1"] = "val301";
337  nodeProperties.back().parameters["arg2"] = "val10302";
338  nodeProperties.back().parameters["arg3"] = "val10303";
339  nodeProperties.push_back(NodeProperties("SUBSYSTEM2.SUBMODULE.REG", 0x370002, defs::SINGLE, defs::READWRITE, 1, addrFileLevel3AbsPath, 0));
340  nodeProperties.back().tags = "test";
341  nodeProperties.push_back(NodeProperties("SUBSYSTEM2.SUBMODULE.MEM", 0x370003, defs::INCREMENTAL, defs::READWRITE, 256, addrFileLevel3AbsPath, 0));
342  nodeProperties.back().tags = "test";
343 
344  nodeProperties.push_back(NodeProperties("SMALL_MEM", 0x400000, defs::INCREMENTAL, defs::READWRITE, 256, addrFileAbsPath, 0));
345  nodeProperties.push_back(NodeProperties("LARGE_MEM", 0x1000000, defs::INCREMENTAL, defs::READWRITE, 26214400, addrFileAbsPath, 0));
346 
347  nodeProperties.push_back(NodeProperties("SUBSYSTEM3", 0x600000, defs::HIERARCHICAL, defs::READWRITE, 1, addrFileAbsPath, 28));
348 
349  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDNODE", 0x600000, defs::HIERARCHICAL, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 4));
350  nodeProperties.back().type = &typeid(DummyParentNode);
351  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDNODE.REG", 0x600001, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 0));
352  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDNODE.REG_WRITE_ONLY", 0x600003, defs::SINGLE, defs::WRITE, 1, getAddrFileAbsPath("derived_address"), 0));
353  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDNODE.REG_UPPER_MASK", 0x600004, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 0));
354  nodeProperties.back().mask = 0xFFFF0000;
355  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDNODE.REG_LOWER_MASK", 0x600004, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 0));
356  nodeProperties.back().mask = 0xFFFF;
357 
358  // 0x600000 + 0x10 + 0x10010
359  const uint32_t lDerivedModule1Addr = 0x600000 + (0x10 | 0x10010);
360  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE1", lDerivedModule1Addr, defs::HIERARCHICAL, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 2));
361  nodeProperties.back().type = &typeid(DummyChildNode);
362  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE1.REG", lDerivedModule1Addr + 1, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_level2_module1"), 0));
363  nodeProperties.back().tags = "test";
364  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE1.MEM", lDerivedModule1Addr + 2, defs::INCREMENTAL, defs::READWRITE, 262144, getAddrFileAbsPath("derived_level2_module1"), 0));
365  nodeProperties.back().tags = "test";
366 
367  const uint32_t lDerivedModule2Addr = 0x600000 + (0x30 | 0x10010 | 0x10010);
368  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE2", lDerivedModule2Addr, defs::HIERARCHICAL, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 4));
369  nodeProperties.back().parameters["arg3"] = "val3";
370  nodeProperties.back().type = &typeid(DummyChildNode);
371  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE2.REG", lDerivedModule2Addr + 1, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_level3_plain"), 0));
372  nodeProperties.back().tags = "test";
373  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE2.REG_WRITE_ONLY", lDerivedModule2Addr + 3, defs::SINGLE, defs::WRITE, 1, getAddrFileAbsPath("derived_level3_plain"), 0));
374  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE2.REG_UPPER_MASK", lDerivedModule2Addr + 4, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_level3_plain"), 0));
375  nodeProperties.back().mask = 0xFFFF0000;
376  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE2.REG_LOWER_MASK", lDerivedModule2Addr + 4, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_level3_plain"), 0));
377  nodeProperties.back().mask = 0xFFFF;
378 
379  const uint32_t lDerivedModule3Addr = 0x600000 + (0x50 | 0x10010 | 0x10010);
380  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE3", lDerivedModule3Addr, defs::HIERARCHICAL, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 4));
381  nodeProperties.back().parameters["arg3"] = "val3";
382  nodeProperties.back().type = &typeid(DummyChildNode);
383  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE3.REG", lDerivedModule3Addr + 1, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_level3_class"), 0));
384  nodeProperties.back().tags = "test";
385  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE3.REG_WRITE_ONLY", lDerivedModule3Addr + 3, defs::SINGLE, defs::WRITE, 1, getAddrFileAbsPath("derived_level3_class"), 0));
386  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE3.REG_UPPER_MASK", lDerivedModule3Addr + 4, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_level3_class"), 0));
387  nodeProperties.back().mask = 0xFFFF0000;
388  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE3.REG_LOWER_MASK", lDerivedModule3Addr + 4, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_level3_class"), 0));
389  nodeProperties.back().mask = 0xFFFF;
390 
391  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE4", 0x610070, defs::HIERARCHICAL, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 4));
392  nodeProperties.back().type = &typeid(DummyChildNode);
393  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE4.REG", 0x610071, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_level3_class"), 0));
394  nodeProperties.back().tags = "test";
395  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE4.REG_WRITE_ONLY", 0x610073, defs::SINGLE, defs::WRITE, 1, getAddrFileAbsPath("derived_level3_class"), 0));
396  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE4.REG_UPPER_MASK", 0x610074, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_level3_class"), 0));
397  nodeProperties.back().mask = 0xFFFF0000;
398  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.DERIVEDMODULE4.REG_LOWER_MASK", 0x610074, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_level3_class"), 0));
399  nodeProperties.back().mask = 0xFFFF;
400 
401  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.BADNODE", 0x600100, defs::HIERARCHICAL, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 4));
402  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.BADNODE.REG", 0x600101, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 0));
403  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.BADNODE.REG_WRITE_ONLY", 0x600103, defs::SINGLE, defs::WRITE, 1, getAddrFileAbsPath("derived_address"), 0));
404  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.BADNODE.REG_UPPER_MASK", 0x600104, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 0));
405  nodeProperties.back().mask = 0xFFFF0000;
406  nodeProperties.push_back(NodeProperties("SUBSYSTEM3.BADNODE.REG_LOWER_MASK", 0x600104, defs::SINGLE, defs::READWRITE, 1, getAddrFileAbsPath("derived_address"), 0));
407  nodeProperties.back().mask = 0xFFFF;
408 
409  nodeProperties.push_back(NodeProperties("IPBUS_ENDPOINT", 0x700000, defs::SINGLE, defs::READWRITE, 1, addrFileAbsPath, 0));
410  nodeProperties.back().fwInfo["type"] = "endpoint";
411  nodeProperties.back().fwInfo["width"] = "0x10";
412 
413  for (size_t i=0; i < nodeProperties.size(); i++) {
414  BOOST_REQUIRE_LE(nodeProperties.at(i).descendantIds.size(), (nodeProperties.size() - i - 1));
415  for (size_t j=0; j < nodeProperties.at(i).descendantIds.size(); j++) {
416  std::string lRelativePath = nodeProperties.at(i+j+1).path.substr(nodeProperties.at(i).path.empty() ? 0 : nodeProperties.at(i).path.size() + 1);
417  nodeProperties.at(i).descendantIds.at(j) = lRelativePath;
418  nodeProperties.at(i).descendantTypes[lRelativePath] = nodeProperties.at(i+j+1).type;
419  }
420  }
421 }
422 
423 
424 void checkProperties(const uhal::Node& aNode, const NodeProperties& aExpected)
425 {
426  BOOST_CHECK_EQUAL(aNode.getPath(), aExpected.path);
427  BOOST_CHECK_EQUAL(aNode.getId(), aExpected.id);
428  BOOST_CHECK_EQUAL(aNode.getAddress(), aExpected.address);
429  BOOST_CHECK_EQUAL(aNode.getPermission(), aExpected.permission);
430  BOOST_CHECK_EQUAL(aNode.getSize(), aExpected.size);
431  BOOST_CHECK_EQUAL(aNode.getMask(), aExpected.mask);
432  BOOST_CHECK_EQUAL(aNode.getMode(), aExpected.mode);
433 
434  BOOST_CHECK_EQUAL(aNode.getDescription(), aExpected.description);
435  BOOST_CHECK_EQUAL(aNode.getModule(), aExpected.module);
436  BOOST_CHECK_EQUAL(aNode.getTags(), aExpected.tags);
437 
438  // Validate parameters map
439  BOOST_CHECK_EQUAL(aNode.getParameters().size(), aExpected.parameters.size());
440  for (boost::unordered_map<std::string,std::string>::const_iterator lIt=aExpected.parameters.begin(); lIt!=aExpected.parameters.end(); lIt++) {
441  BOOST_CHECK_MESSAGE(aNode.getParameters().count(lIt->first) == size_t(1), "Parameter '" << lIt->first << "' was not found");
442  if (aNode.getParameters().count(lIt->first) == size_t(1)){
443  BOOST_CHECK_MESSAGE(aNode.getParameters().find(lIt->first)->second == lIt->second, "Parameter '" << lIt->first << "' has value '" << aNode.getParameters().find(lIt->first)->second << "'; expected value '" << lIt->second << "'");
444  }
445  }
446  for (boost::unordered_map<std::string,std::string>::const_iterator lIt=aNode.getParameters().begin(); lIt!=aNode.getParameters().end(); lIt++) {
447  BOOST_CHECK_MESSAGE(aExpected.parameters.count(lIt->first) == size_t(1), "Node has unexpected parameter '" << lIt->first << "'" << " (value: '" << lIt->second << "')");
448  }
449 
450  // Validate firmware info map
451  BOOST_CHECK_EQUAL(aNode.getFirmwareInfo().size(), aExpected.fwInfo.size());
452  for (boost::unordered_map<std::string,std::string>::const_iterator lIt=aExpected.fwInfo.begin(); lIt!=aExpected.fwInfo.end(); lIt++) {
453  BOOST_CHECK_MESSAGE(aNode.getFirmwareInfo().count(lIt->first) == size_t(1), "FW info '" << lIt->first << "' was not found");
454  if (aNode.getFirmwareInfo().count(lIt->first) == size_t(1)){
455  BOOST_CHECK_MESSAGE(aNode.getFirmwareInfo().find(lIt->first)->second == lIt->second, "FW info '" << lIt->first << "' has value '" << aNode.getFirmwareInfo().find(lIt->first)->second << "'; expected value '" << lIt->second << "'");
456  }
457  }
458  for (boost::unordered_map<std::string,std::string>::const_iterator lIt=aNode.getFirmwareInfo().begin(); lIt!=aNode.getFirmwareInfo().end(); lIt++) {
459  BOOST_CHECK_MESSAGE(aExpected.fwInfo.count(lIt->first) == size_t(1), "Node has unexpected FW info '" << lIt->first << "'" << " (value: '" << lIt->second << "')");
460  }
461 }
462 
463 
464 void checkExceptionsThrownByReadWrite(const uhal::Node& aNode, const NodeProperties& aProperties)
465 {
466  // Single-word read/write methods - check exceptions thrown when they should be
467  if (aProperties.permission == defs::READ)
468  BOOST_CHECK_THROW(aNode.write(1), uhal::exception::WriteAccessDenied);
469  if (aProperties.permission == defs::WRITE) {
470  BOOST_CHECK_THROW(aNode.read(), uhal::exception::ReadAccessDenied);
471  if (aProperties.mask != 0xFFFFFFFF)
472  BOOST_CHECK_THROW(aNode.write(1), uhal::exception::WriteAccessDenied);
473  }
474 
475  // Block read/write methods - check exceptions thrown when they should be
476  if (aProperties.mode == defs::SINGLE) {
477  for (size_t n=0; n <= 0xF; n++) {
478  if (n == 1)
479  continue;
480  BOOST_CHECK_THROW(aNode.readBlock(n), exception::BulkTransferOnSingleRegister);
481  BOOST_CHECK_THROW(aNode.writeBlock(std::vector<uint32_t>(n)), exception::BulkTransferOnSingleRegister);
482  }
483  if (aProperties.permission == defs::READ)
484  BOOST_CHECK_THROW(aNode.writeBlock(std::vector<uint32_t>(1)), exception::WriteAccessDenied);
485  if (aProperties.permission == defs::WRITE)
486  BOOST_CHECK_THROW(aNode.readBlock(1), exception::ReadAccessDenied);
487  }
488  else if (aProperties.mode != defs::HIERARCHICAL) {
489  for (size_t n=0; n <= aNode.getSize(); n++) {
490  if (aProperties.permission == defs::WRITE)
491  BOOST_CHECK_THROW(aNode.readBlock(n), exception::ReadAccessDenied);
492  if (aProperties.permission == defs::READ)
493  BOOST_CHECK_THROW(aNode.writeBlock(std::vector<uint32_t>(n)), exception::WriteAccessDenied);
494  }
495 
496  for (size_t n=aNode.getSize()+1; n <= aNode.getSize() + 0x10; n++) {
497  BOOST_CHECK_THROW(aNode.readBlock(n), exception::BulkTransferRequestedTooLarge);
498  BOOST_CHECK_THROW(aNode.writeBlock(std::vector<uint32_t>(n)), exception::BulkTransferRequestedTooLarge);
499  }
500  }
501 
502  // Block read/write offset methods - check exceptions thrown when they should be
503  switch (aProperties.mode) {
504  case defs::SINGLE :
505  for (size_t i=0; i <= 0xF; i++) {
506  // std::cout << " i = 0x" << std::hex << i << std::endl;
507  for (size_t j=0; j <= 0xF; j++) {
508  BOOST_CHECK_THROW(aNode.readBlockOffset(i, j), exception::BulkTransferOffsetRequestedForSingleRegister);
509  BOOST_CHECK_THROW(aNode.writeBlockOffset(std::vector<uint32_t>(i), j), exception::BulkTransferOffsetRequestedForSingleRegister);
510  }
511  }
512  break;
513 
514  case defs::NON_INCREMENTAL :
515  for (size_t i=0; i <= 0xF; i++) {
516  for (size_t j=0; j <= 0xF; j++) {
517  BOOST_CHECK_THROW(aNode.readBlockOffset(i, j), exception::BulkTransferOffsetRequestedForFifo);
518  BOOST_CHECK_THROW(aNode.writeBlockOffset(std::vector<uint32_t>(i), j), exception::BulkTransferOffsetRequestedForFifo);
519  }
520  }
521  break;
522 
523  case defs::INCREMENTAL :
524  for (size_t lOffset=0; lOffset <= 0xF; lOffset++) {
525  for (size_t n = aNode.getSize() + 1 - lOffset; n <= aNode.getSize() + 0xF - lOffset; n++) {
526  BOOST_CHECK_THROW(aNode.readBlockOffset(n, lOffset), exception::BulkTransferRequestedTooLarge);
527  BOOST_CHECK_THROW(aNode.writeBlockOffset(std::vector<uint32_t>(n), lOffset), exception::BulkTransferRequestedTooLarge);
528  }
529  }
530  break;
531 
532  case defs::HIERARCHICAL :
533  break;
534  }
535 }
536 
537 
538 void checkDescendants (const uhal::Node& aNode, const NodeProperties& aProperties)
539 {
540  // 1) Given an empty ID string, 'getNode' should return same object
541  BOOST_CHECK_EQUAL(&aNode.getNode(""), &aNode);
542 
543  // 2) 'getNode' should throw given an invalid ID
544  BOOST_CHECK_THROW(aNode.getNode("."), exception::NoBranchFoundWithGivenUID);
545  BOOST_CHECK_THROW(aNode.getNode("some_invalid_id"), exception::NoBranchFoundWithGivenUID);
546 
547  // 3) 'getNodes' should return relative IDs of all descendants (order is not defined)
548  std::vector<std::string> lReturnedIds(aNode.getNodes());
549  BOOST_CHECK_EQUAL(lReturnedIds.size(), aProperties.descendantIds.size());
550  std::vector<std::string> lExpectedIds(aProperties.descendantIds);
551  std::sort(lReturnedIds.begin(), lReturnedIds.end());
552  std::sort(lExpectedIds.begin(), lExpectedIds.end());
553 
554  BOOST_CHECK_EQUAL_COLLECTIONS(lReturnedIds.begin(), lReturnedIds.end(), lExpectedIds.begin(), lExpectedIds.end());
555 
556  for (std::vector<std::string>::const_iterator lIt=lReturnedIds.begin(); lIt != lReturnedIds.end(); lIt++) {
557  const std::type_info& lType = *aProperties.descendantTypes.at(*lIt);
558 
559  // 4) Each descendant should be accessible through 'getNode' method
560  BOOST_CHECK_NO_THROW(aNode.getNode(*lIt));
561  BOOST_CHECK(typeid(aNode.getNode(*lIt)) == lType);
562  BOOST_CHECK_EQUAL(&aNode.getNode(*lIt), &aNode.getNode(*lIt).getNode(""));
563 
564  BOOST_CHECK_THROW(aNode.getNode("." + *lIt), exception::NoBranchFoundWithGivenUID);
565  BOOST_CHECK_THROW(aNode.getNode(*lIt + "."), exception::NoBranchFoundWithGivenUID);
566 
567  // 5) Templated 'getNode' method should return pointer to same object instance as non-templated method, but throw for invalid casts
568  BOOST_CHECK_EQUAL(&aNode.getNode<Node>(*lIt), &aNode.getNode(*lIt));
569  if (lType == typeid(Node)) {
570  BOOST_CHECK_THROW(aNode.getNode<DummyParentNode>(*lIt), exception::BadNodeCast);
571  BOOST_CHECK_THROW(aNode.getNode<DummyChildNode>(*lIt), exception::BadNodeCast);
572  }
573  else if (lType == typeid(DummyParentNode)) {
574  BOOST_CHECK_EQUAL(static_cast<const Node*>(&aNode.getNode<DummyParentNode>(*lIt)), &aNode.getNode(*lIt));
575  BOOST_CHECK_THROW(aNode.getNode<DummyChildNode>(*lIt), exception::BadNodeCast);
576  }
577  else if (lType == typeid(DummyChildNode)) {
578  BOOST_CHECK_EQUAL(static_cast<const Node*>(&aNode.getNode<DummyParentNode>(*lIt)), &aNode.getNode(*lIt));
579  BOOST_CHECK_EQUAL(static_cast<const Node*>(&aNode.getNode<DummyChildNode>(*lIt)), &aNode.getNode(*lIt));
580  }
581  else {
582  BOOST_CHECK_MESSAGE(false, "Unit tests have not been written to handle node class '" << aProperties.type->name() << "'");
583  }
584 
585  // 6) For each descendant, the same node object should be returned by calling 'getNode' once using relative ID path, or twice using 2 parts of relative ID path
586  size_t lPositionOfDot(lIt->find("."));
587  while (lPositionOfDot != std::string::npos) {
588  std::string lPathPart1(lIt->substr(0, lPositionOfDot));
589  std::string lPathPart2(lIt->substr(lPositionOfDot+1));
590 
591  BOOST_CHECK_EQUAL(&aNode.getNode(*lIt), &aNode.getNode(lPathPart1).getNode(lPathPart2));
592 
593  lPositionOfDot = lIt->find(".", lPositionOfDot + 1);
594  }
595  }
596 
597  // TODO: Add test that vector returned by getNodes("someRegex") is correct
598 }
599 
600 
601 bool nodeAddrCompare (const Node* aNodeL, const Node* aNodeR)
602 {
603  return ( aNodeL->getAddress() < aNodeR->getAddress() );
604 }
605 
606 
607 void checkIteration(const uhal::Node& aNode, const NodeProperties& aProperties)
608 {
609  // Check that sequence of nodes returned by iterator is correct
610  std::vector<const uhal::Node*> lExpectedNodes;
611  lExpectedNodes.push_back(&aNode);
612  for (std::vector<std::string>::const_iterator lIt = aProperties.descendantIds.begin(); lIt != aProperties.descendantIds.end(); lIt++)
613  lExpectedNodes.push_back(&aNode.getNode(*lIt));
614  std::stable_sort(lExpectedNodes.begin(), lExpectedNodes.end(), nodeAddrCompare);
615 
616  size_t lItCount = 0;
617  for (uhal::Node::const_iterator lIt = aNode.begin(); lIt != aNode.end(); lIt++, lItCount++) {
618  if (lItCount < lExpectedNodes.size())
619  BOOST_CHECK_EQUAL(&*lIt, lExpectedNodes.at(lItCount));
620  else
621  BOOST_CHECK(false);
622  }
623  BOOST_CHECK_EQUAL(lItCount, lExpectedNodes.size());
624 }
625 
626 
627 void checkLineage(const uhal::Node& aTopNode, const uhal::Node& aNode)
628 {
629  // 1) Check lineage returned with top-most node as argument
630  std::vector<const Node*> lExpected(1, &aTopNode);
631  const std::string lPath(aNode.getPath());
632 
633  size_t lDotIndex = aNode.getPath().find('.');
634  while (lDotIndex != std::string::npos) {
635  lExpected.push_back(&aTopNode.getNode(lPath.substr(0, lDotIndex)));
636  lDotIndex = aNode.getPath().find('.', lDotIndex + 1);
637  }
638 
639  const std::vector<const Node*> lReturned = aNode.getLineage(aTopNode);
640  BOOST_CHECK_EQUAL_COLLECTIONS(lReturned.begin(), lReturned.end(), lExpected.begin(), lExpected.end());
641 
642  // 2) Check lineage returned with intermediate-level nodes as argument (e.g. top node's child, grandchild, etc)
643  for (size_t i = 1; i < lExpected.size(); i++) {
644  const std::vector<const Node*> lExpected2(lExpected.begin()+i, lExpected.end());
645  const std::vector<const Node*> lReturned2(aNode.getLineage(*lExpected.at(i)));
646 
647  BOOST_CHECK_EQUAL_COLLECTIONS(lReturned2.begin(), lReturned2.end(), lExpected2.begin(), lExpected2.end());
648  }
649 }
650 
651 
652 void checkNodeTree(const uhal::Node& aNode, const std::vector<NodeProperties>& aExpectedProperties)
653 {
654  for (std::vector<NodeProperties>::const_iterator lIt = aExpectedProperties.begin(); lIt != aExpectedProperties.end(); lIt++) {
655  BOOST_TEST_MESSAGE("Node '" << lIt->path << "'");
656  const uhal::Node& lNode = (lIt->path.empty() ? aNode : aNode.getNode(lIt->path));
657 
658  checkProperties(lNode, *lIt);
660  checkDescendants(lNode, *lIt);
661  checkIteration(lNode, *lIt);
662 
663  if (&lNode != &aNode)
664  checkLineage(aNode, lNode);
665  else
666  BOOST_CHECK_THROW(lNode.getLineage(aNode), std::runtime_error);
667  }
668 }
669 
670 
671 pugi::xml_node getNthChild(const pugi::xml_node& aNode, const size_t aIndex)
672 {
673  pugi::xml_node lNode = aNode.first_child();
674  for (size_t i = 0; i < aIndex; i++)
675  lNode = lNode.next_sibling();
676  return lNode;
677 }
678 
679 void setAttribute(pugi::xml_node aNode, const std::string& aName, const std::string& aValue)
680 {
681  aNode.remove_attribute(aName.c_str());
682  aNode.append_attribute(aName.c_str()).set_value(aValue.c_str());
683 }
684 
685 
686 BOOST_AUTO_TEST_SUITE( nodes )
687 
688 
690  const boost::shared_ptr<uhal::Node> lTopNode(NodeTreeBuilder::getInstance().getNodeTree(addrFileURI, boost::filesystem::current_path() / "."));
691 
692  checkNodeTree(*lTopNode, nodeProperties);
693 }
694 
695 
697  const boost::shared_ptr<uhal::Node> lTopNode(NodeTreeBuilder::getInstance().getNodeTree(addrFileURI, boost::filesystem::current_path() / "."));
698 
699  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0, 0), "no matching nodes");
700  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 1, 0), "node \"REG\"");
701  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 2, 0), "node \"REG_READ_ONLY\"");
702  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 3, 0), "node \"REG_WRITE_ONLY\"");
703  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 4, 0), "nodes \"REG_UPPER_MASK\", \"REG_LOWER_MASK\"");
704  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 4, 1), "2 nodes match");
705  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 4, 2), "nodes \"REG_UPPER_MASK\", \"REG_LOWER_MASK\"");
706  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 4, 3), "nodes \"REG_UPPER_MASK\", \"REG_LOWER_MASK\"");
707  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 5, 0), "nodes \"REG_MASKED_READ_ONLY\", \"REG_MASKED_WRITE_ONLY\"");
708  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 5, 1), "2 nodes match");
709  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 5, 2), "nodes \"REG_MASKED_READ_ONLY\", \"REG_MASKED_WRITE_ONLY\"");
710  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 5, 3), "nodes \"REG_MASKED_READ_ONLY\", \"REG_MASKED_WRITE_ONLY\"");
711  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 6, 0), "nodes \"REG_PARS\", \"REG_OUT_OF_ORDER\"");
712  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 6, 1), "2 nodes match");
713  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 6, 2), "nodes \"REG_PARS\", \"REG_OUT_OF_ORDER\"");
714  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 6, 3), "nodes \"REG_PARS\", \"REG_OUT_OF_ORDER\"");
715  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 7, 0), "no matching nodes");
716 
717  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x0fffff, 0), "no matching nodes");
718  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x100000, 0), "node \"MEM\"");
719  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x100001, 0), "node \"MEM\"");
720  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x100010, 0), "node \"MEM\"");
721  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x130000, 0), "node \"MEM\"");
722  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x13ffff, 0), "node \"MEM\"");
723  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x140000, 0), "no matching nodes");
724 
725  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x200000, 0), "no matching nodes");
726  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x210002, 0), "node \"SUBSYSTEM1.REG\"");
727  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x210003, 0), "node \"SUBSYSTEM1.MEM\"");
728  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x210004, 0), "node \"SUBSYSTEM1.MEM\"");
729  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x250002, 0), "node \"SUBSYSTEM1.MEM\"");
730  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x250003, 0), "no matching nodes");
731 
732  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x270001, 0), "no matching nodes");
733  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x270002, 0), "node \"SUBSYSTEM1.SUBMODULE.REG\"");
734  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x270003, 0), "node \"SUBSYSTEM1.SUBMODULE.MEM\"");
735  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x270004, 0), "node \"SUBSYSTEM1.SUBMODULE.MEM\"");
736  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x270102, 0), "node \"SUBSYSTEM1.SUBMODULE.MEM\"");
737  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x270103, 0), "no matching nodes");
738 
739  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x600000, 0), "no matching nodes");
740  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x600001, 0), "node \"SUBSYSTEM3.DERIVEDNODE.REG\"");
741  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x600002, 0), "no matching nodes");
742  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x600003, 0), "node \"SUBSYSTEM3.DERIVEDNODE.REG_WRITE_ONLY\"");
743  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x600004, 0), "nodes \"REG_UPPER_MASK\", \"REG_LOWER_MASK\" under \"SUBSYSTEM3.DERIVEDNODE\"");
744  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x600004, 1), "2 nodes under \"SUBSYSTEM3.DERIVEDNODE\" match");
745  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x600004, 2), "nodes \"REG_UPPER_MASK\", \"REG_LOWER_MASK\" under \"SUBSYSTEM3.DERIVEDNODE\"");
746  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x600004, 3), "nodes \"REG_UPPER_MASK\", \"REG_LOWER_MASK\" under \"SUBSYSTEM3.DERIVEDNODE\"");
747  BOOST_CHECK_EQUAL(detail::getAddressDescription(*lTopNode, 0x600005, 0), "no matching nodes");
748 }
749 
750 
751 BOOST_AUTO_TEST_SUITE( simple )
752 
754 {
755  boost::shared_ptr<Node> lNode(NodeTreeBuilder::getInstance().build(addrTableDoc.child ( "node" ), boost::filesystem::path()));
756  checkNodeTree(*lNode, nodeProperties);
757 }
758 
760 {
761  for (size_t i = 0; i < nodeProperties.size(); i++) {
762  BOOST_TEST_MESSAGE("Removing 'id' attribute from node " << i);
763 
764  pugi::xml_document lDoc;
765  lDoc.load(addrTableStr.c_str());
766  getNthChild(lDoc.child("node"), i).remove_attribute("id");
767 
768  BOOST_CHECK_THROW(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()), exception::NoRulesPassed);
769  }
770 }
771 
773 {
774  std::vector<std::string> lBadValues;
775  lBadValues.push_back("");
776  lBadValues.push_back(" ");
777  lBadValues.push_back(" ");
778  lBadValues.push_back(".");
779  lBadValues.push_back("bob.");
780  lBadValues.push_back(".bob");
781  lBadValues.push_back("some.value");
782 
783  for (std::vector<std::string>::const_iterator lIt = lBadValues.begin(); lIt != lBadValues.end(); lIt++)
784  {
785  for (size_t i = 0; i < nodeProperties.size(); i++) {
786  BOOST_TEST_MESSAGE("Setting 'id' attribute of node " << i << " to '" << *lIt << "'");
787 
788  pugi::xml_document lDoc;
789  lDoc.load(addrTableStr.c_str());
790  setAttribute(getNthChild(lDoc.child("node"), i), "id", *lIt);
791 
792  BOOST_CHECK_THROW(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()), exception::NodeAttributeIncorrectValue);
793  }
794  }
795 }
796 
798 {
799  std::vector<std::string> lBadValues;
800  lBadValues.push_back("");
801  lBadValues.push_back(" ");
802  lBadValues.push_back(" ");
803  lBadValues.push_back("-1");
804  lBadValues.push_back("-0x11");
805  lBadValues.push_back("0x");
806  lBadValues.push_back("x");
807  lBadValues.push_back("3.14");
808  lBadValues.push_back("bob");
809  lBadValues.push_back("0x1234bob5678");
810 
811  // lBadValues.push_back("0x100000000");
812  // lBadValues.push_back("0x1FFF1234abcd");
813 
814  for (std::vector<std::string>::const_iterator lIt = lBadValues.begin(); lIt != lBadValues.end(); lIt++)
815  {
816  for (size_t i = 0; i < nodeProperties.size(); i++) {
817  BOOST_TEST_MESSAGE("Setting 'address' attribute of node " << i << " to '" << *lIt << "'");
818 
819  pugi::xml_document lDoc;
820  lDoc.load(addrTableStr.c_str());
821  setAttribute(getNthChild(lDoc.child("node"), i), "address", *lIt);
822 
823  BOOST_CHECK_THROW(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()), exception::NodeAttributeIncorrectValue);
824  }
825  }
826 }
827 
829 {
830  std::vector<std::string> lBadValues;
831  lBadValues.push_back("");
832  lBadValues.push_back(" ");
833  lBadValues.push_back(" ");
834  lBadValues.push_back("-1");
835  lBadValues.push_back("42a");
836  lBadValues.push_back("-0x11");
837  lBadValues.push_back("0x");
838  lBadValues.push_back("x");
839  lBadValues.push_back("3.14");
840  lBadValues.push_back("bob");
841  lBadValues.push_back("0x1234bob5678");
842 
843  // lBadValues.push_back("0x100000000");
844  // lBadValues.push_back("0x1FFF1234abcd");
845 
846  for (std::vector<std::string>::const_iterator lIt = lBadValues.begin(); lIt != lBadValues.end(); lIt++)
847  {
848  for (size_t i = 0; i < 2; i++) {
849  BOOST_TEST_MESSAGE("Setting 'mask' attribute of node " << i << " to '" << *lIt << "'");
850 
851  pugi::xml_document lDoc;
852  lDoc.load(addrTableStr.c_str());
853  setAttribute(getNthChild(lDoc.child("node"), i), "mask", *lIt);
854 
855  BOOST_CHECK_THROW(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()), exception::NodeAttributeIncorrectValue);
856  }
857  }
858 }
859 
861 {
862  std::vector<std::string> lBadValues;
863  lBadValues.push_back("");
864  lBadValues.push_back(" ");
865  lBadValues.push_back(" ");
866  lBadValues.push_back("-1");
867  lBadValues.push_back("42a");
868  lBadValues.push_back("-0x11");
869  lBadValues.push_back("0x");
870  lBadValues.push_back("x");
871  lBadValues.push_back("3.14");
872  lBadValues.push_back("bob");
873  lBadValues.push_back("0x1234bob5678");
874 
875  // lBadValues.push_back("0x100000000");
876  // lBadValues.push_back("0x1FFF1234abcd");
877 
878  for (std::vector<std::string>::const_iterator lIt = lBadValues.begin(); lIt != lBadValues.end(); lIt++)
879  {
880  for (size_t i = 2; i < nodeProperties.size(); i++) {
881  BOOST_TEST_MESSAGE("Setting 'size' attribute of node " << i << " to '" << *lIt << "'");
882 
883  pugi::xml_document lDoc;
884  lDoc.load(addrTableStr.c_str());
885  setAttribute(getNthChild(lDoc.child("node"), i), "size", *lIt);
886 
887  BOOST_CHECK_THROW(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()), exception::NodeAttributeIncorrectValue);
888  }
889  }
890 }
891 
893 {
894  std::vector<std::string> lBadValues;
895  lBadValues.push_back("bob");
896  lBadValues.push_back("some_invalid_string");
897  lBadValues.push_back("");
898  lBadValues.push_back("R");
899  lBadValues.push_back("W");
900  lBadValues.push_back("RW");
901  lBadValues.push_back("WR");
902  lBadValues.push_back("READ");
903  lBadValues.push_back("WRITE");
904  lBadValues.push_back("READWRITE");
905  lBadValues.push_back("WRITEREAD");
906 
907  lBadValues.push_back("r ");
908 
909  for (std::vector<std::string>::const_iterator lIt = lBadValues.begin(); lIt != lBadValues.end(); lIt++)
910  {
911  for (size_t i = 0; i < nodeProperties.size(); i++) {
912  BOOST_TEST_MESSAGE("Setting 'permission' attribute of node " << i << " to '" << *lIt << "'");
913 
914  pugi::xml_document lDoc;
915  lDoc.load(addrTableStr.c_str());
916  setAttribute(getNthChild(lDoc.child("node"), i), "permission", *lIt);
917 
918  BOOST_CHECK_THROW(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()), exception::NodeAttributeIncorrectValue);
919  }
920  }
921 }
922 
924 {
925  std::vector<std::string> lBadValues;
926  lBadValues.push_back("bob");
927  lBadValues.push_back("some_invalid_string");
928  lBadValues.push_back("");
929  lBadValues.push_back("SINGLE");
930  lBadValues.push_back("BLOCK");
931  lBadValues.push_back("INCREMENTAL");
932  lBadValues.push_back("INC");
933  lBadValues.push_back("PORT");
934  lBadValues.push_back("NON-INCREMENTAL");
935  lBadValues.push_back("NON-INC");
936 
937  lBadValues.push_back("single ");
938 
939  for (std::vector<std::string>::const_iterator lIt = lBadValues.begin(); lIt != lBadValues.end(); lIt++)
940  {
941  for (size_t i = 0; i < nodeProperties.size(); i++) {
942  BOOST_TEST_MESSAGE("Setting 'mode' attribute of node " << i << " to '" << *lIt << "'");
943 
944  pugi::xml_document lDoc;
945  lDoc.load(addrTableStr.c_str());
946  setAttribute(getNthChild(lDoc.child("node"), i), "mode", *lIt);
947 
948  BOOST_CHECK_THROW(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()), exception::NodeAttributeIncorrectValue);
949  }
950  }
951 }
952 
954 {
955  for (size_t i = 0; i < 2; i++) {
956  BOOST_TEST_MESSAGE("Adding 'size' attribute to node " << i << ", that doesn't have 'mode' attribute");
957 
958  pugi::xml_document lDoc;
959  lDoc.load(addrTableStr.c_str());
960  setAttribute(getNthChild(lDoc.child("node"), i), "size", "42");
961 
962  // This should change to 'BOOST_CHECK_THROW' in future release (after grace period discussed in issue #194 has ended)
963  BOOST_CHECK_NO_THROW(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
964  }
965 }
966 
967 
968 BOOST_AUTO_TEST_SUITE_END()
969 
970 
971 BOOST_AUTO_TEST_SUITE( overlapChecks )
972 
973 
975 {
976  boost::shared_ptr<Node> lNode(NodeTreeBuilder::getInstance().build(addrTableDoc.child ( "node" ), boost::filesystem::path()));
977 
978  checkNodeTree(*lNode, nodeProperties);
979 
981 }
982 
983 
985 {
986  // Move reg1 to same address as reg2 (0x1)
987  pugi::xml_document lDoc;
988  lDoc.load(addrTableStr.c_str());
989  setAttribute(getNthChild(lDoc.child("node"), 0), "address", "0x1");
990  boost::shared_ptr<const Node> lNode(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
991 
992  // Expected overlaps
993  std::vector<std::pair<const Node*, const Node*> > lExpected;
994  lExpected.push_back( std::make_pair(&lNode->getNode("reg1"), &lNode->getNode("reg2")) );
995 
996  // Compare expectations with result
997  std::vector<std::pair<const Node*, const Node*> > lResult = detail::getAddressOverlaps(*lNode);
998  BOOST_CHECK_EQUAL_COLLECTIONS(lResult.begin(), lResult.end(), lExpected.begin(), lExpected.end());
999 }
1000 
1001 
1003 {
1004  // Move reg4 to same address as reg3 (0x2)
1005  pugi::xml_document lDoc;
1006  lDoc.load(addrTableStr.c_str());
1007  setAttribute(getNthChild(lDoc.child("node"), 3), "address", "0x2");
1008  boost::shared_ptr<const Node> lNode(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
1009 
1010  // Expected overlaps
1011  std::vector<std::pair<const Node*, const Node*> > lExpected;
1012  lExpected.push_back( std::make_pair(&lNode->getNode("reg3"), &lNode->getNode("reg4")) );
1013  lExpected.push_back( std::make_pair(&lNode->getNode("reg3"), &lNode->getNode("reg4.A")) );
1014  lExpected.push_back( std::make_pair(&lNode->getNode("reg3"), &lNode->getNode("reg4.B")) );
1015  lExpected.push_back( std::make_pair(&lNode->getNode("reg3"), &lNode->getNode("reg4.C")) );
1016  lExpected.push_back( std::make_pair(&lNode->getNode("reg3"), &lNode->getNode("reg4.D")) );
1017  lExpected.push_back( std::make_pair(&lNode->getNode("reg3.A"), &lNode->getNode("reg4")) );
1018  lExpected.push_back( std::make_pair(&lNode->getNode("reg3.A"), &lNode->getNode("reg4.A")) );
1019  lExpected.push_back( std::make_pair(&lNode->getNode("reg3.A"), &lNode->getNode("reg4.B")) );
1020  lExpected.push_back( std::make_pair(&lNode->getNode("reg3.B"), &lNode->getNode("reg4")) );
1021  lExpected.push_back( std::make_pair(&lNode->getNode("reg3.B"), &lNode->getNode("reg4.C")) );
1022  lExpected.push_back( std::make_pair(&lNode->getNode("reg3.B"), &lNode->getNode("reg4.D")) );
1023 
1024  // Compare expectations with result
1025  std::vector<std::pair<const Node*, const Node*> > lResult = detail::getAddressOverlaps(*lNode);
1026  BOOST_CHECK_EQUAL_COLLECTIONS(lResult.begin(), lResult.end(), lExpected.begin(), lExpected.end());
1027 }
1028 
1029 
1031 {
1032  // Change mask of reg4.A to 0x10100ff to overlap with reg4.C and reg4.D
1033  pugi::xml_document lDoc;
1034  lDoc.load(addrTableStr.c_str());
1035  setAttribute(getNthChild(getNthChild(lDoc.child("node"), 3), 0), "mask", "0x10100ff");
1036  boost::shared_ptr<const Node> lNode(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
1037 
1038  // Expected overlaps
1039  std::vector<std::pair<const Node*, const Node*> > lExpected;
1040  lExpected.push_back( std::make_pair(&lNode->getNode("reg4.A"), &lNode->getNode("reg4.C")) );
1041  lExpected.push_back( std::make_pair(&lNode->getNode("reg4.A"), &lNode->getNode("reg4.D")) );
1042 
1043  // Compare expectations with result
1044  std::vector<std::pair<const Node*, const Node*> > lResult = detail::getAddressOverlaps(*lNode);
1045  BOOST_CHECK_EQUAL_COLLECTIONS(lResult.begin(), lResult.end(), lExpected.begin(), lExpected.end());
1046 }
1047 
1048 
1050 {
1051  // Move port1 to same address as port2 (0x5)
1052  pugi::xml_document lDoc;
1053  lDoc.load(addrTableStr.c_str());
1054  setAttribute(getNthChild(lDoc.child("node"), 4), "address", "0x5");
1055  boost::shared_ptr<const Node> lNode(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
1056 
1057  // Expected overlaps
1058  std::vector<std::pair<const Node*, const Node*> > lExpected;
1059  lExpected.push_back( std::make_pair(&lNode->getNode("port1"), &lNode->getNode("port2")) );
1060 
1061  // Compare expectations with result
1062  std::vector<std::pair<const Node*, const Node*> > lResult = detail::getAddressOverlaps(*lNode);
1063  BOOST_CHECK_EQUAL_COLLECTIONS(lResult.begin(), lResult.end(), lExpected.begin(), lExpected.end());
1064 }
1065 
1066 
1067 BOOST_FIXTURE_TEST_CASE (overlap_unmasked_reg_vs_masked_reg, AddressTableOverlapFixture)
1068 {
1069  // Move reg1 to same address as reg3 (0x2)
1070  pugi::xml_document lDoc;
1071  lDoc.load(addrTableStr.c_str());
1072  setAttribute(getNthChild(lDoc.child("node"), 0), "address", "0x2");
1073  boost::shared_ptr<const Node> lNode(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
1074 
1075  // Expected overlaps
1076  std::vector<std::pair<const Node*, const Node*> > lExpected;
1077  lExpected.push_back( std::make_pair(&lNode->getNode("reg1"), &lNode->getNode("reg3")) );
1078  lExpected.push_back( std::make_pair(&lNode->getNode("reg1"), &lNode->getNode("reg3.A")) );
1079  lExpected.push_back( std::make_pair(&lNode->getNode("reg1"), &lNode->getNode("reg3.B")) );
1080 
1081  // Compare expectations with result
1082  std::vector<std::pair<const Node*, const Node*> > lResult = detail::getAddressOverlaps(*lNode);
1083  BOOST_CHECK_EQUAL_COLLECTIONS(lResult.begin(), lResult.end(), lExpected.begin(), lExpected.end());
1084 }
1085 
1086 
1088 {
1089  // Move reg1 to same address as port1 (0x4)
1090  pugi::xml_document lDoc;
1091  lDoc.load(addrTableStr.c_str());
1092  setAttribute(getNthChild(lDoc.child("node"), 0), "address", "0x4");
1093  boost::shared_ptr<const Node> lNode(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
1094 
1095  // Expected overlaps
1096  std::vector<std::pair<const Node*, const Node*> > lExpected;
1097  lExpected.push_back( std::make_pair(&lNode->getNode("reg1"), &lNode->getNode("port1")) );
1098 
1099  // Compare expectations with result
1100  std::vector<std::pair<const Node*, const Node*> > lResult = detail::getAddressOverlaps(*lNode);
1101  BOOST_CHECK_EQUAL_COLLECTIONS(lResult.begin(), lResult.end(), lExpected.begin(), lExpected.end());
1102 }
1103 
1104 
1106 {
1107  // Move reg3 to same address as port1 (0x4)
1108  pugi::xml_document lDoc;
1109  lDoc.load(addrTableStr.c_str());
1110  setAttribute(getNthChild(lDoc.child("node"), 2), "address", "0x4");
1111  boost::shared_ptr<const Node> lNode(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
1112 
1113  // Expected overlaps
1114  std::vector<std::pair<const Node*, const Node*> > lExpected;
1115  lExpected.push_back( std::make_pair(&lNode->getNode("reg3"), &lNode->getNode("port1")) );
1116  lExpected.push_back( std::make_pair(&lNode->getNode("reg3.A"), &lNode->getNode("port1")) );
1117  lExpected.push_back( std::make_pair(&lNode->getNode("reg3.B"), &lNode->getNode("port1")) );
1118 
1119  // Compare expectations with result
1120  std::vector<std::pair<const Node*, const Node*> > lResult = detail::getAddressOverlaps(*lNode);
1121  BOOST_CHECK_EQUAL_COLLECTIONS(lResult.begin(), lResult.end(), lExpected.begin(), lExpected.end());
1122 }
1123 
1124 
1126 {
1127  // Create list of nodes that will be moved
1128  // pair.first = index of XML nodes
1129  // pair.second = node paths that will be flagged by overlap check
1130  std::vector<std::pair<size_t, std::vector<std::string> > > lModifiedNodes(4);
1131 
1132  lModifiedNodes.at(0).first = 0;
1133  lModifiedNodes.at(0).second.push_back("reg1");
1134 
1135  lModifiedNodes.at(1).first = 2;
1136  lModifiedNodes.at(1).second.push_back("reg3");
1137  lModifiedNodes.at(1).second.push_back("reg3.A");
1138  lModifiedNodes.at(1).second.push_back("reg3.B");
1139 
1140  lModifiedNodes.at(2).first = 4;
1141  lModifiedNodes.at(2).second.push_back("port1");
1142 
1143  lModifiedNodes.at(3).first = 6;
1144  lModifiedNodes.at(3).second.push_back("ram1");
1145 
1146  // Target addresses that above nodes will be moved to. First, middle and last address of 'ram2'
1147  std::vector<std::string> lAddresses;
1148  lAddresses.push_back("0x10");
1149  lAddresses.push_back("0x1a");
1150  lAddresses.push_back("0x1f");
1151 
1152  for (std::vector<std::pair<size_t, std::vector<std::string> > >::const_iterator lNodeIt = lModifiedNodes.begin(); lNodeIt != lModifiedNodes.end(); lNodeIt++)
1153  {
1154  for (std::vector<std::string>::const_iterator lAddrIt = lAddresses.begin(); lAddrIt != lAddresses.end(); lAddrIt++)
1155  {
1156  BOOST_TEST_MESSAGE("Moving '" << lNodeIt->second.front() << "' to address " << *lAddrIt);
1157 
1158  // Move node to get an overlap
1159  pugi::xml_document lDoc;
1160  lDoc.load(addrTableStr.c_str());
1161  setAttribute(getNthChild(lDoc.child("node"), lNodeIt->first), "address", lAddrIt->c_str());
1162  boost::shared_ptr<const Node> lNode(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
1163 
1164  // Expected overlaps
1165  std::vector<std::pair<const Node*, const Node*> > lExpected;
1166  for (size_t i = 0; i < lNodeIt->second.size(); i++)
1167  {
1168  if (lAddrIt == lAddresses.begin())
1169  lExpected.push_back( std::make_pair(&lNode->getNode(lNodeIt->second.at(i)), &lNode->getNode("ram2")) );
1170  else
1171  lExpected.push_back( std::make_pair(&lNode->getNode("ram2"), &lNode->getNode(lNodeIt->second.at(i))) );
1172  }
1173 
1174  // Compare expectations with result
1175  std::vector<std::pair<const Node*, const Node*> > lResult = detail::getAddressOverlaps(*lNode);
1176  BOOST_CHECK_EQUAL_COLLECTIONS(lResult.begin(), lResult.end(), lExpected.begin(), lExpected.end());
1177  }
1178  }
1179 }
1180 
1181 
1183 {
1184  // Move module 1 to address 0x0
1185  pugi::xml_document lDoc;
1186  lDoc.load(addrTableStr.c_str());
1187  setAttribute(getNthChild(lDoc.child("node"), 8), "address", "0x0");
1188  boost::shared_ptr<const Node> lNode(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
1189 
1190  // Expected overlaps
1191  std::vector<std::pair<const Node*, const Node*> > lExpected;
1192  lExpected.push_back( std::make_pair(&lNode->getNode("reg1"), &lNode->getNode("module1.reg1")) );
1193  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2"), &lNode->getNode("reg2")) );
1194  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2.mask1"), &lNode->getNode("reg2")) );
1195  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2.mask2"), &lNode->getNode("reg2")) );
1196  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2.mask3"), &lNode->getNode("reg2")) );
1197  lExpected.push_back( std::make_pair(&lNode->getNode("module1.port"), &lNode->getNode("reg3")) );
1198  lExpected.push_back( std::make_pair(&lNode->getNode("module1.port"), &lNode->getNode("reg3.A")) );
1199  lExpected.push_back( std::make_pair(&lNode->getNode("module1.port"), &lNode->getNode("reg3.B")) );
1200  lExpected.push_back( std::make_pair(&lNode->getNode("module1.ram"), &lNode->getNode("ram2")) );
1201 
1202  // Compare expectations with result
1203  std::vector<std::pair<const Node*, const Node*> > lResult = detail::getAddressOverlaps(*lNode);
1204  BOOST_CHECK_EQUAL_COLLECTIONS(lResult.begin(), lResult.end(), lExpected.begin(), lExpected.end());
1205 }
1206 
1207 
1209 {
1210  // Move module 2 to same address as module 1 (0x40)
1211  pugi::xml_document lDoc;
1212  lDoc.load(addrTableStr.c_str());
1213  setAttribute(getNthChild(lDoc.child("node"), 9), "address", "0x40");
1214  boost::shared_ptr<const Node> lNode(NodeTreeBuilder::getInstance().build(lDoc.child ( "node" ), boost::filesystem::path()));
1215 
1216  // Expected overlaps
1217  std::vector<std::pair<const Node*, const Node*> > lExpected;
1218  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg1"), &lNode->getNode("module2.regA")) );
1219  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2"), &lNode->getNode("module2.regB")) );
1220  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2"), &lNode->getNode("module2.regB.A")) );
1221  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2"), &lNode->getNode("module2.regB.B")) );
1222  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2"), &lNode->getNode("module2.regB.C")) );
1223  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2.mask1"), &lNode->getNode("module2.regB")) );
1224  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2.mask1"), &lNode->getNode("module2.regB.A")) );
1225  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2.mask2"), &lNode->getNode("module2.regB")) );
1226  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2.mask2"), &lNode->getNode("module2.regB.B")) );
1227  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2.mask3"), &lNode->getNode("module2.regB")) );
1228  lExpected.push_back( std::make_pair(&lNode->getNode("module1.reg2.mask3"), &lNode->getNode("module2.regB.C")) );
1229  lExpected.push_back( std::make_pair(&lNode->getNode("module1.port"), &lNode->getNode("module2.fifo")) );
1230  lExpected.push_back( std::make_pair(&lNode->getNode("module1.ram"), &lNode->getNode("module2.block")) );
1231 
1232  // Compare expectations with result
1233  std::vector<std::pair<const Node*, const Node*> > lResult = detail::getAddressOverlaps(*lNode);
1234  BOOST_CHECK_EQUAL_COLLECTIONS(lResult.begin(), lResult.end(), lExpected.begin(), lExpected.end());
1235 }
1236 
1237 
1238 BOOST_AUTO_TEST_SUITE_END()
1239 
1240 
1241 BOOST_AUTO_TEST_SUITE_END()
1242 
1243 }
1244 }
uhal::tests::SimpleAddressTableFixture::~SimpleAddressTableFixture
~SimpleAddressTableFixture()
Definition: test_nodes.cpp:94
uhal::operator<<
std::ostream & operator<<(std::ostream &aStr, const uhal::HttpResponseType &aHttpResponse)
Definition: HttpResponseGrammar.cpp:41
uhal::tests::SimpleAddressTableFixture::addrTableDoc
pugi::xml_document addrTableDoc
Definition: test_nodes.cpp:97
uhal::Node::readBlock
ValVector< uint32_t > readBlock(const uint32_t &aSize) const
Read a block of unsigned data from a block of registers or a block-read port.
Definition: Node.cpp:606
boost::shared_ptr< uhal::Node >
uhal::tests::getNthChild
pugi::xml_node getNthChild(const pugi::xml_node &aNode, const size_t aIndex)
Definition: test_nodes.cpp:671
uhal::Node::writeBlock
ValHeader writeBlock(const std::vector< uint32_t > &aValues) const
Write a block of data to a block of registers or a block-write port.
Definition: Node.cpp:516
fixtures.hpp
uhal::Node::getParameters
const boost::unordered_map< std::string, std::string > & getParameters() const
Return parameters of the current node.
Definition: Node.cpp:308
uhal::tests::NodeProperties
Definition: test_nodes.cpp:69
uhal::tests::setAttribute
void setAttribute(pugi::xml_node aNode, const std::string &aName, const std::string &aValue)
Definition: test_nodes.cpp:679
uhal::tests::NodeProperties::permission
defs::NodePermission permission
Definition: test_nodes.cpp:77
uhal::defs::NodePermission
NodePermission
define Read and Write permissions of a uhal Node
Definition: definitions.hpp:50
uhal::tests::checkDescendants
void checkDescendants(const uhal::Node &aNode, const NodeProperties &aProperties)
Definition: test_nodes.cpp:538
uhal::Node::getDescription
const std::string & getDescription() const
Return the optional description string which the user can specify for the current node.
Definition: Node.cpp:296
uhal::tests::NodeProperties::type
const std::type_info * type
Definition: test_nodes.cpp:87
uhal::tests::BOOST_CHECK
BOOST_CHECK(!mem.valid())
xml.hpp
uhal::tests::BOOST_CHECK_THROW
BOOST_CHECK_THROW(hw.getNode("REG").writeBlockOffset(xx, 0), uhal::exception::BulkTransferOffsetRequestedForSingleRegister)
uhal::tests::j
std::vector< uint32_t >::const_iterator j
Definition: test_rawclient.cpp:113
uhal::Node::end
const_iterator end() const
Definition: Node.cpp:180
uhal::tests::NodeProperties::NodeProperties
NodeProperties(const std::string &aIdPath, const uint32_t aAddress, const defs::BlockReadWriteMode aMode, const defs::NodePermission aPermission, const size_t aSize, const std::string &aModule, const size_t aNrDescendants)
Definition: test_nodes.cpp:137
uhal::tests::AddressTableOverlapFixture::AddressTableOverlapFixture
AddressTableOverlapFixture()
Definition: test_nodes.cpp:171
sort
PUGI__FN void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7457
boost
Definition: log.hpp:13
uhal::Node::begin
const_iterator begin() const
Definition: Node.cpp:174
uhal::Node::getNode
const Node & getNode(const std::string &aId) const
Retrieve the Node given by a full-stop delimeted name path relative, to the current node.
Definition: Node.cpp:415
uhal::tests::nodeAddrCompare
bool nodeAddrCompare(const Node *aNodeL, const Node *aNodeR)
Definition: test_nodes.cpp:601
uhal::Node::getAddress
const uint32_t & getAddress() const
Return the register address with which this node is associated.
Definition: Node.cpp:260
uhal::tests::NodeProperties::address
uint32_t address
Definition: test_nodes.cpp:75
uhal::tests::NodeProperties::description
std::string description
Definition: test_nodes.cpp:80
uhal::Node::getPermission
const defs::NodePermission & getPermission() const
Return the read/write access permissions of this node.
Definition: Node.cpp:284
uhal::tests::NodeProperties::module
std::string module
Definition: test_nodes.cpp:81
uhal::Node::getSize
const uint32_t & getSize() const
Return the maximum size available to a block read/write.
Definition: Node.cpp:278
pugi::xml_document::load
xml_parse_result load(std::basic_istream< char, std::char_traits< char > > &stream, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:7083
uhal::defs::HIERARCHICAL
@ HIERARCHICAL
Definition: definitions.hpp:53
pugi::xml_node::first_child
xml_node first_child() const
Definition: pugixml.cpp:5629
uhal::tests::SimpleAddressTableFixture::addrTableStr
const std::string addrTableStr
Definition: test_nodes.cpp:96
pugi::xml_node::child
xml_node child(const char_t *name) const
Definition: pugixml.cpp:5497
uhal
Definition: HttpResponseGrammar.hpp:49
uhal::Node::getLineage
std::vector< const Node * > getLineage(const Node &aAncestor) const
Returns ancestry path of nodes from (but not including) aAncestor to this node.
Definition: Node.cpp:681
uhal::tests::NodeProperties::mode
defs::BlockReadWriteMode mode
Definition: test_nodes.cpp:76
uhal::tests::NodeProperties::~NodeProperties
~NodeProperties()
Definition: test_nodes.cpp:71
DummyDerivedNode.hpp
pugi::xml_node::remove_attribute
bool remove_attribute(const xml_attribute &a)
Definition: pugixml.cpp:6048
uhal::tests::DummyAddressFileFixture::~DummyAddressFileFixture
~DummyAddressFileFixture()
Definition: test_nodes.cpp:119
uhal::tests::AbstractFixture
Definition: fixtures.hpp:48
uhal::Node
A heirarchical node for navigating heirarchical firmwares.
Definition: Node.hpp:86
uhal::tests::DummyAddressFileFixture::addrFileLevel3AbsPath
std::string addrFileLevel3AbsPath
Definition: test_nodes.cpp:131
uhal::tests::AddressTableOverlapFixture::~AddressTableOverlapFixture
~AddressTableOverlapFixture()
Definition: test_nodes.cpp:106
uhal::tests::AddressTableOverlapFixture
Definition: test_nodes.cpp:103
uhal::detail::getAddressOverlaps
std::vector< std::pair< const Node *, const Node * > > getAddressOverlaps(const Node &aNode)
Definition: utilities.cpp:121
uhal::defs::BlockReadWriteMode
BlockReadWriteMode
define whether transactions target a single register, a block of registers, a block-read/write port o...
Definition: definitions.hpp:53
uhal::tests::SimpleAddressTableFixture
Definition: test_nodes.cpp:91
uhal::tests::DummyAddressFileFixture::DummyAddressFileFixture
DummyAddressFileFixture()
Definition: test_nodes.cpp:274
pugi::xml_attribute::set_value
bool set_value(const char_t *rhs)
Definition: pugixml.cpp:5306
pugi::xml_node
Definition: pugixml.hpp:455
uhal::tests::DummyAddressFileFixture::getAddrFileAbsPath
std::string getAddrFileAbsPath(const std::string &aSuffix)
Definition: test_nodes.cpp:121
uhal::tests::checkIteration
void checkIteration(const uhal::Node &aNode, const NodeProperties &aProperties)
Definition: test_nodes.cpp:607
uhal::Node::getNodes
std::vector< std::string > getNodes() const
Return all node IDs known to this HwInterface.
Definition: Node.cpp:452
uhal::tests::DummyParentNode
Definition: DummyDerivedNode.hpp:12
pugi::xml_node::append_attribute
xml_attribute append_attribute(const char_t *name)
Definition: pugixml.cpp:5659
uhal::tests::DummyAddressFileFixture::nodeProperties
std::vector< NodeProperties > nodeProperties
Definition: test_nodes.cpp:132
uhal::tests::DummyAddressFileFixture
Fixture for tests based on 'dummy' address files.
Definition: test_nodes.cpp:116
uhal::tests::NodeProperties::path
std::string path
Definition: test_nodes.cpp:73
uhal::Node::writeBlockOffset
ValHeader writeBlockOffset(const std::vector< uint32_t > &aValues, const uint32_t &aOffset) const
Write a block of data to a block of registers or a block-write port.
Definition: Node.cpp:547
uhal.hpp
uhal::Node::read
ValWord< uint32_t > read() const
Read a single, unmasked, unsigned word.
Definition: Node.cpp:585
uhal::tests::AddressTableOverlapFixture::addrTableStr
const std::string addrTableStr
Definition: test_nodes.cpp:108
uhal::Node::getMode
const defs::BlockReadWriteMode & getMode() const
Return whether the node represents a single register, a block of registers or a block-read/write port...
Definition: Node.cpp:272
uhal::tests::DummyAddressFileFixture::addrFileAbsPath
const std::string addrFileAbsPath
Definition: test_nodes.cpp:129
uhal::defs::NON_INCREMENTAL
@ NON_INCREMENTAL
Definition: definitions.hpp:53
pugi::xml_node::next_sibling
xml_node next_sibling() const
Definition: pugixml.cpp:5528
uhal::tests::NodeProperties::fwInfo
boost::unordered_map< std::string, std::string > fwInfo
Definition: test_nodes.cpp:86
uhal::tests::NodeProperties::size
size_t size
Definition: test_nodes.cpp:78
uhal::Node::getId
const std::string & getId() const
Return the unique ID of the current node.
Definition: Node.cpp:195
uhal::defs::INCREMENTAL
@ INCREMENTAL
Definition: definitions.hpp:53
uhal::tests::NodeProperties::id
std::string id
Definition: test_nodes.cpp:74
uhal::tests::DummyAddressFileFixture::addrFileLevel2AbsPath
std::string addrFileLevel2AbsPath
Definition: test_nodes.cpp:130
uhal::Node::getPath
std::string getPath() const
Return the full path to the current node.
Definition: Node.cpp:201
uhal::tests::DummyAddressFileFixture::addrFileURI
const std::string addrFileURI
Definition: test_nodes.cpp:128
uhal::Node::getModule
const std::string & getModule() const
Return the name of the module in which the current node resides.
Definition: Node.cpp:302
uhal::defs::READWRITE
@ READWRITE
Definition: definitions.hpp:50
uhal::tests::SimpleAddressTableFixture::nodeProperties
std::vector< NodeProperties > nodeProperties
Definition: test_nodes.cpp:99
uhal::Node::getMask
const uint32_t & getMask() const
Return the mask to be applied if this node is a sub-field, rather than an entire register.
Definition: Node.cpp:266
uhal::tests::AddressTableOverlapFixture::nodeProperties
std::vector< NodeProperties > nodeProperties
Definition: test_nodes.cpp:111
uhal::tests::BOOST_CHECK_NO_THROW
BOOST_CHECK_NO_THROW(hw.getNode("REG").writeBlock(xx))
uhal::tests::checkProperties
void checkProperties(const uhal::Node &aNode, const NodeProperties &aExpected)
Definition: test_nodes.cpp:424
uhal::tests::DummyChildNode
Class further derived from Level1.
Definition: DummyDerivedNode.hpp:27
uhal::Node::getFirmwareInfo
const boost::unordered_map< std::string, std::string > & getFirmwareInfo() const
Return parameters for inferring the VHDL address decoding.
Definition: Node.cpp:314
uhal::tests::BOOST_FIXTURE_TEST_CASE
BOOST_FIXTURE_TEST_CASE(dummy_address_files, DummyAddressFileFixture)
Definition: test_nodes.cpp:689
uhal::tests::BOOST_CHECK_EQUAL
BOOST_CHECK_EQUAL(mem.size(), N)
uhal::tests::AddressTableOverlapFixture::addrTableDoc
pugi::xml_document addrTableDoc
Definition: test_nodes.cpp:109
pugi::xml_document
Definition: pugixml.hpp:1001
uhal::Node::write
ValHeader write(const uint32_t &aValue) const
Write a single, unmasked word to a register.
Definition: Node.cpp:490
NodeTreeBuilder.hpp
uhal::Node::readBlockOffset
ValVector< uint32_t > readBlockOffset(const uint32_t &aSize, const uint32_t &aOffset) const
Read a block of unsigned data from a block of registers or a block-read port.
Definition: Node.cpp:637
uhal::tests::NodeProperties::tags
std::string tags
Definition: test_nodes.cpp:84
uhal::Node::const_iterator
Definition: Node.hpp:94
uhal::tests::checkLineage
void checkLineage(const uhal::Node &aTopNode, const uhal::Node &aNode)
Definition: test_nodes.cpp:627
uhal::tests::NodeProperties::mask
uint32_t mask
Definition: test_nodes.cpp:79
uhal::tests::checkExceptionsThrownByReadWrite
void checkExceptionsThrownByReadWrite(const uhal::Node &aNode, const NodeProperties &aProperties)
Definition: test_nodes.cpp:464
uhal::NodeTreeBuilder::getInstance
static NodeTreeBuilder & getInstance()
Static method to retrieve the single instance of the class.
Definition: NodeTreeBuilder.cpp:144
uhal::detail::getAddressDescription
std::string getAddressDescription(const ClientInterface &, const uint32_t, const size_t &)
Generates a short string summarising which nodes match the specified address.
Definition: utilities.cpp:106
uhal::Node::getTags
const std::string & getTags() const
Return the optional tags string which the user can specify for the current node.
Definition: Node.cpp:290
uhal::defs::NOMASK
const uint32_t NOMASK
define what it means to have no mask
Definition: definitions.hpp:56
uhal::tests::NodeProperties::descendantTypes
std::map< std::string, const std::type_info * > descendantTypes
Definition: test_nodes.cpp:83
uhal::defs::WRITE
@ WRITE
Definition: definitions.hpp:50
uhal::defs::READ
@ READ
Definition: definitions.hpp:50
uhal::tests::NodeProperties::parameters
boost::unordered_map< std::string, std::string > parameters
Definition: test_nodes.cpp:85
uhal::tests::checkNodeTree
void checkNodeTree(const uhal::Node &aNode, const std::vector< NodeProperties > &aExpectedProperties)
Definition: test_nodes.cpp:652
utilities.hpp
uhal::tests::NodeProperties::descendantIds
std::vector< std::string > descendantIds
Definition: test_nodes.cpp:82
uhal::tests::SimpleAddressTableFixture::SimpleAddressTableFixture
SimpleAddressTableFixture()
Definition: test_nodes.cpp:152
uhal::defs::SINGLE
@ SINGLE
Definition: definitions.hpp:53