Component.cc Source File

Back to the index.

Component.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2010 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * Note: See DummyComponent.cc for unit tests of the component framework.
29  */
30 
31 #include "assert.h"
32 #include <fstream>
33 
35 #include "Component.h"
36 #include "ComponentFactory.h"
37 #include "EscapedString.h"
38 #include "GXemul.h"
39 #include "StringHelper.h"
40 
41 
42 Component::Component(const string& className, const string& visibleClassName)
43  : m_parentComponent(NULL)
44  , m_className(className)
45  , m_visibleClassName(visibleClassName)
46  , m_step(0)
47 {
48  AddVariable("name", &m_name);
49  AddVariable("template", &m_template);
50  AddVariable("step", &m_step);
51 }
52 
53 
55 {
56  return m_className;
57 }
58 
59 
61 {
62  return m_visibleClassName;
63 }
64 
65 
66 string Component::GetAttribute(const string& attributeName)
67 {
68  // The Component base class always returns an empty string
69  // for all attribute names. It is up to individual Component
70  // implementations to return overrides.
71 
72  return "";
73 }
74 
75 
77 {
79 
80  if (GetClassName() == "root")
81  clone = new RootComponent;
82  else
84 
85  if (clone.IsNULL()) {
86  std::cerr << "INTERNAL ERROR in Component::Clone(): "
87  "could not clone a '" << GetClassName() << "'\n";
88  throw std::exception();
89  }
90 
91  // Copy the value of each state variable to the clone:
92  StateVariableMap::const_iterator varIt = m_stateVariables.begin();
93  for ( ; varIt != m_stateVariables.end(); ++varIt) {
94  const string& varName = varIt->first;
95  const StateVariable& variable = varIt->second;
96 
97  StateVariableMap::iterator cloneVarIt =
98  clone->m_stateVariables.find(varName);
99 
100  if (cloneVarIt == clone->m_stateVariables.end()) {
101  std::cerr << "INTERNAL ERROR in Component::Clone(): "
102  "could not copy variable " << varName << "'s "
103  << " value to the clone: clone is missing"
104  " this variable?\n";
105  assert(false);
106  } else if (!(cloneVarIt->second).CopyValueFrom(variable)) {
107  std::cerr << "INTERNAL ERROR in Component::Clone(): "
108  "could not copy variable " << varName << "'s "
109  << " value to the clone.\n";
110  assert(false);
111  }
112  }
113 
114  for (Components::const_iterator it = m_childComponents.begin();
115  it != m_childComponents.end(); ++it) {
116  refcount_ptr<Component> child = (*it)->Clone();
117  if (child.IsNULL()) {
118  std::cerr << "INTERNAL ERROR in Component::Clone(): "
119  "could not clone child of class '" <<
120  (*it)->GetClassName() << "'\n";
121  assert(false);
122  } else {
123  clone->AddChild(child);
124  }
125  }
126 
127  return clone;
128 }
129 
130 
131 refcount_ptr<Component> Component::LightCloneInternal() const
132 {
134 
135  if (GetClassName() == "root")
136  clone = new RootComponent;
137  else
139 
140  if (clone.IsNULL()) {
141  std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): "
142  "could not clone a '" << GetClassName() << "'\n";
143  throw std::exception();
144  }
145 
146  // Copy the value of each state variable to the clone:
147  StateVariableMap::const_iterator varIt = m_stateVariables.begin();
148  for ( ; varIt != m_stateVariables.end(); ++varIt) {
149  const string& varName = varIt->first;
150  const StateVariable& variable = varIt->second;
151 
152  StateVariableMap::iterator cloneVarIt =
153  clone->m_stateVariables.find(varName);
154 
155  if (cloneVarIt == clone->m_stateVariables.end()) {
156  std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): "
157  "could not copy variable " << varName << "'s "
158  << " value to the clone: clone is missing"
159  " this variable?\n";
160  throw std::exception();
161  }
162 
163  // Skip custom variables:
164  if (variable.GetType() == StateVariable::Custom)
165  continue;
166 
167  if (!(cloneVarIt->second).CopyValueFrom(variable)) {
168  std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): "
169  "could not copy variable " << varName << "'s "
170  << " value to the clone.\n";
171  throw std::exception();
172  }
173  }
174 
175  for (Components::const_iterator it = m_childComponents.begin();
176  it != m_childComponents.end(); ++it) {
177  refcount_ptr<Component> child = (*it)->LightCloneInternal();
178  if (child.IsNULL()) {
179  std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): "
180  "could not clone child of class '" <<
181  (*it)->GetClassName() << "'\n";
182  throw std::exception();
183  } else {
184  clone->AddChild(child);
185  }
186  }
187 
188  return clone;
189 }
190 
191 
193 {
194  return LightCloneInternal();
195 }
196 
197 
199  ostream& changeMessages) const
200 {
201  // Recursively look for changes in state. Compare the
202  // oldClone component with this component first.
203 
204  if (oldClone->GetClassName() != GetClassName()) {
205  changeMessages << oldClone->GenerateShortestPossiblePath() <<
206  " changed class from " << oldClone->GetClassName() <<
207  " to " << GetClassName() << "?\n";
208  return;
209  }
210 
211  // Compare all state variables:
212  StateVariableMap::const_iterator varIt = m_stateVariables.begin();
213  for ( ; varIt != m_stateVariables.end(); ++varIt) {
214  const string& varName = varIt->first;
215 
216  // Don't output "step" changes, because they happen all
217  // the time for all executable components.
218  if (varName == "step")
219  continue;
220 
221  const StateVariable& variable = varIt->second;
222  const StateVariable* oldVariable = oldClone->GetVariable(varName);
223 
224  // NOTE: Custom types have a nonsense tostring, which
225  // usually just says "(custom)" or something, so they
226  // are quickly compared.
227 
228  // TODO: In the future, maybe RAM components and such (i.e.
229  // custom data types) can be lazily reference counted or
230  // similar, to detect changes in RAM as well.
231 
232  string var = variable.ToString();
233  string varOld = oldVariable->ToString();
234 
235  if (var != varOld)
236  changeMessages << "=> " << GenerateShortestPossiblePath() << "."
237  << varName << ": " << varOld << " -> " << var << "\n";
238  }
239 
240  // Compare all children.
241  const Components& oldChildren = oldClone->GetChildren();
242  for (size_t i = 0; i < m_childComponents.size(); ++ i) {
243  string myName = m_childComponents[i]->GetVariable("name")->ToString();
244 
245  // Find the corresponding child component in the oldClone:
246  size_t j;
247  bool found = false;
248  for (j=0; j<oldChildren.size(); ++j)
249  if (oldChildren[j]->GetVariable("name")->ToString() == myName) {
250  m_childComponents[i]->DetectChanges(oldChildren[j], changeMessages);
251  found = true;
252  break;
253  }
254 
255  if (!found)
256  changeMessages << m_childComponents[i]->
257  GenerateShortestPossiblePath() << " (appeared)\n";
258  }
259 
260  // ... and see if any disappeared (i.e. were in the old clone,
261  // but not in the current tree):
262  for (size_t j=0; j<oldChildren.size(); ++j) {
263  string oldName = oldChildren[j]->GetVariable("name")->ToString();
264 
265  bool found = false;
266  for (size_t k=0; k<m_childComponents.size(); ++k) {
267  string newName = m_childComponents[k]->GetVariable("name")->ToString();
268  if (newName == oldName) {
269  found = true;
270  break;
271  }
272  }
273 
274  if (!found)
275  changeMessages << oldChildren[j]->
276  GenerateShortestPossiblePath() << " (disappeared)\n";
277  }
278 }
279 
280 
282 {
283  ResetState();
284 
285  // Recurse:
286  for (size_t i = 0; i < m_childComponents.size(); ++ i)
287  m_childComponents[i]->Reset();
288 }
289 
290 
292 {
293  // Base implementation.
294  m_step = 0;
295 }
296 
297 
299 {
300  bool everythingOk = PreRunCheckForComponent(gxemul);
301 
302  // Recurse:
303  for (size_t i = 0; i < m_childComponents.size(); ++ i)
304  everythingOk &= m_childComponents[i]->PreRunCheck(gxemul);
305 
306  return everythingOk;
307 }
308 
309 
311 {
312  // Base implementation: Do nothing. Everything is Ok.
313  return true;
314 }
315 
316 
318 {
320 
321  // Recurse:
322  for (size_t i = 0; i < m_childComponents.size(); ++ i)
323  m_childComponents[i]->FlushCachedState();
324 }
325 
326 
328 {
329  // Base implementation: Do nothing.
330 }
331 
332 
333 int Component::Execute(GXemul* gxemul, int nrOfCycles)
334 {
335  // Base implementation: Do nothing, but pretend we executed
336  // the instructions. Actual components that inherit from this
337  // class should of course _do_ something here.
338 
339  return nrOfCycles;
340 }
341 
342 
344 {
345  // The base component does not run at any frequency. Only components
346  // that actually run something "per cycle" should return values
347  // greater than 0.0.
348 
349  return 0.0;
350 }
351 
352 
354 {
355  // Default implementation (the base Component class) is not a RootComponent.
356  return NULL;
357 }
358 
359 
361 {
362  // Default implementation (the base Component class) is not a CPU.
363  return NULL;
364 }
365 
366 
368 {
369  // Default implementation (the base Component class) is not an
370  // address data bus.
371  return NULL;
372 }
373 
374 
375 void Component::SetParent(Component* parentComponent)
376 {
377  m_parentComponent = parentComponent;
378 }
379 
380 
382 {
383  return m_parentComponent;
384 }
385 
386 
388 {
389  return m_parentComponent;
390 }
391 
392 
393 void Component::GetMethodNames(vector<string>& names) const
394 {
395  // The default component has no implemented methods.
396 }
397 
398 
399 bool Component::MethodMayBeReexecutedWithoutArgs(const string& methodName) const
400 {
401  // By default, methods are _not_ re-executable without args.
402  return false;
403 }
404 
405 
407  const string& methodName,
408  const vector<string>& arguments)
409 {
410  std::cerr << "Internal error: someone tried to execute "
411  "method '" << methodName << "' on the Component base"
412  " class. Perhaps you are missing an override?\n";
413  throw std::exception();
414 }
415 
416 
418 {
419  stringstream ss;
420 
421  // If this component has a "model", then show that.
422  const StateVariable* model = GetVariable("model");
423  if (model != NULL && !model->ToString().empty()) {
424  if (!ss.str().empty())
425  ss << ", ";
426  ss << model->ToString();
427  }
428 
429  // If this component has a frequency (i.e. it is runnable), then
430  // show the frequency:
431  double freq = GetCurrentFrequency();
432  if (freq != 0.0) {
433  if (!ss.str().empty())
434  ss << ", ";
435 
436  if (freq >= 1e9)
437  ss << freq/1e9 << " GHz";
438  else if (freq >= 1e6)
439  ss << freq/1e6 << " MHz";
440  else if (freq >= 1e3)
441  ss << freq/1e3 << " kHz";
442  else
443  ss << freq << " Hz";
444  }
445 
446  const StateVariable* paused = GetVariable("paused");
447  // TODO: ToBool :)
448  if (paused != NULL && paused->ToInteger() > 0) {
449  if (!ss.str().empty())
450  ss << ", ";
451 
452  ss << "paused";
453  }
454 
455  return ss.str();
456 }
457 
458 
459 string Component::GenerateTreeDump(const string& branchTemplate,
460  bool htmlLinksForClassNames, string prefixForComponentUrls) const
461 {
462  // This generates an ASCII string which looks like:
463  //
464  // root
465  // |-- child1
466  // | |-- child1's child1
467  // | \-- child1's child2
468  // \-- child2
469  // \-- child2's child
470 
471  string branch;
472  for (size_t pos=0; pos<branchTemplate.length(); pos++) {
473  stringchar ch = branchTemplate[pos];
474  if (ch == '\\') {
475  if (pos < branchTemplate.length() - 4)
476  branch += ' ';
477  else
478  branch += ch;
479  } else {
480  if (pos == branchTemplate.length() - 3 ||
481  pos == branchTemplate.length() - 2)
482  ch = '-';
483  branch += ch;
484  }
485  }
486 
487  // Fallback to showing the component's class name in parentheses...
488  const string className = GetClassName();
489  string name = "(unnamed " + className + ")";
490 
491  // ... but prefer the state variable "name" if it is non-empty:
492  const StateVariable* value = GetVariable("name");
493  if (!value->ToString().empty())
494  name = value->ToString();
495 
496  string str = branch;
497 
498  if (htmlLinksForClassNames) {
499  // See if this class name has its own HTML page.
500  std::ifstream documentationComponentFile((
501  "doc/components/component_"
502  + className + ".html").c_str());
503 
504  if (documentationComponentFile.is_open())
505  str += "<a href=\"" + prefixForComponentUrls +
506  "components/component_" +
507  className + ".html\">" + name + "</a>";
508  else
509  str += name;
510  } else {
511  str += name;
512  }
513 
514  // If this component was created by a template, then show the template
515  // type in [ ].
516  const StateVariable* templateName;
517  if ((templateName = GetVariable("template")) != NULL &&
518  !templateName->ToString().empty())
519  {
520  string tName = templateName->ToString();
521 
522  str += " [";
523 
524  if (htmlLinksForClassNames) {
525  // See if this class/template name has its own HTML page.
526  // (Usually machines. TODO: also other components.)
527  std::ifstream documentationMachineFile((
528  "doc/machines/machine_"
529  + tName + ".html").c_str());
530 
531  if (documentationMachineFile.is_open())
532  str += "<a href=\"" + prefixForComponentUrls +
533  "machines/machine_" +
534  tName + ".html\">" + tName + "</a>";
535  else
536  str += tName;
537  } else {
538  str += tName;
539  }
540 
541  str += "]";
542  }
543 
544  // Get any additional details (CPU model, memory mapped address, etc.):
545  string details = GenerateDetails();
546  if (!details.empty())
547  str += " (" + details + ")";
548 
549  // Show the branch of the tree...
550  string result = " " + str + "\n";
551 
552  // ... and recurse to show children, if there are any:
553  const Components& children = GetChildren();
554  for (size_t i=0, n=children.size(); i<n; ++i) {
555  string subBranch = branchTemplate;
556  if (i == n-1)
557  subBranch += "\\ ";
558  else
559  subBranch += "| ";
560 
561  result += children[i]->GenerateTreeDump(subBranch,
562  htmlLinksForClassNames, prefixForComponentUrls);
563  }
564 
565  return result;
566 }
567 
568 
570 {
571  Component* root = this;
572  while (root->GetParent() != NULL)
573  root = root->GetParent();
574 
575  RootComponent* rootComponent = root->AsRootComponent();
576  if (rootComponent == NULL)
577  return NULL;
578 
579  return rootComponent->GetOwner();
580 }
581 
582 
584 {
585  GXemul* gxemul = GetRunningGXemulInstance();
586  if (gxemul == NULL)
587  return NULL;
588 
589  // TODO: Return NULL if the UI has debug messages turned off.
590 
591  return gxemul->GetUI();
592 }
593 
594 
596  size_t insertPosition)
597 {
598  if (insertPosition == (size_t) -1) {
599  insertPosition = m_childComponents.size();
600  m_childComponents.push_back(childComponent);
601  } else {
602  m_childComponents.insert(
603  m_childComponents.begin() + insertPosition,
604  childComponent);
605  }
606 
607  // A component cannot have two parents.
608  assert(childComponent->GetParent() == NULL);
609 
610  childComponent->SetParent(this);
611 
612  // Make sure that the child's "name" state variable is unique among
613  // all children of this component. (Yes, this is O(n^2) and it may
614  // need to be rewritten to cope with _lots_ of components.)
615  size_t postfix = 0;
616  bool collision = false;
617  do {
618  const StateVariable* name =
619  childComponent->GetVariable("name");
620  if (name->ToString().empty() || collision) {
621  // Set the default name:
622  // visibleclassname + postfix number
623  stringstream ss;
624  ss << childComponent->GetVisibleClassName() << postfix;
625  EscapedString escaped(ss.str());
626  childComponent->SetVariableValue("name",
627  escaped.Generate());
628 
629  name = childComponent->GetVariable("name");
630  }
631 
632  collision = false;
633  for (size_t i=0; i<m_childComponents.size(); ++i) {
634  if (i == insertPosition)
635  continue;
636 
637  // Collision?
638  const StateVariable* otherName =
639  m_childComponents[i]->GetVariable("name");
640  if (otherName != NULL) {
641  if (name->ToString() == otherName->ToString()) {
642  collision = true;
643  ++ postfix;
644  break;
645  }
646  } else {
647  // Hm. All components should have a "name".
648  assert(false);
649  }
650  }
651  } while (collision);
652 }
653 
654 
655 size_t Component::RemoveChild(Component* childToRemove)
656 {
657  size_t index = 0;
658  for (Components::iterator it = m_childComponents.begin();
659  it != m_childComponents.end(); ++it, ++index) {
660  if (childToRemove == (*it)) {
661  childToRemove->SetParent(NULL);
662  m_childComponents.erase(it);
663  return index;
664  }
665  }
666 
667  // Child not found? Should not happen.
668  assert(false);
669 
670  return (size_t) -1;
671 }
672 
673 
675 {
676  return m_childComponents;
677 }
678 
679 
681 {
682  return m_childComponents;
683 }
684 
685 
687 {
688  string path = GetVariable("name")->ToString();
689  if (path.empty())
690  path = "(" + GetClassName() + ")";
691 
692  if (m_parentComponent != NULL)
693  path = m_parentComponent->GeneratePath() + "." + path;
694 
695  return path;
696 }
697 
698 
699 static vector<string> SplitPathStringIntoVector(const string &path)
700 {
701  // Split the path into a vector. This is slow and hackish, but works.
702  vector<string> pathStrings;
703  string word;
704 
705  for (size_t i=0, n=path.length(); i<n; i++) {
706  stringchar ch = path[i];
707  if (ch == '.') {
708  pathStrings.push_back(word);
709  word = "";
710  } else {
711  word += ch;
712  }
713  }
714 
715  pathStrings.push_back(word);
716 
717  return pathStrings;
718 }
719 
720 
722 {
723  string myPath = GeneratePath();
724  vector<string> allComponentPaths;
725 
726  const Component* root = this;
727  while (root->GetParent() != NULL)
728  root = root->GetParent();
729 
730  root->AddAllComponentPaths(allComponentPaths);
731 
732  // Include as few as possible sub-parts of myPath (starting from the
733  // end), to uniqely identify the component.
734  vector<string> myPathParts = SplitPathStringIntoVector(myPath);
735 
736  for (size_t n=1; n<=myPathParts.size(); ++n) {
737  string attempt = "";
738  for (size_t i=myPathParts.size()-n; i<myPathParts.size(); i++) {
739  if (attempt.length() > 0)
740  attempt += ".";
741  attempt += myPathParts[i];
742  }
743 
744  // std::cerr << "attempt = " << attempt << "\n";
745  // attempt = ram0
746  // attempt = mainbus0.ram0
747  // attempt = machine0.mainbus0.ram0
748  // etc.
749 
750  // See if this substring is unique in allComponentPaths.
751  int nHits = 0;
752  string dotAttempt = "." + attempt;
753  size_t dotAttemptLength = dotAttempt.length();
754  for (size_t j=0; j<allComponentPaths.size(); ++j) {
755  const string& s = allComponentPaths[j];
756  if (s.length() < attempt.length())
757  continue;
758 
759  if (s == attempt)
760  nHits ++;
761  else if (s.length() > dotAttemptLength &&
762  s.substr(s.length() - dotAttemptLength, dotAttemptLength) == dotAttempt)
763  nHits ++;
764  }
765 
766  // Unique? Then we found a good short path.
767  if (nHits == 1)
768  return attempt;
769 
770  // Otherwise continue.
771  }
772 
773  // Worst case: return full path.
774  return myPath;
775 }
776 
777 
779 {
780  // Trim whitespace
781  while (path.length() > 0 && path[path.length() - 1] == ' ')
782  path = path.substr(0, path.length() - 1);
783 
784  refcount_ptr<Component> component = LookupPath(SplitPathStringIntoVector(path), 0);
785 
786  if (component.IsNULL()) {
787  // Maybe it was a path starting from somewhere other than the
788  // root. That is, if we find "." + path in the list of all
789  // components' full names exactly 1 time, then we return that.
790  vector<string> allComponentPaths;
791  AddAllComponentPaths(allComponentPaths);
792 
793  const Component* root = this;
794  while (root->GetParent() != NULL)
795  root = root->GetParent();
796 
797  int nMatches = 0;
798  string strToFind = "." + path;
799  for (size_t i=0, n=allComponentPaths.size(); i<n; i++) {
800  if (allComponentPaths[i].length() > strToFind.length()) {
801  string subs = allComponentPaths[i].substr(
802  allComponentPaths[i].length() - strToFind.length());
803  if (strToFind == subs) {
804  nMatches ++;
805  component = root->LookupPath(allComponentPaths[i]);
806  }
807  }
808  }
809 
810  if (nMatches != 1)
811  return NULL;
812  }
813 
814  return component;
815 }
816 
817 
818 const refcount_ptr<Component> Component::LookupPath(const vector<string>& path,
819  size_t index) const
820 {
821  refcount_ptr<Component> component;
822 
823  if (index > path.size()) {
824  // Huh? Lookup of empty path? Should not usually happen.
825  assert(false);
826  return component;
827  }
828 
829  StateVariableMap::const_iterator it = m_stateVariables.find("name");
830  if (it == m_stateVariables.end()) {
831  // Failure (return NULL) if we don't have a name.
832  return component;
833  }
834 
835  string nameOfThisComponent = (it->second).ToString();
836  bool match = (path[index] == nameOfThisComponent);
837 
838  // No match? Or was it the last part of the path? Then return.
839  if (!match || index == path.size() - 1) {
840  // (Successfully, if there was a match.)
841  if (match)
842  return const_cast<Component*>(this);
843  return component;
844  }
845 
846  // If there are still parts left to check, look among all the children:
847  const string& pathPartToLookup = path[index+1];
848  for (size_t i=0, n=m_childComponents.size(); i<n; i++) {
849  const StateVariable* childName =
850  m_childComponents[i]->GetVariable("name");
851  if (childName != NULL) {
852  if (childName->ToString() == pathPartToLookup) {
853  component = m_childComponents[i]->
854  LookupPath(path, index+1);
855  break;
856  }
857  }
858  }
859 
860  return component;
861 }
862 
863 
864 void Component::AddAllComponentPaths(vector<string>& allComponentPaths) const
865 {
866  // Add the component itself first:
867  allComponentPaths.push_back(GeneratePath());
868 
869  // Then all children:
870  for (size_t i=0, n=m_childComponents.size(); i<n; i++)
871  m_childComponents[i]->AddAllComponentPaths(allComponentPaths);
872 }
873 
874 
875 static bool PartialMatch(const string& partialPath, const string& path)
876 {
877  if (partialPath.empty())
878  return true;
879 
880  const size_t partialPathLength = partialPath.length();
881  const size_t pathLength = path.length();
882  size_t pathPos = 0;
883 
884  do {
885  // Partial path too long? Then abort immediately.
886  if (partialPathLength + pathPos > pathLength)
887  break;
888 
889  // A substring match? Then we might have found it.
890  if (path.substr(pathPos, partialPathLength) == partialPath) {
891  // If the path has no tail (".subcomponent"), then
892  // we found it:
893  if (path.find('.', pathPos + partialPathLength) ==
894  string::npos)
895  return true;
896  }
897 
898  // Find next place in path to test:
899  do {
900  pathPos ++;
901  } while (pathPos < pathLength && path[pathPos] != '.');
902 
903  if (pathPos < pathLength)
904  pathPos ++;
905 
906  } while (pathPos < pathLength);
907 
908  return false;
909 }
910 
911 
913  const string& partialPath, bool shortestPossible) const
914 {
915  vector<string> allComponentPaths;
916  vector<string> matches;
917 
918  AddAllComponentPaths(allComponentPaths);
919 
920  for (size_t i=0, n=allComponentPaths.size(); i<n; i++)
921  if (PartialMatch(partialPath, allComponentPaths[i])) {
922  string match = allComponentPaths[i];
923 
924  if (shortestPossible) {
925  const Component* root = this;
926  while (root->GetParent() != NULL)
927  root = root->GetParent();
928 
929  refcount_ptr<Component> component =
930  root->LookupPath(match);
931  match = component->GenerateShortestPossiblePath();
932  }
933 
934  matches.push_back(match);
935  }
936 
937  return matches;
938 }
939 
940 
941 void Component::GetVariableNames(vector<string>& names) const
942 {
943  for (StateVariableMap::const_iterator it = m_stateVariables.begin();
944  it != m_stateVariables.end(); ++it)
945  names.push_back(it->first);
946 }
947 
948 
950 {
951  StateVariableMap::iterator it = m_stateVariables.find(name);
952  if (it == m_stateVariables.end())
953  return NULL;
954  else
955  return &(it->second);
956 }
957 
958 
959 const StateVariable* Component::GetVariable(const string& name) const
960 {
961  StateVariableMap::const_iterator it = m_stateVariables.find(name);
962  if (it == m_stateVariables.end())
963  return NULL;
964  else
965  return &(it->second);
966 }
967 
968 
969 bool Component::CheckVariableWrite(StateVariable& var, const string& oldValue)
970 {
971  GXemul* gxemul = GetRunningGXemulInstance();
972  UI* ui = GetUI();
973 
974  if (gxemul != NULL) {
975  const string& name = var.GetName();
976 
977  if (name == "step") {
978  // If we are the root component, then writing to step
979  // has special meaning:
980  if (GetParent() == NULL) {
981  bool error = false;
982  int64_t oldStep = StringHelper::ParseNumber(oldValue.c_str(), error);
983  int64_t newStep = var.ToInteger();
984 
985  // 0. Value is the same as before. Simply return.
986  if (newStep == oldStep)
987  return true;
988 
989  // 1. The new value is too low (less than 0).
990  if (newStep < 0) {
991  if (ui != NULL)
992  ui->ShowDebugMessage("root.step can"
993  " not be set to lower than zero.\n");
994  return false;
995  }
996 
997  // 2. The value is lower; run backwards if possible.
998  if (newStep < oldStep) {
999  if (!gxemul->GetSnapshottingEnabled()) {
1000  if (ui != NULL)
1001  ui->ShowDebugMessage("root.step can"
1002  " not be decreased; snapshotting"
1003  " was not enabled prior to\nstarting"
1004  " the emulation. (-B command line"
1005  " option.)\n");
1006  return false;
1007  }
1008 
1009  return gxemul->ModifyStep(oldStep, newStep);
1010  }
1011 
1012  // 3. The value is higher; run forwards.
1013  return gxemul->ModifyStep(oldStep, newStep);
1014  } else {
1015  // We are not the root component. Direct (interactive)
1016  // writes to the step variable is not allowed.
1017  if (ui != NULL)
1018  ui->ShowDebugMessage("The step variable of "
1019  "this component cannot be set manually.\n");
1020  }
1021 
1022  return false;
1023  }
1024  }
1025 
1026  return true;
1027 }
1028 
1029 
1030 bool Component::SetVariableValue(const string& name, const string& expression)
1031 {
1032  UI* ui = GetUI();
1033 
1034  StateVariableMap::iterator it = m_stateVariables.find(name);
1035  if (it == m_stateVariables.end()) {
1036  if (ui != NULL)
1037  ui->ShowDebugMessage((string) name + ": no such variable\n");
1038  return false;
1039  }
1040 
1041  StateVariable& var = it->second;
1042 
1043  stringstream oldValue;
1044  var.SerializeValue(oldValue);
1045 
1046  bool success = var.SetValue(expression);
1047  if (!success) {
1048  if (ui != NULL)
1049  ui->ShowDebugMessage((string) name + ": expression could"
1050  " not be assigned; type mismatch?\n");
1051  return false;
1052  }
1053 
1054  stringstream newValue;
1055  var.SerializeValue(newValue);
1056 
1057  if (oldValue.str() != newValue.str()) {
1058  success = CheckVariableWrite(var, oldValue.str());
1059  if (!success) {
1060  // Revert to the previous:
1061  var.SetValue(oldValue.str());
1062  return false;
1063  }
1064  }
1065 
1066  return true;
1067 }
1068 
1069 
1070 void Component::Serialize(ostream& ss, SerializationContext& context) const
1071 {
1072  SerializationContext subContext = context.Indented();
1073  string tabs = context.Tabs();
1074 
1075  ss << tabs << "component " << m_className << "\n" << tabs << "{\n";
1076 
1077  for (StateVariableMap::const_iterator it = m_stateVariables.begin();
1078  it != m_stateVariables.end(); ++it)
1079  (it->second).Serialize(ss, subContext);
1080 
1081  for (size_t i = 0, n = m_childComponents.size(); i < n; ++ i)
1082  m_childComponents[i]->Serialize(ss, subContext);
1083 
1084  ss << tabs << "}\n";
1085 }
1086 
1087 
1088 static bool GetNextToken(const string& str, size_t& pos, string& token)
1089 {
1090  token = "";
1091 
1092  size_t len = str.length();
1093 
1094  // Skip initial whitespace:
1095  while (pos < len &&
1096  (str[pos] == ' ' || str[pos] == '\t' ||
1097  str[pos] == '\r' || str[pos] == '\n'))
1098  ++ pos;
1099 
1100  if (pos >= len)
1101  return false;
1102 
1103  // Get the token, until end-of-string or until whitespace is found:
1104  bool quoted = false;
1105  do {
1106  char ch = str[pos];
1107 
1108  if (!quoted) {
1109  if (ch == '"')
1110  quoted = true;
1111  if (ch == ' ' || ch == '\t' ||
1112  ch == '\r' || ch == '\n')
1113  break;
1114  token += ch;
1115  } else {
1116  if (ch == '"')
1117  quoted = false;
1118  token += ch;
1119  if (ch == '\\' && pos < len-1)
1120  token += str[++pos];
1121  }
1122 
1123  ++ pos;
1124  } while (pos < len);
1125 
1126  return true;
1127 }
1128 
1129 
1130 refcount_ptr<Component> Component::Deserialize(ostream& messages, const string& str, size_t& pos)
1131 {
1132  refcount_ptr<Component> deserializedTree = NULL;
1133  string token;
1134 
1135  if (!GetNextToken(str, pos, token) || token != "component") {
1136  messages << "Expecting \"component\".\n";
1137  return deserializedTree;
1138  }
1139 
1140  string className;
1141  if (!GetNextToken(str, pos, className)) {
1142  messages << "Expecting a class name.\n";
1143  return deserializedTree;
1144  }
1145 
1146  if (!GetNextToken(str, pos, token) || token != "{") {
1147  messages << "Expecting {.\n";
1148  return deserializedTree;
1149  }
1150 
1151  // root is a special case (cannot be created by the factory). All other
1152  // class types should be possible to create using the factory.
1153  if (className == "root") {
1154  deserializedTree = new RootComponent;
1155  } else {
1156  deserializedTree = ComponentFactory::CreateComponent(className);
1157  if (deserializedTree.IsNULL()) {
1158  messages << "Could not create a '" << className << "' component.\n";
1159  return deserializedTree;
1160  }
1161  }
1162 
1163  while (pos < str.length()) {
1164  size_t savedPos = pos;
1165 
1166  // Either 1) } (end of current component)
1167  // or 2) component name { ...
1168  // or 3) variableType name "value"
1169 
1170  if (!GetNextToken(str, pos, token)) {
1171  // Failure.
1172  messages << "Failure. (0)\n";
1173  deserializedTree = NULL;
1174  break;
1175  }
1176 
1177  // Case 1:
1178  if (token == "}")
1179  break;
1180 
1181  string name;
1182  if (!GetNextToken(str, pos, name)) {
1183  // Failure.
1184  messages << "Failure. (1)\n";
1185  deserializedTree = NULL;
1186  break;
1187  }
1188 
1189  if (token == "component") {
1190  // Case 2:
1191  refcount_ptr<Component> child =
1192  Component::Deserialize(messages, str, savedPos);
1193  if (child.IsNULL()) {
1194  // Failure.
1195  messages << "Failure. (2)\n";
1196  deserializedTree = NULL;
1197  break;
1198  }
1199 
1200  deserializedTree->AddChild(child);
1201  pos = savedPos;
1202  } else {
1203  // Case 3:
1204  string varType = token;
1205  string varValue;
1206  if (!GetNextToken(str, pos, varValue)) {
1207  // Failure.
1208  messages << "Failure. (3)\n";
1209  deserializedTree = NULL;
1210  break;
1211  }
1212 
1213  if (!deserializedTree->SetVariableValue(name,
1214  varValue)) {
1215  messages << "Warning: variable '" << name <<
1216  "' for component class " << className <<
1217  " could not be deserialized; skipping.\n";
1218  }
1219  }
1220  }
1221 
1222  return deserializedTree;
1223 }
1224 
1225 
1227 {
1228  // Serialize
1229  SerializationContext context;
1230  stringstream ss;
1231  Serialize(ss, context);
1232 
1233  string result = ss.str();
1234 
1235  Checksum checksumOriginal;
1236  AddChecksum(checksumOriginal);
1237 
1238  // Deserialize
1239  size_t pos = 0;
1240  stringstream messages;
1241  refcount_ptr<Component> tmpDeserializedTree = Deserialize(messages, result, pos);
1242  if (tmpDeserializedTree.IsNULL())
1243  return false;
1244 
1245  Checksum checksumDeserialized;
1246  tmpDeserializedTree->AddChecksum(checksumDeserialized);
1247 
1248  // ... and compare the checksums:
1249  return checksumOriginal == checksumDeserialized;
1250 }
1251 
1252 
1253 void Component::AddChecksum(Checksum& checksum) const
1254 {
1255  // Some random stuff is added between normal fields to the checksum.
1256  // This is to make it harder to get the same checksum for two different
1257  // objects, that just have some fields swapped, or such. (Yes, I know,
1258  // that is not a very scientific explanation :) but it will have to do.)
1259 
1260  checksum.Add(((uint64_t) 0x12491725 << 32) | 0xabcef011);
1261  checksum.Add(m_className);
1262 
1263  SerializationContext dummyContext;
1264 
1265  // Add all state variables.
1266  for (StateVariableMap::const_iterator it = m_stateVariables.begin();
1267  it != m_stateVariables.end();
1268  ++ it) {
1269  checksum.Add(((uint64_t) 0x019fb879 << 32) | 0x25addae1);
1270 
1271  stringstream ss;
1272  (it->second).Serialize(ss, dummyContext);
1273  checksum.Add(ss.str());
1274  }
1275 
1276  // Add all child components.
1277  for (size_t i = 0; i < m_childComponents.size(); ++ i) {
1278  checksum.Add((((uint64_t) 0xf98a7c7c << 32) | 0x109f0000)
1279  + i * 0x98127417);
1280  m_childComponents[i]->AddChecksum(checksum);
1281  }
1282 
1283  checksum.Add(((uint64_t) 0x90a10224 << 32) | 0x97defa7a);
1284 }
1285 
1286 
Component::PreRunCheck
bool PreRunCheck(GXemul *gxemul)
Checks the state of this component and all its children, before starting execution.
Definition: Component.cc:298
Component::GetChildren
Components & GetChildren()
Gets pointers to child components.
Definition: Component.cc:674
Component::FlushCachedStateForComponent
virtual void FlushCachedStateForComponent()
Resets the cached state of this component.
Definition: Component.cc:327
Component::AddChecksum
void AddChecksum(Checksum &checksum) const
Adds this component's state, including children, to a checksum.
Definition: Component.cc:1253
refcount_ptr::IsNULL
bool IsNULL() const
Checks whether or not an object is referenced by the reference counted pointer.
Definition: refcount_ptr.h:218
Component::GenerateTreeDump
string GenerateTreeDump(const string &branchTemplate, bool htmlLinksForClassNames=false, string prefixForComponentUrls="") const
Generates an ASCII tree dump of a component tree.
Definition: Component.cc:459
Component::GenerateDetails
virtual string GenerateDetails() const
Generate details about the component.
Definition: Component.cc:417
stringchar
char stringchar
Definition: misc.h:59
Component::AddVariable
bool AddVariable(const string &name, T *variablePointer)
Adds a state variable of type T to the Component.
Definition: Component.h:563
Component::AddChild
void AddChild(refcount_ptr< Component > childComponent, size_t insertPosition=(size_t) -1)
Adds a reference to a child component.
Definition: Component.cc:595
ComponentFactory.h
SerializationContext::Indented
SerializationContext Indented()
Constructs a SerializationContext which is indented (1 step) compared to the current context.
Definition: SerializationContext.h:74
Component::GetCurrentFrequency
virtual double GetCurrentFrequency() const
Returns the current frequency (in Hz) that the component runs at.
Definition: Component.cc:343
GXemul::GetSnapshottingEnabled
bool GetSnapshottingEnabled() const
Checks whether snapshots are currently enabled or not.
Definition: GXemul.cc:764
GXemul
The main emulator class.
Definition: GXemul.h:55
Component::Deserialize
static refcount_ptr< Component > Deserialize(ostream &messages, const string &str, size_t &pos)
Deserializes a string into a component tree.
Definition: Component.cc:1130
StateVariable
StateVariables make up the persistent state of Component objects.
Definition: StateVariable.h:69
refcount_ptr< Component >
EscapedString
A helper class for escaping strings using C-style escapes.
Definition: EscapedString.h:44
StateVariable::ToInteger
uint64_t ToInteger() const
Returns the variable as an unsignedinteger value.
Definition: StateVariable.cc:280
Component::FindPathByPartialMatch
vector< string > FindPathByPartialMatch(const string &partialPath, bool shortestPossible=false) const
Finds complete component paths, given a partial path.
Definition: Component.cc:912
EscapedString::Generate
string Generate() const
Generates an escaped string, from the original string.
Definition: EscapedString.cc:37
Component::Execute
virtual int Execute(GXemul *gxemul, int nrOfCycles)
Execute one or more cycles.
Definition: Component.cc:333
Component::RemoveChild
size_t RemoveChild(Component *childToRemove)
Removes a reference to a child component.
Definition: Component.cc:655
Component::GetUI
UI * GetUI()
Gets an UI reference for outputting debug messages during runtime.
Definition: Component.cc:583
RootComponent.h
UI
Base class for a User Interface.
Definition: UI.h:42
StateVariable::GetType
enum Type GetType() const
Gets the type of the variable.
Definition: StateVariable.cc:132
Component::GetMethodNames
virtual void GetMethodNames(vector< string > &names) const
Retrieves a component's implemented method names.
Definition: Component.cc:393
RootComponent::GetOwner
GXemul * GetOwner()
Definition: RootComponent.h:74
Component::ExecuteMethod
virtual void ExecuteMethod(GXemul *gxemul, const string &methodName, const vector< string > &arguments)
Executes a method on the component.
Definition: Component.cc:406
Component::GetVariableNames
void GetVariableNames(vector< string > &names) const
Retrieves a component's state variable names.
Definition: Component.cc:941
UI::ShowDebugMessage
virtual void ShowDebugMessage(const string &msg)=0
Shows a debug message.
Component::GetClassName
string GetClassName() const
Gets the class name of the component.
Definition: Component.cc:54
StateVariable::Custom
@ Custom
Definition: StateVariable.h:86
Component::DetectChanges
void DetectChanges(const refcount_ptr< Component > &oldClone, ostream &changeMessages) const
Compare an older clone to the current tree, to find changes.
Definition: Component.cc:198
SerializationContext
A context used during serialization of objects.
Definition: SerializationContext.h:38
GXemul::ModifyStep
bool ModifyStep(int64_t oldStep, int64_t newStep)
Change step either forwards or backwards.
Definition: GXemul.cc:801
StateVariable::SetValue
bool SetValue(const string &expression)
Set the variable's value, using a string expression.
Definition: StateVariable.cc:412
Component::Component
Component(const string &className, const string &visibleClassName)
Base constructor for a Component.
Definition: Component.cc:42
Component::LookupPath
const refcount_ptr< Component > LookupPath(string path) const
Looks up a path from this Component, and returns a pointer to the found Component,...
Definition: Component.cc:778
StateVariable::SerializeValue
void SerializeValue(ostream &ss) const
Serializes the variable value into a string.
Definition: StateVariable.cc:362
Component::AsRootComponent
virtual RootComponent * AsRootComponent()
Returns the component's RootComponent interface.
Definition: Component.cc:353
ComponentFactory::CreateComponent
static refcount_ptr< Component > CreateComponent(const string &componentNameAndOptionalArgs, GXemul *gxemul=NULL)
Creates a component given a short component name.
Definition: ComponentFactory.cc:87
Component.h
StateVariable::ToString
string ToString() const
Returns the variable as a readable string.
Definition: StateVariable.cc:229
Checksum::Add
void Add(uint64_t x)
Add a uint64_t to the checksum.
Definition: Checksum.cc:43
Component::SetVariableValue
bool SetVariableValue(const string &name, const string &expression)
Sets a variable to a new value.
Definition: Component.cc:1030
EscapedString.h
StringHelper.h
Component::GenerateShortestPossiblePath
string GenerateShortestPossiblePath() const
Generates a short string representation of the path to the Component.
Definition: Component.cc:721
Component::GetParent
Component * GetParent()
Gets this component's parent component, if any.
Definition: Component.cc:381
RootComponent
A Component which is the default root node in the configuration.
Definition: RootComponent.h:60
Component::CheckVariableWrite
virtual bool CheckVariableWrite(StateVariable &var, const string &oldValue)
Checks whether a write to a variable is OK.
Definition: Component.cc:969
GXemul::GetUI
UI * GetUI()
Gets a pointer to the GXemul instance' active UI.
Definition: GXemul.cc:653
Component::CheckConsistency
bool CheckConsistency() const
Checks consistency by serializing and deserializing the component (including all its child components...
Definition: Component.cc:1226
Component::GeneratePath
string GeneratePath() const
Generates a string representation of the path to the Component.
Definition: Component.cc:686
Component::MethodMayBeReexecutedWithoutArgs
virtual bool MethodMayBeReexecutedWithoutArgs(const string &methodName) const
Returns whether a method name may be re-executed without args.
Definition: Component.cc:399
Component::ResetState
virtual void ResetState()
Resets the state variables of this component.
Definition: Component.cc:291
StateVariable::GetName
const string & GetName() const
Gets the name of the variable.
Definition: StateVariable.cc:138
Component::SetParent
void SetParent(Component *parentComponent)
Sets the parent component of this component.
Definition: Component.cc:375
Component
A Component is a node in the configuration tree that makes up an emulation setup.
Definition: Component.h:64
Checksum
A checksum accumulator.
Definition: Checksum.h:49
Component::LightClone
const refcount_ptr< Component > LightClone() const
Makes a light clone of the component and all its children.
Definition: Component.cc:192
Components
vector< refcount_ptr< Component > > Components
Definition: Component.h:43
Component::GetVariable
StateVariable * GetVariable(const string &name)
Gets a pointer to a state variable.
Definition: Component.cc:949
Component::FlushCachedState
void FlushCachedState()
Resets the cached state of this component and all its children.
Definition: Component.cc:317
Component::AsCPUComponent
virtual CPUComponent * AsCPUComponent()
Returns the component's CPUComponent interface.
Definition: Component.cc:360
AddressDataBus
An interface for implementing components that read/write data via an address bus.
Definition: AddressDataBus.h:45
Component::GetAttribute
static string GetAttribute(const string &attributeName)
Creates a Component.
Definition: Component.cc:66
Component::Serialize
void Serialize(ostream &ss, SerializationContext &context) const
Serializes the Component into a string stream.
Definition: Component.cc:1070
SerializationContext::Tabs
string Tabs() const
Generates a string of Tab characters, based on the indentation level.
Definition: SerializationContext.h:87
Component::Clone
refcount_ptr< Component > Clone() const
Clones the component and all its children.
Definition: Component.cc:76
StringHelper::ParseNumber
static uint64_t ParseNumber(const char *str, bool &error)
Parses a string into a 64-bit number.
Definition: StringHelper.cc:34
Component::AsAddressDataBus
virtual AddressDataBus * AsAddressDataBus()
Returns the component's AddressDataBus interface, if any.
Definition: Component.cc:367
Component::PreRunCheckForComponent
virtual bool PreRunCheckForComponent(GXemul *gxemul)
Checks the state of this component, before starting execution.
Definition: Component.cc:310
Component::GetVisibleClassName
string GetVisibleClassName() const
Gets the visible class name of the component.
Definition: Component.cc:60
GXemul.h
Component::GetRunningGXemulInstance
GXemul * GetRunningGXemulInstance()
Returns a reference to the current GXemul instance.
Definition: Component.cc:569
CPUComponent
A base-class for processors Component implementations.
Definition: CPUComponent.h:47
Component::Reset
void Reset()
Resets the state of this component and all its children.
Definition: Component.cc:281

Generated on Tue Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18