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 
34 #include "components/RootComponent.h"
35 #include "Component.h"
36 #include "ComponentFactory.h"
37 #include "EscapedString.h"
38 #include "GXemul.h"
39 #include "StringHelper.h"
40 
41 
Component(const string & className,const string & visibleClassName)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 
GetClassName() const54 string Component::GetClassName() const
55 {
56 	return m_className;
57 }
58 
59 
GetVisibleClassName() const60 string Component::GetVisibleClassName() const
61 {
62 	return m_visibleClassName;
63 }
64 
65 
GetAttribute(const string & attributeName)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 
Clone() const76 refcount_ptr<Component> Component::Clone() const
77 {
78 	refcount_ptr<Component> clone;
79 
80 	if (GetClassName() == "root")
81 		clone = new RootComponent;
82 	else
83 		clone = ComponentFactory::CreateComponent(GetClassName());
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 
LightCloneInternal() const131 refcount_ptr<Component> Component::LightCloneInternal() const
132 {
133 	refcount_ptr<Component> clone;
134 
135 	if (GetClassName() == "root")
136 		clone = new RootComponent;
137 	else
138 		clone = ComponentFactory::CreateComponent(GetClassName());
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 
LightClone() const192 const refcount_ptr<Component> Component::LightClone() const
193 {
194 	return LightCloneInternal();
195 }
196 
197 
DetectChanges(const refcount_ptr<Component> & oldClone,ostream & changeMessages) const198 void Component::DetectChanges(const refcount_ptr<Component>& oldClone,
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 
Reset()281 void Component::Reset()
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 
ResetState()291 void Component::ResetState()
292 {
293 	// Base implementation.
294 	m_step = 0;
295 }
296 
297 
PreRunCheck(GXemul * gxemul)298 bool Component::PreRunCheck(GXemul* gxemul)
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 
PreRunCheckForComponent(GXemul * gxemul)310 bool Component::PreRunCheckForComponent(GXemul* gxemul)
311 {
312 	// Base implementation: Do nothing. Everything is Ok.
313 	return true;
314 }
315 
316 
FlushCachedState()317 void Component::FlushCachedState()
318 {
319 	FlushCachedStateForComponent();
320 
321 	// Recurse:
322 	for (size_t i = 0; i < m_childComponents.size(); ++ i)
323 		m_childComponents[i]->FlushCachedState();
324 }
325 
326 
FlushCachedStateForComponent()327 void Component::FlushCachedStateForComponent()
328 {
329 	// Base implementation: Do nothing.
330 }
331 
332 
Execute(GXemul * gxemul,int nrOfCycles)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 
GetCurrentFrequency() const343 double Component::GetCurrentFrequency() const
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 
AsRootComponent()353 RootComponent* Component::AsRootComponent()
354 {
355 	// Default implementation (the base Component class) is not a RootComponent.
356 	return NULL;
357 }
358 
359 
AsCPUComponent()360 CPUComponent* Component::AsCPUComponent()
361 {
362 	// Default implementation (the base Component class) is not a CPU.
363 	return NULL;
364 }
365 
366 
AsAddressDataBus()367 AddressDataBus* Component::AsAddressDataBus()
368 {
369 	// Default implementation (the base Component class) is not an
370 	// address data bus.
371 	return NULL;
372 }
373 
374 
SetParent(Component * parentComponent)375 void Component::SetParent(Component* parentComponent)
376 {
377 	m_parentComponent = parentComponent;
378 }
379 
380 
GetParent()381 Component* Component::GetParent()
382 {
383 	return m_parentComponent;
384 }
385 
386 
GetParent() const387 const Component* Component::GetParent() const
388 {
389 	return m_parentComponent;
390 }
391 
392 
GetMethodNames(vector<string> & names) const393 void Component::GetMethodNames(vector<string>& names) const
394 {
395 	// The default component has no implemented methods.
396 }
397 
398 
MethodMayBeReexecutedWithoutArgs(const string & methodName) const399 bool Component::MethodMayBeReexecutedWithoutArgs(const string& methodName) const
400 {
401 	// By default, methods are _not_ re-executable without args.
402 	return false;
403 }
404 
405 
ExecuteMethod(GXemul * gxemul,const string & methodName,const vector<string> & arguments)406 void Component::ExecuteMethod(GXemul* gxemul,
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 
GenerateDetails() const417 string Component::GenerateDetails() const
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 
GenerateTreeDump(const string & branchTemplate,bool htmlLinksForClassNames,string prefixForComponentUrls) const459 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 
GetRunningGXemulInstance()569 GXemul* Component::GetRunningGXemulInstance()
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 
GetUI()583 UI* Component::GetUI()
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 
AddChild(refcount_ptr<Component> childComponent,size_t insertPosition)595 void Component::AddChild(refcount_ptr<Component> childComponent,
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 
RemoveChild(Component * childToRemove)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 
GetChildren()674 Components& Component::GetChildren()
675 {
676 	return m_childComponents;
677 }
678 
679 
GetChildren() const680 const Components& Component::GetChildren() const
681 {
682 	return m_childComponents;
683 }
684 
685 
GeneratePath() const686 string Component::GeneratePath() const
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 
SplitPathStringIntoVector(const string & path)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 
GenerateShortestPossiblePath() const721 string Component::GenerateShortestPossiblePath() const
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 
LookupPath(string path) const778 const refcount_ptr<Component> Component::LookupPath(string path) const
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 
LookupPath(const vector<string> & path,size_t index) const818 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 
AddAllComponentPaths(vector<string> & allComponentPaths) const864 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 
PartialMatch(const string & partialPath,const string & path)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 
FindPathByPartialMatch(const string & partialPath,bool shortestPossible) const912 vector<string> Component::FindPathByPartialMatch(
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 
GetVariableNames(vector<string> & names) const941 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 
GetVariable(const string & name)949 StateVariable* Component::GetVariable(const string& name)
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 
GetVariable(const string & name) const959 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 
CheckVariableWrite(StateVariable & var,const string & oldValue)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 
SetVariableValue(const string & name,const string & expression)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 
Serialize(ostream & ss,SerializationContext & context) const1070 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 
GetNextToken(const string & str,size_t & pos,string & token)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 
Deserialize(ostream & messages,const string & str,size_t & pos)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 
CheckConsistency() const1226 bool Component::CheckConsistency() const
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 
AddChecksum(Checksum & checksum) const1253 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 
1287