169 #include <sys/time.h> 178 , m_commandInterpreter(this)
180 , m_interrupting(false)
181 , m_nrOfSingleStepsLeft(1)
183 , m_snapshottingEnabled(false)
185 gettimeofday(&m_lastOutputTime, NULL);
186 m_lastOutputStep = 0;
198 m_emulationFileName =
"";
206 string nameWithoutArgs = templateName;
207 size_t p = nameWithoutArgs.find(
'(');
209 nameWithoutArgs = templateName.substr(0, p);
221 bool GXemul::CreateEmulationFromTemplateMachine(
const string& templateName)
224 std::cerr << templateName <<
" is not a known template machine name.\n" 225 "Use gxemul -H to get a list of valid machine templates.\n";
241 std::cout <<
"Available template machines:\n\n";
245 size_t maxNameLen = 0;
246 for (
size_t i=0; i<names.size(); ++i)
247 if (names[i].length() > maxNameLen)
248 maxNameLen = names[i].length();
250 for (
size_t i=0; i<names.size(); ++i) {
251 string name = names[i];
253 std::cout <<
" " << name;
254 for (
size_t j=0; j<maxNameLen - name.length() + 6; ++j)
258 name,
"description");
271 if (!component.
IsNULL() &&
273 std::cout <<
"<pre>" <<
283 (machines?
"template machines" :
"components") <<
":\n" 284 "<p><table border=0>\n" 287 (machines?
"Machine name" :
"Component name") <<
":" 288 "</u></b> </td>\n";
290 std::cout <<
" <td><b><u>Screenshot:</u></b> </td>\n";
292 #ifdef UNSTABLE_DEVEL 293 " <td><b><u>Status:</u></b> </td>\n" 295 " <td><b><u>Description:</u></b> </td>\n" 296 " <td><b><u>Comments:</u></b> </td>\n" 297 " <td><b><u>Contributors:</u></b> </td>\n" 300 bool everyOther =
false;
302 for (
size_t i=0; i<names.size(); ++i) {
303 const string& componentName = names[i];
312 componentName,
"machine").empty() &&
314 componentName,
"template").empty();
317 if (!isTemplateMachine)
321 if (isTemplateMachine)
328 componentName,
"template").empty()) {
332 if (!component.
IsNULL() &&
347 (everyOther?
"#f2f2f2" :
"#e4e4e4") <<
">\n";
351 std::ifstream documentationComponentFile((
352 "doc/components/component_" 353 + componentName +
".html").c_str());
354 std::ifstream documentationMachineFile((
355 "doc/machines/machine_" 356 + componentName +
".html").c_str());
358 if (documentationComponentFile.is_open())
361 "<a href=\"components/component_" <<
363 <<
".html\"><tt>" << componentName <<
365 else if (documentationMachineFile.is_open())
368 "<a href=\"machines/machine_" <<
370 <<
".html\"><tt>" << componentName <<
374 " <td valign=top><tt>" << componentName
380 std::ifstream screenshotThumbFile((
381 "doc/machines/machine_" 382 + componentName +
"-thumb.png").c_str());
383 std::ifstream screenshotLargeFile((
384 "doc/machines/machine_" 385 + componentName +
".png").c_str());
387 std::cout <<
" <td valign=top align=center><tt>";
389 if (screenshotLargeFile.is_open())
390 std::cout <<
"<a href=machines/machine_" <<
391 componentName <<
".png>";
393 if (screenshotThumbFile.is_open())
394 std::cout <<
"<img src=machines/machine_" <<
395 componentName <<
"-thumb.png>";
396 else if (screenshotLargeFile.is_open())
397 std::cout <<
"(screenshot)";
399 if (screenshotLargeFile.is_open())
402 std::cout <<
"</tt></td>\n";
406 #ifdef UNSTABLE_DEVEL 408 componentName,
"stable")?
"stable " :
409 "experimental ") <<
"</td>\n" 412 componentName,
"description") <<
413 treeDump <<
"</td>\n" 415 componentName,
"comments") <<
"</td>\n" 417 componentName,
"contributors") <<
"</td>\n" 420 everyOther = !everyOther;
423 std::cout <<
"</table><p>\n";
429 bool optionsEnoughToStartRunning =
false;
431 if (templateMachine !=
"") {
432 if (CreateEmulationFromTemplateMachine(templateMachine)) {
435 std::cerr <<
"Failed to create configuration from " 436 "template: " << templateMachine <<
"\n" <<
447 if (filenameCount > 0) {
448 if (templateMachine !=
"") {
450 while (filenameCount > 0) {
456 cmd <<
"load " << filenames[0]
457 <<
" root.machine0.mainbus0.cpu0";
460 m_onResetCommands.push_back(cmd.str());
466 optionsEnoughToStartRunning =
true;
469 if (filenameCount == 1) {
470 string configfileName = filenames[0];
471 optionsEnoughToStartRunning =
true;
473 string cmd =
"load " + configfileName;
474 m_onResetCommands.push_back(cmd);
476 std::cerr <<
"More than one configfile name " 477 "supplied on the command line?" <<
"\n" <<
484 if (optionsEnoughToStartRunning) {
487 if (templateMachine !=
"") {
492 "No binary specified. Usually when starting up an emulation based on a template\n" 493 "machine, you need to supply one or more binaries. This could be an operating\n" 494 "system kernel, a ROM image, or something similar.\n" 496 "You can also use the -V option to start in paused mode, and load binaries\n" 499 "(Run gxemul -h for more help on command line options.)\n";
516 <<
"(unknown version)" 524 void GXemul::PrintUsage()
const 526 std::cout <<
Version() <<
"\n";
528 std::cout <<
"Insufficient command line arguments given to" 529 " start an emulation. You have\n" 530 "the following alternatives:\n" <<
532 " 1. Run gxemul with the machine selection option " 533 "(-e), which creates\n" 534 " a default emulation from a template machine.\n\n" 535 " 2. Run gxemul with a configuration file (.gxemul).\n" 536 " This is useful for more complicated setups.\n\n" 537 " 3. Run gxemul -V with no other options, which causes" 538 " gxemul to be started\n" 539 " with no emulation loaded at all.\n\n" <<
541 "Run gxemul -h for help on command line options.\n\n";
571 if (nChildren == 0 || nChildren > 1)
591 "-----------------------------------------------\n\n");
599 }
catch (std::exception& ex) {
601 ss <<
"\n### FATAL ERROR ###\n\n" << ex.what() <<
"\n\n" <<
602 "If you are able to reproduce this crash, " 603 "please send detailed repro-steps to\n" 604 "the author, to the gxemul-devel mailing list, or" 605 " ask in #GXemul on the\n" 606 "FreeNode IRC network.\n";
619 return m_emulationFileName;
625 m_emulationFileName = filename;
633 return m_commandInterpreter;
641 std::cerr <<
"root component has no 'step' variable? aborting.\n";
642 throw std::exception();
649 void GXemul::SetStep(uint64_t step)
652 if (stepVariable == NULL) {
653 std::cerr <<
"root component has no 'step' variable? aborting.\n";
654 throw std::exception();
669 return m_rootComponent;
675 return m_rootComponent;
681 if (newRootComponent.
IsNULL()) {
682 std::cerr <<
"GXemul::SetRootComponent: NULL\n";
683 throw std::exception();
687 if (rootComponent == NULL) {
688 std::cerr <<
"GXemul::SetRootComponent: not a RootComponent\n";
689 throw std::exception();
694 m_rootComponent = newRootComponent;
707 vector<string>::const_iterator it = m_onResetCommands.begin();
708 for (; it != m_onResetCommands.end(); ++it) {
710 bool success =
false;
733 m_interrupting =
true;
736 m_interrupting =
false;
743 m_runState = newState;
757 switch (m_runState) {
761 return "Single-stepping";
768 return "Unknown RunState";
774 return m_snapshottingEnabled;
782 "snapshotting/reverse execution support.)\n");
784 m_snapshottingEnabled = enabled;
796 m_quietMode = quietMode;
805 m_nrOfSingleStepsLeft = steps;
814 if (oldStep == newStep)
817 if (newStep < oldStep) {
826 int64_t nrOfStepsToRunFromSnapshot = newStep -
GetStep();
831 Execute(nrOfStepsToRunFromSnapshot);
844 void GXemul::TakeSnapshot()
848 if (m_snapshot.
IsNULL()) {
850 ss <<
"(snapshot at step " <<
GetStep() <<
")\n";
871 vector<ComponentAndFrequency>& componentsAndFrequencies)
876 if (freq != NULL && step != NULL &&
877 (paused == NULL || paused->
ToInteger() == 0)) {
879 memset(&caf, 0,
sizeof(caf));
885 componentsAndFrequencies.push_back(caf);
889 for (
size_t i=0; i<children.size(); ++i)
890 GetComponentsAndFrequencies(children[i], componentsAndFrequencies);
896 vector<ComponentAndFrequency> componentsAndFrequencies;
899 if (componentsAndFrequencies.size() == 0) {
901 " found in the configuration.\n");
907 if (m_snapshottingEnabled &&
GetStep() == 0)
911 double fastestFrequency = componentsAndFrequencies[0].frequency;
912 size_t fastestComponentIndex = 0;
913 for (
size_t i=0; i<componentsAndFrequencies.size(); ++i)
914 if (componentsAndFrequencies[i].
frequency > fastestFrequency) {
915 fastestFrequency = componentsAndFrequencies[i].frequency;
916 fastestComponentIndex = i;
919 bool printEmptyLineBetweenSteps =
false;
924 if (m_nrOfSingleStepsLeft == 0)
925 m_nrOfSingleStepsLeft = 1;
932 if (printEmptyLineBetweenSteps)
935 printEmptyLineBetweenSteps =
true;
938 ss <<
"step " << step <<
": ";
947 for (
size_t k=0; k<componentsAndFrequencies.size(); ++k) {
948 uint64_t nsteps = (k == fastestComponentIndex ?
step 949 : (uint64_t) (step * componentsAndFrequencies[k].
frequency / fastestFrequency));
951 uint64_t stepsExecutedSoFar = componentsAndFrequencies[k].step->ToInteger();
953 if (stepsExecutedSoFar > nsteps) {
954 std::cerr <<
"Internal error: " <<
955 componentsAndFrequencies[k].component->GetVariable(
"name")->ToString() <<
956 " has executed " << stepsExecutedSoFar <<
" steps, goal is " << nsteps <<
".\n";
957 throw std::exception();
960 if (stepsExecutedSoFar < nsteps) {
961 ++ stepsExecutedSoFar;
967 int n = componentsAndFrequencies[k].component->Execute(
this, 1);
975 componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar);
979 stringstream changeMessages;
981 string msg = changeMessages.str();
982 if (msg.length() > 0)
988 -- m_nrOfSingleStepsLeft;
993 m_nrOfSingleStepsLeft = 0;
999 uint64_t startingStep =
step;
1003 std::cerr <<
"GXemul::Execute(): TODO: Only " 1004 "root.accuracy=\"cycle\" is currently supported\n";
1011 while (step < startingStep + longestTotalRun) {
1017 if (componentsAndFrequencies.size() == 1) {
1018 toExecute = longestTotalRun;
1019 componentsAndFrequencies[0].nextTimeToExecute =
step;
1030 for (
size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1031 double q = (k == fastestComponentIndex ? 1.0
1032 : fastestFrequency / componentsAndFrequencies[k].frequency);
1034 double c = (componentsAndFrequencies[k].step->ToInteger()+1) * q;
1035 componentsAndFrequencies[k].nextTimeToExecute = (uint64_t) ceil(c) - 1;
1039 for (
size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1044 int diff = componentsAndFrequencies[k].nextTimeToExecute -
1045 componentsAndFrequencies[fastestComponentIndex].nextTimeToExecute;
1046 if (k != fastestComponentIndex) {
1047 if (toExecute == -1 || diff < toExecute)
1056 if (step + toExecute > startingStep + longestTotalRun)
1057 toExecute = startingStep + longestTotalRun -
step;
1064 int maxExecuted = 0;
1066 for (
size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1071 int n = componentsAndFrequencies[k].component->Execute(
this, toExecute);
1074 uint64_t stepsExecutedSoFar = n +
1075 componentsAndFrequencies[k].step->ToInteger();
1076 componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar);
1078 if (k == fastestComponentIndex)
1081 if (n != toExecute) {
1084 if (n > toExecute) {
1085 std::cerr <<
"Internal error: " << n <<
1086 " steps executed, toExecute = " << toExecute <<
"\n";
1087 throw std::exception();
1091 ss <<
"only " << n <<
" steps of " << toExecute <<
" executed.";
1102 std::cerr <<
"maxExecuted=0. internal error\n";
1103 throw std::exception();
1106 step += maxExecuted;
1111 struct timeval tvend;
1112 gettimeofday(&tvend, NULL);
1114 double secondsSinceLastOutput =
1115 ((double)tvend.tv_sec + tvend.tv_usec / 1000000.0)
1116 - ((double)m_lastOutputTime.tv_sec + m_lastOutputTime.tv_usec / 1000000.0);
1118 if (secondsSinceLastOutput > 1.0 && (step - m_lastOutputStep) > 10000) {
1119 m_lastOutputTime = tvend;
1121 int64_t stepsPerSecond = (int64_t)
1122 ( (
double)(step - m_lastOutputStep) / secondsSinceLastOutput );
1123 m_lastOutputStep = step;
1126 ss << step <<
" steps";
1127 if (stepsPerSecond > 0)
1128 ss <<
" (" << stepsPerSecond <<
" steps/second)";
1136 std::cerr <<
"GXemul::Execute() called without being in a" 1137 " running state. Internal error?\n";
1138 throw std::exception();
1141 if (m_interrupting) {
1142 m_interrupting =
false;
1150 #ifdef WITHUNITTESTS 1152 static void Test_Construction()
void SetRunState(RunState newState)
Sets the RunState.
void SetEmulationFilename(const string &filename)
Sets the current emulation setup's filename.
GXemul()
Creates a GXemul instance.
virtual void ShowDebugMessage(const string &msg)=0
Shows a debug message.
StateVariable * GetVariable(const string &name)
Gets a pointer to a state variable.
string GetRunStateAsString() const
Gets the current RunState as a string.
Dummy UI, which does not do anything.
static refcount_ptr< Component > CreateComponent(const string &componentNameAndOptionalArgs, GXemul *gxemul=NULL)
Creates a component given a short component name.
RunState GetRunState() const
Gets the current RunState.
bool Reset()
Resets the emulation.
bool GetQuietMode() const
Gets the current quiet mode setting.
void Interrupt()
Interrupts emulation.
const refcount_ptr< Component > LightClone() const
Makes a light clone of the component and all its children.
bool RunCommand(const string &command, bool *pSuccess=NULL)
Runs a command, given as a string.
A Component which is the default root node in the configuration.
virtual void UpdateUI()=0
Updates various UI elements.
uint64_t GetStep() const
Gets the current step of the emulation.
static void ListTemplates()
Dump a list to stdout with all available machine templates.
uint64_t nextTimeToExecute
Components & GetChildren()
Gets pointers to child components.
void SetSnapshottingEnabled(bool enabled)
Sets whether or not to use snapshots.
Text-terminal based User Interface.
void DetectChanges(const refcount_ptr< Component > &oldClone, ostream &changeMessages) const
Compare an older clone to the current tree, to find changes.
virtual void Initialize()=0
Initializes the UI.
void SetNrOfSingleStepsInARow(uint64_t steps)
Sets the nr of single-steps to perform in a row.
An interactive command interpreter, which run Commands.
bool ModifyStep(int64_t oldStep, int64_t newStep)
Change step either forwards or backwards.
static string Version()
Returns the GXemul version string.
#define UNITTESTS(class)
Helper for unit test case execution.
CommandInterpreter & GetCommandInterpreter()
Gets a reference to the CommandInterpreter.
const string & GetEmulationFilename() const
Gets the current emulation setup's filename.
bool SetValue(const string &expression)
Set the variable's value, using a string expression.
double ToDouble() const
Returns the variable as a double value.
static bool HasAttribute(const string &name, const string &attributeName)
Checks if a component has a specific attribute.
virtual RootComponent * AsRootComponent()
Returns the component's RootComponent interface.
A Component is a node in the configuration tree that makes up an emulation setup. ...
static void DumpMachineAsHTML(const string &machineName)
static vector< string > GetAllComponentNames(bool onlyTemplates)
Returns a vector of all available component names.
bool GetSnapshottingEnabled() const
Checks whether snapshots are currently enabled or not.
uint64_t ToInteger() const
Returns the variable as an unsignedinteger value.
StateVariables make up the persistent state of Component objects.
virtual void FatalError(const string &msg)=0
Shows a fatal error message.
void ClearEmulation()
Discards the current emulation, and starts anew with just an empty root component.
virtual int MainLoop()=0
Runs the UI's main loop.
void SetRootComponent(refcount_ptr< Component > newRootComponent)
Sets the root component, discarding the previous one.
void InitUI()
Initializes the UI.
bool IsTemplateMachine(const string &templateName) const
refcount_ptr< Component > Clone() const
Clones the component and all its children.
refcount_ptr< Component > GetRootComponent()
Gets a pointer to the root configuration component.
static string GetAttribute(const string &name, const string &attributeName)
Gets a specific attribute value for a component.
void AddChild(refcount_ptr< Component > childComponent, size_t insertPosition=(size_t) -1)
Adds a reference to a child component.
void Reset()
Resets the state of this component and all its children.
int Run()
Runs GXemul's main loop.
static void GenerateHTMLListOfComponents(bool machines)
virtual void ShowStartupBanner()=0
Shows a startup banner.
UI * GetUI()
Gets a pointer to the GXemul instance' active UI.
void SetOwner(GXemul *owner)
Base class for a User Interface.
void SetQuietMode(bool quietMode)
Sets whether or not to run in quiet mode.
vector< refcount_ptr< Component > > Components
void Execute(const int longestTotalRun=100000)
Run the emulation for "a while".
string GenerateTreeDump(const string &branchTemplate, bool htmlLinksForClassNames=false, string prefixForComponentUrls="") const
Generates an ASCII tree dump of a component tree.
bool ParseFilenames(string templateMachine, int filenameCount, char *filenames[])
Parses command line arguments (file names).
#define UNITTEST(functionname)
Helper for unit test case execution.
bool IsNULL() const
Checks whether or not an object is referenced by the reference counted pointer.
refcount_ptr< Component > component