GXemul.cc Source File

Back to the index.

GXemul.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2018 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  * This file contains two things:
29  *
30  * 1. Doxygen documentation for the general design concepts of the
31  * emulator. The mainpage documentation written here ends up on
32  * the "main page" in the generated HTML documentation.
33  *
34  * 2. The GXemul class implementation.
35  */
36 
37 
38 /*! \mainpage Source code documentation
39  *
40  * \section intro_sec Introduction
41  *
42  * This is the automatically generated Doxygen documentation for %GXemul,
43  * built from comments throughout the source code.
44  *
45  * See the <a href="../../index.html">main documentation</a> for more
46  * information about this version of %GXemul.
47  *
48  * See GXemul's home page for more information about %GXemul in general:
49  * <a href="http://gxemul.sourceforge.net/">http://gxemul.sourceforge.net/</a>
50  *
51  * (<b>NOTE:</b> There is a huge portion of code in
52  * %GXemul which is legacy code. The documentation you will find on this page
53  * is only about the new framework, which is available from release 0.6.0.)
54  *
55  * The main program creates a GXemul instance, and does one of two things:
56  * <ul>
57  * <li>Starts without any template %machine. (<tt>-V</tt>)
58  * <li>Starts with a template %machine, and a list of additional
59  * components and files
60  * to attempt to attach (usually kernel binary to boot in the
61  * emulated %machine).
62  * </ul>
63  *
64  * After letting the %GXemul instance load the files (or, in the more general
65  * case, attach the components), GXemul::Run() is called.
66  * This is the main loop. It doesn't really do much, it simply calls the UI's
67  * main loop, i.e. ConsoleUI::MainLoop().
68  *
69  * Most of the source code in %GXemul centers around a few core concepts.
70  * An overview of these concepts are given below. Anyone who wishes to
71  * delve into the source code should be familiar with them.
72  *
73  *
74  * \section concepts_sec Core concepts
75  *
76  * See the end-user <a href="../../framework.html">description of the framework</a>
77  * for information about how these concepts appear to the actual user. The
78  * sections below describe how those concepts are implemented in the code.
79  *
80  * \subsection components_subsec Components
81  *
82  * The most important core concept in %GXemul is the Component. Examples of
83  * components are processors, networks interface cards, video displays, RAM
84  * %memory, busses, %interrupt controllers, and all other kinds of devices.
85  *
86  * Each component has a parent, so the full set of components in an emulation
87  * are in fact a tree. A GXemul instance has one such tree. The root
88  * component is a special RootComponent, which holds some basic state about
89  * the emulation, such as the number of steps executed.
90  * It also contains zero or more sub-components.
91  *
92  * <center><img src="../../model.png"></center>
93  *
94  * Starting from the root node, each component has a <i>path</i>, e.g.
95  * <tt>root.machine1.mainbus0.ram0</tt> for the RAM component in machine1
96  * in the example above.
97  *
98  * The state of each component is stored within that component. The state
99  * consists of a number of variables (see StateVariable) such as strings,
100  * integers, bools, and other more high-level types such as zero-filled %memory
101  * arrays. Such %memory arrays are used e.g. by the RAMComponent to emulate
102  * RAM, and can also be used to emulate video framebuffer %memory.
103  *
104  * Individual components are implemented in <tt>src/components/</tt>, with
105  * header files in <tt>src/include/components/</tt>. The <tt>configure</tt>
106  * script looks for the string <tt>COMPONENT(name)</tt> in the header files,
107  * and automagically adds those to the list of components that will be
108  * available at runtime. In addition, <tt>make documentation</tt> also builds
109  * HTML pages with lists of available
110  * <a href="../../components.html">components</a>, and as a special case,
111  * a list of available
112  * <a href="../../machines.html">template machines</a> (because they have
113  * special meaning to the end-user).
114  *
115  * \subsection commandinterpreter_subsec Command interpreter
116  *
117  * A GXemul instance has a CommandInterpreter, which is the part that parses a
118  * command line, figures out which Command is to be executed, and executes it.
119  * The %CommandInterpreter can be given a complete command line as a string, or
120  * it can be given one character (or keypress) at a time. In the later case,
121  * the TAB key either completes the word currently being written, or writes
122  * out a list of possible completions.
123  *
124  * The %CommandInterpreter, via the ConsoleUI, is the user interface as seen
125  * by the user.
126  *
127  * \subsection unittest_subsec Unit tests
128  *
129  * Wherever it makes sense, unit tests should be written to make sure
130  * that the code is correct, and stays correct. The UnitTest class contains
131  * static helper functions for writing unit tests, such as UnitTest::Assert.
132  * To add unit tests to a class, the class should be UnitTestable, and in
133  * particular, it should implement UnitTestable::RunUnitTests by using the
134  * UNITTESTS(className) macro. Individual test cases are then called, as
135  * static non-member functions, using the UNITTEST(testname) macro.
136  *
137  * Since test cases are non-member functions, they need to create instances
138  * of the class they wish to test, and they can only call public member
139  * functions on those objects, not private ones. Thus, the unit tests only
140  * test the "public API" of all classes. (If the internal API needs to be
141  * tested, then a workaround can be to add a ConsistencyCheck member function
142  * which is public, but mentioning in the documentation for that function
143  * that it is only meant for internal use and debugging.)
144  *
145  * Unit tests are normally executed by <tt>make test</tt>. This is implicitly
146  * done when doing <tt>make install</tt> as well.
147  *
148  * It is recommended to run the <tt>configure</tt> script with the
149  * <tt>--debug</tt> option during development; among other things, this enables
150  * use of <a href="http://wyw.dcweb.cn/">Wu Yongwei</a>'s new/debug %memory
151  * leak detector (part of
152  * <a href="http://sourceforge.net/projects/nvwa/">Stones of NVWA</a>).
153  */
154 
155 
156 /*****************************************************************************/
157 
158 #include "ConsoleUI.h"
159 #include "NullUI.h"
160 
161 #include "GXemul.h"
163 #include "ComponentFactory.h"
164 #include "UnitTest.h"
165 
166 #include <assert.h>
167 #include <string.h>
168 #include <unistd.h>
169 #include <sys/time.h>
170 #include <cmath>
171 #include <fstream>
172 #include <iostream>
173 
174 
176  : m_quietMode(false)
177  , m_ui(new NullUI(this))
178  , m_commandInterpreter(this)
179  , m_runState(Paused)
180  , m_interrupting(false)
181  , m_nrOfSingleStepsLeft(1)
182  , m_rootComponent(new RootComponent(this))
183  , m_snapshottingEnabled(false)
184 {
185  gettimeofday(&m_lastOutputTime, NULL);
186  m_lastOutputStep = 0;
187 
188  ClearEmulation();
189 }
190 
191 
193 {
194  if (GetRunState() == Running)
196 
197  m_rootComponent = new RootComponent(this);
198  m_emulationFileName = "";
199 
200  GetUI()->UpdateUI();
201 }
202 
203 
204 bool GXemul::IsTemplateMachine(const string& templateName) const
205 {
206  string nameWithoutArgs = templateName;
207  size_t p = nameWithoutArgs.find('(');
208  if (p > 0)
209  nameWithoutArgs = templateName.substr(0, p);
210 
211  if (!ComponentFactory::HasAttribute(nameWithoutArgs, "template"))
212  return false;
213 
214  if (!ComponentFactory::HasAttribute(nameWithoutArgs, "machine"))
215  return false;
216 
217  return true;
218 }
219 
220 
221 bool GXemul::CreateEmulationFromTemplateMachine(const string& templateName)
222 {
223  if (!IsTemplateMachine(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";
226  return false;
227  }
228 
230  ComponentFactory::CreateComponent(templateName, this);
231  if (machine.IsNULL())
232  return false;
233 
234  GetRootComponent()->AddChild(machine);
235  return true;
236 }
237 
238 
240 {
241  std::cout << "Available template machines:\n\n";
242 
243  vector<string> names = ComponentFactory::GetAllComponentNames(true);
244 
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();
249 
250  for (size_t i=0; i<names.size(); ++i) {
251  string name = names[i];
252 
253  std::cout << " " << name;
254  for (size_t j=0; j<maxNameLen - name.length() + 6; ++j)
255  std::cout << " ";
256 
257  std::cout << ComponentFactory::GetAttribute(
258  name, "description");
259  std::cout << "\n";
260  }
261 
262  std::cout << "\n";
263 }
264 
265 
266 void GXemul::DumpMachineAsHTML(const string& machineName)
267 {
268  refcount_ptr<Component> component =
270 
271  if (!component.IsNULL() &&
272  component->GetChildren().size() != 0)
273  std::cout << "<pre>" <<
274  component->GenerateTreeDump("", true, "../")
275  << "</pre>";
276 }
277 
278 
280 {
281  std::cout <<
282  "Available " <<
283  (machines? "template machines" : "components") << ":\n"
284  "<p><table border=0>\n"
285  "<tr>\n"
286  " <td><b><u>" <<
287  (machines? "Machine&nbsp;name" : "Component&nbsp;name") << ":"
288  "</u></b>&nbsp;&nbsp;</td>\n";
289  if (machines)
290  std::cout << " <td><b><u>Screenshot:</u></b>&nbsp;&nbsp;</td>\n";
291  std::cout <<
292 #ifdef UNSTABLE_DEVEL
293  " <td><b><u>Status:</u></b>&nbsp;&nbsp;</td>\n"
294 #endif
295  " <td><b><u>Description:</u></b>&nbsp;&nbsp;</td>\n"
296  " <td><b><u>Comments:</u></b>&nbsp;&nbsp;</td>\n"
297  " <td><b><u>Contributors:</u></b>&nbsp;&nbsp;</td>\n"
298  "</tr>\n";
299 
300  bool everyOther = false;
301  vector<string> names = ComponentFactory::GetAllComponentNames(false);
302  for (size_t i=0; i<names.size(); ++i) {
303  const string& componentName = names[i];
304  string treeDump;
305 
306  refcount_ptr<Component> creatable =
307  ComponentFactory::CreateComponent(componentName);
308  if (creatable.IsNULL())
309  continue;
310 
311  bool isTemplateMachine = !ComponentFactory::GetAttribute(
312  componentName, "machine").empty() &&
314  componentName, "template").empty();
315 
316  if (machines) {
317  if (!isTemplateMachine)
318  continue;
319  } else {
320  // Other components: Don't include template machines.
321  if (isTemplateMachine)
322  continue;
323  }
324 
325  // Include an ASCII tree dump for template components that
326  // have children:
328  componentName, "template").empty()) {
329  refcount_ptr<Component> component =
330  ComponentFactory::CreateComponent(componentName);
331 
332  if (!component.IsNULL() &&
333  component->GetChildren().size() != 0)
334  treeDump = "<pre>" +
335  component->GenerateTreeDump("", true)
336  + "</pre>";
337  }
338 
339  // Some distance between table entries:
340  std::cout <<
341  "<tr>\n"
342  " <td></td>"
343  "</tr>\n";
344 
345  std::cout <<
346  "<tr bgcolor=" <<
347  (everyOther? "#f2f2f2" : "#e4e4e4") << ">\n";
348 
349  // Include a href link to a "full html page" for a component,
350  // if it exists:
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());
357 
358  if (documentationComponentFile.is_open())
359  std::cout <<
360  " <td valign=top>"
361  "<a href=\"components/component_" <<
362  componentName
363  << ".html\"><tt>" << componentName <<
364  "</tt></a></td>\n";
365  else if (documentationMachineFile.is_open())
366  std::cout <<
367  " <td valign=top>"
368  "<a href=\"machines/machine_" <<
369  componentName
370  << ".html\"><tt>" << componentName <<
371  "</tt></a></td>\n";
372  else
373  std::cout <<
374  " <td valign=top><tt>" << componentName
375  << "</tt></td>\n";
376 
377  if (machines) {
378  // Include an img and a href link to a screenshot for a component,
379  // if it exists:
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());
386 
387  std::cout << " <td valign=top align=center><tt>";
388 
389  if (screenshotLargeFile.is_open())
390  std::cout << "<a href=machines/machine_" <<
391  componentName << ".png>";
392 
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)";
398 
399  if (screenshotLargeFile.is_open())
400  std::cout << "</a>";
401 
402  std::cout << "</tt></td>\n";
403  }
404 
405  std::cout <<
406 #ifdef UNSTABLE_DEVEL
407  " <td valign=top>" << (ComponentFactory::HasAttribute(
408  componentName, "stable")? "stable&nbsp;&nbsp;" :
409  "experimental&nbsp;&nbsp;") << "</td>\n"
410 #endif
411  " <td valign=top>" << ComponentFactory::GetAttribute(
412  componentName, "description") <<
413  treeDump << "</td>\n"
414  " <td valign=top>" << ComponentFactory::GetAttribute(
415  componentName, "comments") << "</td>\n"
416  " <td valign=top>" << ComponentFactory::GetAttribute(
417  componentName, "contributors") << "</td>\n"
418  "</tr>\n";
419 
420  everyOther = !everyOther;
421  }
422 
423  std::cout << "</table><p>\n";
424 }
425 
426 
427 bool GXemul::ParseFilenames(string templateMachine, int filenameCount, char *filenames[])
428 {
429  bool optionsEnoughToStartRunning = false;
430 
431  if (templateMachine != "") {
432  if (CreateEmulationFromTemplateMachine(templateMachine)) {
433  // A template is now being used.
434  } else {
435  std::cerr << "Failed to create configuration from "
436  "template: " << templateMachine << "\n" <<
437  "Aborting." << "\n";
438  return false;
439  }
440  }
441 
442  // 1. If a machine template has been selected, then treat the following
443  // arguments as arguments to the 'add' command.
444  //
445  // 2. Otherwise, treat the argument as a configuration file.
446 
447  if (filenameCount > 0) {
448  if (templateMachine != "") {
449  // Machine template.
450  while (filenameCount > 0) {
451  stringstream cmd;
452 
453  // TODO: Different syntax!
454  // Use "add" with different syntax here...
455 
456  cmd << "load " << filenames[0]
457  << " root.machine0.mainbus0.cpu0";
458 
459  // TODO: Get rid of this onReset mechanism!
460  m_onResetCommands.push_back(cmd.str());
461 
462  filenameCount --;
463  filenames ++;
464  }
465 
466  optionsEnoughToStartRunning = true;
467  } else {
468  // Config file.
469  if (filenameCount == 1) {
470  string configfileName = filenames[0];
471  optionsEnoughToStartRunning = true;
472 
473  string cmd = "load " + configfileName;
474  m_onResetCommands.push_back(cmd);
475  } else {
476  std::cerr << "More than one configfile name "
477  "supplied on the command line?" << "\n" <<
478  "Aborting." << "\n";
479  return false;
480  }
481  }
482  }
483 
484  if (optionsEnoughToStartRunning) {
485  return true;
486  } else {
487  if (templateMachine != "") {
488  if (GetRunState() == Paused)
489  return true;
490 
491  std::cerr <<
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"
495  "\n"
496  "You can also use the -V option to start in paused mode, and load binaries\n"
497  "interactively.\n"
498  "\n"
499  "(Run gxemul -h for more help on command line options.)\n";
500  return false;
501  }
502 
503  PrintUsage();
504  return false;
505  }
506 }
507 
508 
510 {
511  stringstream ss;
512  ss << "GXemul "
513 #ifdef VERSION
514  << VERSION
515 #else
516  << "(unknown version)"
517 #endif
518  << " " COPYRIGHT_MSG"\n" SECONDARY_MSG;
519 
520  return ss.str();
521 }
522 
523 
524 void GXemul::PrintUsage() const
525 {
526  std::cout << Version() << "\n";
527 
528  std::cout << "Insufficient command line arguments given to"
529  " start an emulation. You have\n"
530  "the following alternatives:\n" <<
531  "\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" <<
540  "\n" <<
541  "Run gxemul -h for help on command line options.\n\n";
542 }
543 
544 
546 {
547  // Default to the console UI:
548  m_ui = new ConsoleUI(this);
549 
550  // Once a GUI has been implemented, this is the
551  // place to call its constructor. TODO
552 
553  GetUI()->Initialize();
554 }
555 
556 
558 {
559  // Not really running yet:
560  RunState savedRunState = GetRunState();
562 
563  if (!GetQuietMode()) {
565 
566  // Dump (a suitable part of) the configuration tree at startup.
567  const Component* component = GetRootComponent();
568  if (component->GetChildren().size() > 0) {
569  while (true) {
570  int nChildren = component->GetChildren().size();
571  if (nChildren == 0 || nChildren > 1)
572  break;
573 
574  component = component->GetChildren()[0];
575  }
576 
577  GetUI()->ShowDebugMessage(component->GenerateTreeDump("") + "\n");
578  }
579  }
580 
581  if (!Reset()) {
582  GetUI()->ShowDebugMessage("Aborting.\n");
583  return 1;
584  }
585 
586  if (!GetQuietMode()) {
587  // A separator line, if we start emulating directly without dropping
588  // into the interactive debugger. (To mimic pre-0.6.0 appearance.)
589  if (savedRunState == Running)
590  GetUI()->ShowDebugMessage("--------------------------------"
591  "-----------------------------------------------\n\n");
592  }
593 
594  SetRunState(savedRunState);
595 
596 
597  try {
598  GetUI()->MainLoop();
599  } catch (std::exception& ex) {
600  stringstream ss;
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";
607 
608  GetUI()->FatalError(ss.str());
609 
610  return 1;
611  }
612 
613  return 0;
614 }
615 
616 
617 const string& GXemul::GetEmulationFilename() const
618 {
619  return m_emulationFileName;
620 }
621 
622 
623 void GXemul::SetEmulationFilename(const string& filename)
624 {
625  m_emulationFileName = filename;
626 
627  GetUI()->UpdateUI();
628 }
629 
630 
632 {
633  return m_commandInterpreter;
634 }
635 
636 
637 uint64_t GXemul::GetStep() const
638 {
639  const StateVariable* step = GetRootComponent()->GetVariable("step");
640  if (step == NULL) {
641  std::cerr << "root component has no 'step' variable? aborting.\n";
642  throw std::exception();
643  }
644 
645  return step->ToInteger();
646 }
647 
648 
649 void GXemul::SetStep(uint64_t step)
650 {
651  StateVariable* stepVariable = GetRootComponent()->GetVariable("step");
652  if (stepVariable == NULL) {
653  std::cerr << "root component has no 'step' variable? aborting.\n";
654  throw std::exception();
655  }
656 
657  stepVariable->SetValue(step);
658 }
659 
660 
662 {
663  return m_ui;
664 }
665 
666 
668 {
669  return m_rootComponent;
670 }
671 
672 
674 {
675  return m_rootComponent;
676 }
677 
678 
680 {
681  if (newRootComponent.IsNULL()) {
682  std::cerr << "GXemul::SetRootComponent: NULL\n";
683  throw std::exception();
684  }
685 
686  RootComponent* rootComponent = newRootComponent->AsRootComponent();
687  if (rootComponent == NULL) {
688  std::cerr << "GXemul::SetRootComponent: not a RootComponent\n";
689  throw std::exception();
690  }
691 
692  rootComponent->SetOwner(this);
693 
694  m_rootComponent = newRootComponent;
695 
696  GetUI()->UpdateUI();
697 }
698 
699 
701 {
702  // 1. Reset all components in the tree.
703  GetRootComponent()->Reset();
704 
705  // 2. Run "on reset" commands. (These are usually commands to load
706  // binaries into CPUs.)
707  vector<string>::const_iterator it = m_onResetCommands.begin();
708  for (; it != m_onResetCommands.end(); ++it) {
709  string cmd = *it;
710  bool success = false;
711 
712  GetCommandInterpreter().RunCommand(cmd, &success);
713 
714  if (!GetQuietMode())
715  GetUI()->ShowDebugMessage("\n");
716 
717  if (!success) {
718  GetUI()->ShowDebugMessage("Failing on-reset command:\n"
719  " " + cmd + "\n");
720  return false;
721  }
722  }
723 
724  return true;
725 }
726 
727 
729 {
730  switch (GetRunState()) {
731  case SingleStepping:
732  case Running:
733  m_interrupting = true;
734  break;
735  default:
736  m_interrupting = false;
737  }
738 }
739 
740 
742 {
743  m_runState = newState;
744 
745  GetUI()->UpdateUI();
746 }
747 
748 
750 {
751  return m_runState;
752 }
753 
754 
756 {
757  switch (m_runState) {
758  case Paused:
759  return "Paused";
760  case SingleStepping:
761  return "Single-stepping";
762  case Running:
763  return "Running";
764  case Quitting:
765  return "Quitting";
766  }
767 
768  return "Unknown RunState";
769 }
770 
771 
773 {
774  return m_snapshottingEnabled;
775 }
776 
777 
779 {
780  if (enabled)
781  GetUI()->ShowDebugMessage("(Enabling "
782  "snapshotting/reverse execution support.)\n");
783 
784  m_snapshottingEnabled = enabled;
785 }
786 
787 
789 {
790  return m_quietMode;
791 }
792 
793 
794 void GXemul::SetQuietMode(bool quietMode)
795 {
796  m_quietMode = quietMode;
797 }
798 
799 
801 {
802  if (steps < 1)
803  steps = 1;
804 
805  m_nrOfSingleStepsLeft = steps;
806 }
807 
808 
809 bool GXemul::ModifyStep(int64_t oldStep, int64_t newStep)
810 {
811  if (!GetSnapshottingEnabled())
812  return false;
813 
814  if (oldStep == newStep)
815  return true;
816 
817  if (newStep < oldStep) {
818  // Run in reverse, by running forward from the most suitable
819  // snapshot.
820 
821  // TODO: Multiple snapshots!
822  refcount_ptr<Component> newRoot = m_snapshot->Clone();
823  SetRootComponent(newRoot);
824 
825  // GetStep will now return the step count for the new root.
826  int64_t nrOfStepsToRunFromSnapshot = newStep - GetStep();
827 
828  RunState oldRunState = GetRunState();
830 
831  Execute(nrOfStepsToRunFromSnapshot);
832 
833  SetRunState(oldRunState);
834  } else {
835  // Run forward, by setting a step breakpoint.
836  GetUI()->ShowDebugMessage("TODO: run forward by setting a step breakpoint!\n");
837  return false;
838  }
839 
840  return true;
841 }
842 
843 
844 void GXemul::TakeSnapshot()
845 {
846  // TODO: Multiple snapshots!
847 
848  if (m_snapshot.IsNULL()) {
849  stringstream ss;
850  ss << "(snapshot at step " << GetStep() << ")\n";
851  GetUI()->ShowDebugMessage(ss.str());
852 
853  m_snapshot = GetRootComponent()->Clone();
854  }
855 }
856 
857 
859 {
861  double frequency;
863 
865 };
866 
867 
868 // Gathers a list of components and their frequencies. (Only components that
869 // have a variable named "frequency" are executable.)
870 static void GetComponentsAndFrequencies(refcount_ptr<Component> component,
871  vector<ComponentAndFrequency>& componentsAndFrequencies)
872 {
873  const StateVariable* paused = component->GetVariable("paused");
874  const StateVariable* freq = component->GetVariable("frequency");
875  StateVariable* step = component->GetVariable("step");
876  if (freq != NULL && step != NULL &&
877  (paused == NULL || paused->ToInteger() == 0)) {
878  struct ComponentAndFrequency caf;
879 
880  caf.component = component;
881  caf.frequency = freq->ToDouble();
882  caf.step = step;
883  caf.nextTimeToExecute = 0;
884 
885  componentsAndFrequencies.push_back(caf);
886  }
887 
888  Components children = component->GetChildren();
889  for (size_t i=0; i<children.size(); ++i)
890  GetComponentsAndFrequencies(children[i], componentsAndFrequencies);
891 }
892 
893 
894 void GXemul::Execute(const int longestTotalRun)
895 {
896  vector<ComponentAndFrequency> componentsAndFrequencies;
897  GetComponentsAndFrequencies(GetRootComponent(), componentsAndFrequencies);
898 
899  if (componentsAndFrequencies.size() == 0) {
900  GetUI()->ShowDebugMessage("No executable components"
901  " found in the configuration.\n");
903  return;
904  }
905 
906  // Take an initial snapshot at step 0, if snapshotting is enabled:
907  if (m_snapshottingEnabled && GetStep() == 0)
908  TakeSnapshot();
909 
910  // Find the fastest component:
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;
917  }
918 
919  bool printEmptyLineBetweenSteps = false;
920 
921  switch (GetRunState()) {
922 
923  case SingleStepping:
924  if (m_nrOfSingleStepsLeft == 0)
925  m_nrOfSingleStepsLeft = 1;
926 
927  // Note that setting run state to something else, OR
928  // decreasing nr of single steps left to 0, will break the loop.
929  while (!m_interrupting && m_nrOfSingleStepsLeft > 0 && GetRunState() == SingleStepping) {
930  uint64_t step = GetStep();
931 
932  if (printEmptyLineBetweenSteps)
933  GetUI()->ShowDebugMessage("\n");
934  else
935  printEmptyLineBetweenSteps = true;
936 
937  stringstream ss;
938  ss << "step " << step << ": ";
939 
940  // Indent all debug output with message header "step X: ":
941  UI::SetIndentationMessageHelper indentationHelper(GetUI(), ss.str());
942 
943  ++ step;
944 
945  // Component X, using frequency fX, should have executed
946  // nstepsX = steps * fX / fastestFrequency nr of steps.
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));
950 
951  uint64_t stepsExecutedSoFar = componentsAndFrequencies[k].step->ToInteger();
952 
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();
958  }
959 
960  if (stepsExecutedSoFar < nsteps) {
961  ++ stepsExecutedSoFar;
962 
963  const refcount_ptr<Component> lightClone =
965 
966  // Execute one step...
967  int n = componentsAndFrequencies[k].component->Execute(this, 1);
968  if (n != 1) {
969  GetUI()->ShowDebugMessage("Single-stepping aborted.\n");
971  return;
972  }
973 
974  // ... and write back the number of executed steps:
975  componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar);
976 
977  // Now, let's compare the clone of the component tree
978  // before execution with what we have now.
979  stringstream changeMessages;
980  GetRootComponent()->DetectChanges(lightClone, changeMessages);
981  string msg = changeMessages.str();
982  if (msg.length() > 0)
983  GetUI()->ShowDebugMessage(msg);
984  }
985  }
986 
987  SetStep(step);
988  -- m_nrOfSingleStepsLeft;
989  }
990 
991  // Done. Let's pause again.
993  m_nrOfSingleStepsLeft = 0;
994  break;
995 
996  case Running:
997  {
998  uint64_t step = GetStep();
999  uint64_t startingStep = step;
1000 
1001  // TODO: sloppy vs cycle accuracy.
1002  if (GetRootComponent()->GetVariable("accuracy")->ToString() != "cycle") {
1003  std::cerr << "GXemul::Execute(): TODO: Only "
1004  "root.accuracy=\"cycle\" is currently supported\n";
1006  return;
1007  }
1008 
1009  // The following code is for cycle accurate emulation:
1010 
1011  while (step < startingStep + longestTotalRun) {
1012  if (m_interrupting || GetRunState() != Running)
1013  break;
1014 
1015  int toExecute = -1;
1016 
1017  if (componentsAndFrequencies.size() == 1) {
1018  toExecute = longestTotalRun;
1019  componentsAndFrequencies[0].nextTimeToExecute = step;
1020  } else {
1021  // First, calculate the next time step when each
1022  // component k will execute.
1023  //
1024  // For n = 0,1,2,3, ...
1025  // n * fastestFrequency / componentsAndFrequencies[k].frequency
1026  // are the steps at which the component executes
1027  // (when rounded UP! i.e. executing at step 4.2 means that it
1028  // did not execute at step 4, but will at step 5).
1029 
1030  for (size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1031  double q = (k == fastestComponentIndex ? 1.0
1032  : fastestFrequency / componentsAndFrequencies[k].frequency);
1033 
1034  double c = (componentsAndFrequencies[k].step->ToInteger()+1) * q;
1035  componentsAndFrequencies[k].nextTimeToExecute = (uint64_t) ceil(c) - 1;
1036  }
1037 
1038  // std::cerr << "step " << step << " debug:\n";
1039  for (size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1040  // std::cerr << " next step for component " <<
1041  // componentsAndFrequencies[k].component->GetVariable("name")->ToString()
1042  // << ": " << componentsAndFrequencies[k].nextTimeToExecute << "\n";
1043 
1044  int diff = componentsAndFrequencies[k].nextTimeToExecute -
1045  componentsAndFrequencies[fastestComponentIndex].nextTimeToExecute;
1046  if (k != fastestComponentIndex) {
1047  if (toExecute == -1 || diff < toExecute)
1048  toExecute = diff;
1049  }
1050  }
1051 
1052  if (toExecute < 1)
1053  toExecute = 1;
1054  }
1055 
1056  if (step + toExecute > startingStep + longestTotalRun)
1057  toExecute = startingStep + longestTotalRun - step;
1058 
1059  // std::cerr << " toExecute = " << toExecute << "\n";
1060 
1061  // Run the components.
1062  // If multiple components are to run at the same time (i.e.
1063  // same nextTimeToExecute), toExecute will be exactly 1.
1064  int maxExecuted = 0;
1065  bool abort = false;
1066  for (size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1067  if (step != componentsAndFrequencies[k].nextTimeToExecute)
1068  continue;
1069 
1070  // Execute the calculated number of steps...
1071  int n = componentsAndFrequencies[k].component->Execute(this, toExecute);
1072 
1073  // ... and write back the number of executed steps:
1074  uint64_t stepsExecutedSoFar = n +
1075  componentsAndFrequencies[k].step->ToInteger();
1076  componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar);
1077 
1078  if (k == fastestComponentIndex)
1079  maxExecuted = n;
1080 
1081  if (n != toExecute) {
1082  abort = true;
1083 
1084  if (n > toExecute) {
1085  std::cerr << "Internal error: " << n <<
1086  " steps executed, toExecute = " << toExecute << "\n";
1087  throw std::exception();
1088  }
1089 
1090  stringstream ss;
1091  ss << "only " << n << " steps of " << toExecute << " executed.";
1092  GetUI()->ShowDebugMessage(componentsAndFrequencies[k].component, ss.str());
1093  }
1094  }
1095 
1096  if (abort) {
1097  GetUI()->ShowDebugMessage("Continuous execution aborted.\n");
1099  }
1100 
1101  if (maxExecuted == 0 && GetRunState() == Running) {
1102  std::cerr << "maxExecuted=0. internal error\n";
1103  throw std::exception();
1104  }
1105 
1106  step += maxExecuted;
1107  SetStep(step);
1108  }
1109 
1110  // Output nr of steps (and speed) every second:
1111  struct timeval tvend;
1112  gettimeofday(&tvend, NULL);
1113 
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);
1117 
1118  if (secondsSinceLastOutput > 1.0 && (step - m_lastOutputStep) > 10000) {
1119  m_lastOutputTime = tvend;
1120 
1121  int64_t stepsPerSecond = (int64_t)
1122  ( (double)(step - m_lastOutputStep) / secondsSinceLastOutput );
1123  m_lastOutputStep = step;
1124 
1125  stringstream ss;
1126  ss << step << " steps";
1127  if (stepsPerSecond > 0)
1128  ss << " (" << stepsPerSecond << " steps/second)";
1129 
1130  GetUI()->ShowDebugMessage(ss.str());
1131  }
1132  }
1133  break;
1134 
1135  default:
1136  std::cerr << "GXemul::Execute() called without being in a"
1137  " running state. Internal error?\n";
1138  throw std::exception();
1139  }
1140 
1141  if (m_interrupting) {
1142  m_interrupting = false;
1144  }
1145 }
1146 
1147 
1148 /*****************************************************************************/
1149 
1150 #ifdef WITHUNITTESTS
1151 
1152 static void Test_Construction()
1153 {
1154  GXemul gxemul;
1155 }
1156 
1158 {
1159  UNITTEST(Test_Construction);
1160 
1161  // Note: Most execution tests are in DummyComponent.cc, because they
1162  // test component behavior. But they also test GXemul::Execute etc.
1163 }
1164 
1165 
1166 #endif
1167 
void SetRunState(RunState newState)
Sets the RunState.
Definition: GXemul.cc:741
void SetEmulationFilename(const string &filename)
Sets the current emulation setup&#39;s filename.
Definition: GXemul.cc:623
GXemul()
Creates a GXemul instance.
Definition: GXemul.cc:175
virtual void ShowDebugMessage(const string &msg)=0
Shows a debug message.
StateVariable * GetVariable(const string &name)
Gets a pointer to a state variable.
Definition: Component.cc:949
string GetRunStateAsString() const
Gets the current RunState as a string.
Definition: GXemul.cc:755
Dummy UI, which does not do anything.
Definition: NullUI.h:37
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.
Definition: GXemul.cc:749
bool Reset()
Resets the emulation.
Definition: GXemul.cc:700
bool GetQuietMode() const
Gets the current quiet mode setting.
Definition: GXemul.cc:788
void Interrupt()
Interrupts emulation.
Definition: GXemul.cc:728
const refcount_ptr< Component > LightClone() const
Makes a light clone of the component and all its children.
Definition: Component.cc:192
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.
Definition: RootComponent.h:57
virtual void UpdateUI()=0
Updates various UI elements.
uint64_t GetStep() const
Gets the current step of the emulation.
Definition: GXemul.cc:637
static void ListTemplates()
Dump a list to stdout with all available machine templates.
Definition: GXemul.cc:239
uint64_t nextTimeToExecute
Definition: GXemul.cc:864
Components & GetChildren()
Gets pointers to child components.
Definition: Component.cc:674
void SetSnapshottingEnabled(bool enabled)
Sets whether or not to use snapshots.
Definition: GXemul.cc:778
Text-terminal based User Interface.
Definition: ConsoleUI.h:39
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
virtual void Initialize()=0
Initializes the UI.
void SetNrOfSingleStepsInARow(uint64_t steps)
Sets the nr of single-steps to perform in a row.
Definition: GXemul.cc:800
An interactive command interpreter, which run Commands.
bool ModifyStep(int64_t oldStep, int64_t newStep)
Change step either forwards or backwards.
Definition: GXemul.cc:809
static string Version()
Returns the GXemul version string.
Definition: GXemul.cc:509
The main emulator class.
Definition: GXemul.h:54
#define UNITTESTS(class)
Helper for unit test case execution.
Definition: UnitTest.h:184
CommandInterpreter & GetCommandInterpreter()
Gets a reference to the CommandInterpreter.
Definition: GXemul.cc:631
#define new
Definition: debug_new.h:127
const string & GetEmulationFilename() const
Gets the current emulation setup&#39;s filename.
Definition: GXemul.cc:617
bool SetValue(const string &expression)
Set the variable&#39;s value, using a string expression.
double ToDouble() const
Returns the variable as a double value.
RunState
Definition: GXemul.h:57
StateVariable * step
Definition: GXemul.cc:862
static bool HasAttribute(const string &name, const string &attributeName)
Checks if a component has a specific attribute.
virtual RootComponent * AsRootComponent()
Returns the component&#39;s RootComponent interface.
Definition: Component.cc:353
A Component is a node in the configuration tree that makes up an emulation setup. ...
Definition: Component.h:62
static void DumpMachineAsHTML(const string &machineName)
Definition: GXemul.cc:266
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.
Definition: GXemul.cc:772
uint64_t ToInteger() const
Returns the variable as an unsignedinteger value.
StateVariables make up the persistent state of Component objects.
Definition: StateVariable.h:67
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.
Definition: GXemul.cc:192
#define COPYRIGHT_MSG
Definition: misc.h:46
virtual int MainLoop()=0
Runs the UI&#39;s main loop.
void SetRootComponent(refcount_ptr< Component > newRootComponent)
Sets the root component, discarding the previous one.
Definition: GXemul.cc:679
void InitUI()
Initializes the UI.
Definition: GXemul.cc:545
bool IsTemplateMachine(const string &templateName) const
Definition: GXemul.cc:204
refcount_ptr< Component > Clone() const
Clones the component and all its children.
Definition: Component.cc:76
refcount_ptr< Component > GetRootComponent()
Gets a pointer to the root configuration component.
Definition: GXemul.cc:667
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.
Definition: Component.cc:595
void Reset()
Resets the state of this component and all its children.
Definition: Component.cc:281
int Run()
Runs GXemul&#39;s main loop.
Definition: GXemul.cc:557
static void GenerateHTMLListOfComponents(bool machines)
Definition: GXemul.cc:279
virtual void ShowStartupBanner()=0
Shows a startup banner.
UI * GetUI()
Gets a pointer to the GXemul instance&#39; active UI.
Definition: GXemul.cc:661
void SetOwner(GXemul *owner)
Base class for a User Interface.
Definition: UI.h:40
void SetQuietMode(bool quietMode)
Sets whether or not to run in quiet mode.
Definition: GXemul.cc:794
vector< refcount_ptr< Component > > Components
Definition: Component.h:43
void Execute(const int longestTotalRun=100000)
Run the emulation for "a while".
Definition: GXemul.cc:894
string GenerateTreeDump(const string &branchTemplate, bool htmlLinksForClassNames=false, string prefixForComponentUrls="") const
Generates an ASCII tree dump of a component tree.
Definition: Component.cc:459
bool ParseFilenames(string templateMachine, int filenameCount, char *filenames[])
Parses command line arguments (file names).
Definition: GXemul.cc:427
#define UNITTEST(functionname)
Helper for unit test case execution.
Definition: UnitTest.h:217
bool IsNULL() const
Checks whether or not an object is referenced by the reference counted pointer.
Definition: refcount_ptr.h:216
#define SECONDARY_MSG
Definition: misc.h:54
refcount_ptr< Component > component
Definition: GXemul.cc:860

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13