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 " <td><b><u>Description:</u></b> </td>\n"
293 " <td><b><u>Comments:</u></b> </td>\n"
294 " <td><b><u>Contributors:</u></b> </td>\n"
297 bool everyOther =
false;
299 for (
size_t i=0; i<names.size(); ++i) {
300 const string& componentName = names[i];
309 componentName,
"machine").empty() &&
311 componentName,
"template").empty();
314 if (!isTemplateMachine)
318 if (isTemplateMachine)
325 componentName,
"template").empty()) {
329 if (!component.
IsNULL() &&
344 (everyOther?
"#f2f2f2" :
"#e4e4e4") <<
">\n";
348 std::ifstream documentationComponentFile((
349 "doc/components/component_"
350 + componentName +
".html").c_str());
351 std::ifstream documentationMachineFile((
352 "doc/machines/machine_"
353 + componentName +
".html").c_str());
355 if (documentationComponentFile.is_open())
358 "<a href=\"components/component_" <<
360 <<
".html\"><tt>" << componentName <<
362 else if (documentationMachineFile.is_open())
365 "<a href=\"machines/machine_" <<
367 <<
".html\"><tt>" << componentName <<
371 " <td valign=top><tt>" << componentName
377 std::ifstream screenshotThumbFile((
378 "doc/machines/machine_"
379 + componentName +
"-thumb.png").c_str());
380 std::ifstream screenshotLargeFile((
381 "doc/machines/machine_"
382 + componentName +
".png").c_str());
384 std::cout <<
" <td valign=top align=center><tt>";
386 if (screenshotLargeFile.is_open())
387 std::cout <<
"<a href=machines/machine_" <<
388 componentName <<
".png>";
390 if (screenshotThumbFile.is_open())
391 std::cout <<
"<img src=machines/machine_" <<
392 componentName <<
"-thumb.png>";
393 else if (screenshotLargeFile.is_open())
394 std::cout <<
"(screenshot)";
396 if (screenshotLargeFile.is_open())
399 std::cout <<
"</tt></td>\n";
404 componentName,
"description") <<
405 treeDump <<
"</td>\n"
407 componentName,
"comments") <<
"</td>\n"
409 componentName,
"contributors") <<
"</td>\n"
412 everyOther = !everyOther;
415 std::cout <<
"</table><p>\n";
421 bool optionsEnoughToStartRunning =
false;
423 if (templateMachine !=
"") {
424 if (CreateEmulationFromTemplateMachine(templateMachine)) {
427 std::cerr <<
"Failed to create configuration from "
428 "template: " << templateMachine <<
"\n" <<
439 if (filenameCount > 0) {
440 if (templateMachine !=
"") {
442 while (filenameCount > 0) {
448 cmd <<
"load " << filenames[0]
449 <<
" root.machine0.mainbus0.cpu0";
452 m_onResetCommands.push_back(
cmd.str());
458 optionsEnoughToStartRunning =
true;
461 if (filenameCount == 1) {
462 string configfileName = filenames[0];
463 optionsEnoughToStartRunning =
true;
465 string cmd =
"load " + configfileName;
466 m_onResetCommands.push_back(
cmd);
468 std::cerr <<
"More than one configfile name "
469 "supplied on the command line?" <<
"\n" <<
476 if (optionsEnoughToStartRunning) {
479 if (templateMachine !=
"") {
484 "No binary specified. Usually when starting up an emulation based on a template\n"
485 "machine, you need to supply one or more binaries. This could be an operating\n"
486 "system kernel, a ROM image, or something similar.\n"
488 "You can also use the -V option to start in paused mode, and load binaries\n"
491 "(Run gxemul -h for more help on command line options.)\n";
508 <<
"(unknown version)"
516 void GXemul::PrintUsage()
const
518 std::cout <<
Version() <<
"\n";
520 std::cout <<
"Insufficient command line arguments given to"
521 " start an emulation. You have\n"
522 "the following alternatives:\n" <<
524 " 1. Run gxemul with the machine selection option "
525 "(-e), which creates\n"
526 " a default emulation from a template machine.\n\n"
527 " 2. Run gxemul with a configuration file (.gxemul).\n"
528 " This is useful for more complicated setups.\n\n"
529 " 3. Run gxemul -V with no other options, which causes"
530 " gxemul to be started\n"
531 " with no emulation loaded at all.\n\n" <<
533 "Run gxemul -h for help on command line options.\n\n";
563 if (nChildren == 0 || nChildren > 1)
583 "-----------------------------------------------\n\n");
591 }
catch (std::exception& ex) {
593 ss <<
"\n### FATAL ERROR ###\n\n" << ex.what() <<
"\n\n" <<
594 "If you are able to reproduce this crash, "
595 "please send detailed repro-steps to\n"
596 "the author, to the gxemul-devel mailing list, or"
597 " ask in #GXemul on the\n"
598 "FreeNode IRC network.\n";
611 return m_emulationFileName;
617 m_emulationFileName = filename;
625 return m_commandInterpreter;
633 std::cerr <<
"root component has no 'step' variable? aborting.\n";
634 throw std::exception();
641 void GXemul::SetStep(uint64_t step)
644 if (stepVariable == NULL) {
645 std::cerr <<
"root component has no 'step' variable? aborting.\n";
646 throw std::exception();
661 return m_rootComponent;
667 return m_rootComponent;
673 if (newRootComponent.
IsNULL()) {
674 std::cerr <<
"GXemul::SetRootComponent: NULL\n";
675 throw std::exception();
679 if (rootComponent == NULL) {
680 std::cerr <<
"GXemul::SetRootComponent: not a RootComponent\n";
681 throw std::exception();
686 m_rootComponent = newRootComponent;
699 vector<string>::const_iterator it = m_onResetCommands.begin();
700 for (; it != m_onResetCommands.end(); ++it) {
702 bool success =
false;
725 m_interrupting =
true;
728 m_interrupting =
false;
735 m_runState = newState;
749 switch (m_runState) {
753 return "Single-stepping";
760 return "Unknown RunState";
766 return m_snapshottingEnabled;
774 "snapshotting/reverse execution support.)\n");
776 m_snapshottingEnabled = enabled;
788 m_quietMode = quietMode;
797 m_nrOfSingleStepsLeft = steps;
806 if (oldStep == newStep)
809 if (newStep < oldStep) {
818 int64_t nrOfStepsToRunFromSnapshot = newStep -
GetStep();
823 Execute(nrOfStepsToRunFromSnapshot);
836 void GXemul::TakeSnapshot()
840 if (m_snapshot.
IsNULL()) {
842 ss <<
"(snapshot at step " <<
GetStep() <<
")\n";
863 vector<ComponentAndFrequency>& componentsAndFrequencies)
868 if (freq != NULL && step != NULL &&
869 (paused == NULL || paused->
ToInteger() == 0)) {
877 componentsAndFrequencies.push_back(caf);
881 for (
size_t i=0; i<children.size(); ++i)
882 GetComponentsAndFrequencies(children[i], componentsAndFrequencies);
888 vector<ComponentAndFrequency> componentsAndFrequencies;
891 if (componentsAndFrequencies.size() == 0) {
893 " found in the configuration.\n");
899 if (m_snapshottingEnabled &&
GetStep() == 0)
903 double fastestFrequency = componentsAndFrequencies[0].frequency;
904 size_t fastestComponentIndex = 0;
905 for (
size_t i=0; i<componentsAndFrequencies.size(); ++i)
906 if (componentsAndFrequencies[i].
frequency > fastestFrequency) {
907 fastestFrequency = componentsAndFrequencies[i].frequency;
908 fastestComponentIndex = i;
911 bool printEmptyLineBetweenSteps =
false;
916 if (m_nrOfSingleStepsLeft == 0)
917 m_nrOfSingleStepsLeft = 1;
924 if (printEmptyLineBetweenSteps)
927 printEmptyLineBetweenSteps =
true;
930 ss <<
"step " <<
step <<
": ";
939 for (
size_t k=0; k<componentsAndFrequencies.size(); ++k) {
940 uint64_t nsteps = (k == fastestComponentIndex ?
step
941 : (uint64_t) (
step * componentsAndFrequencies[k].
frequency / fastestFrequency));
943 uint64_t stepsExecutedSoFar = componentsAndFrequencies[k].step->ToInteger();
945 if (stepsExecutedSoFar > nsteps) {
946 std::cerr <<
"Internal error: " <<
947 componentsAndFrequencies[k].component->GetVariable(
"name")->ToString() <<
948 " has executed " << stepsExecutedSoFar <<
" steps, goal is " << nsteps <<
".\n";
949 throw std::exception();
952 if (stepsExecutedSoFar < nsteps) {
953 ++ stepsExecutedSoFar;
959 int n = componentsAndFrequencies[k].component->Execute(
this, 1);
967 componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar);
971 stringstream changeMessages;
973 string msg = changeMessages.str();
974 if (msg.length() > 0)
980 -- m_nrOfSingleStepsLeft;
985 m_nrOfSingleStepsLeft = 0;
991 uint64_t startingStep =
step;
995 std::cerr <<
"GXemul::Execute(): TODO: Only "
996 "root.accuracy=\"cycle\" is currently supported\n";
1003 while (
step < startingStep + longestTotalRun) {
1009 if (componentsAndFrequencies.size() == 1) {
1010 toExecute = longestTotalRun;
1011 componentsAndFrequencies[0].nextTimeToExecute =
step;
1022 for (
size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1023 double q = (k == fastestComponentIndex ? 1.0
1024 : fastestFrequency / componentsAndFrequencies[k].frequency);
1026 double c = (componentsAndFrequencies[k].step->ToInteger()+1) * q;
1027 componentsAndFrequencies[k].nextTimeToExecute = (uint64_t) ceil(c) - 1;
1031 for (
size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1036 int diff = componentsAndFrequencies[k].nextTimeToExecute -
1037 componentsAndFrequencies[fastestComponentIndex].nextTimeToExecute;
1038 if (k != fastestComponentIndex) {
1039 if (toExecute == -1 || diff < toExecute)
1048 if (
step + toExecute > startingStep + longestTotalRun)
1049 toExecute = startingStep + longestTotalRun -
step;
1056 int maxExecuted = 0;
1058 for (
size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1063 int n = componentsAndFrequencies[k].component->Execute(
this, toExecute);
1066 uint64_t stepsExecutedSoFar = n +
1067 componentsAndFrequencies[k].step->ToInteger();
1068 componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar);
1070 if (k == fastestComponentIndex)
1073 if (n != toExecute) {
1076 if (n > toExecute) {
1077 std::cerr <<
"Internal error: " << n <<
1078 " steps executed, toExecute = " << toExecute <<
"\n";
1079 throw std::exception();
1083 ss <<
"only " << n <<
" steps of " << toExecute <<
" executed.";
1094 std::cerr <<
"maxExecuted=0. internal error\n";
1095 throw std::exception();
1098 step += maxExecuted;
1103 struct timeval tvend;
1104 gettimeofday(&tvend, NULL);
1106 double secondsSinceLastOutput =
1107 ((double)tvend.tv_sec + tvend.tv_usec / 1000000.0)
1108 - ((double)m_lastOutputTime.tv_sec + m_lastOutputTime.tv_usec / 1000000.0);
1110 if (secondsSinceLastOutput > 1.0 && (step - m_lastOutputStep) > 10000) {
1111 m_lastOutputTime = tvend;
1113 int64_t stepsPerSecond = (int64_t)
1114 ( (
double)(step - m_lastOutputStep) / secondsSinceLastOutput );
1115 m_lastOutputStep = step;
1118 ss << step <<
" steps";
1119 if (stepsPerSecond > 0)
1120 ss <<
" (" << stepsPerSecond <<
" steps/second)";
1128 std::cerr <<
"GXemul::Execute() called without being in a"
1129 " running state. Internal error?\n";
1130 throw std::exception();
1133 if (m_interrupting) {
1134 m_interrupting =
false;
1142 #ifdef WITHUNITTESTS
1144 static void Test_Construction()