GXemul.cc Source File

Back to the index.

GXemul.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2019 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://gavare.se/gxemul/">http://gavare.se/gxemul/</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 <b><i>still being developed</i></b>.
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 
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  " <td><b><u>Description:</u></b>&nbsp;&nbsp;</td>\n"
293  " <td><b><u>Comments:</u></b>&nbsp;&nbsp;</td>\n"
294  " <td><b><u>Contributors:</u></b>&nbsp;&nbsp;</td>\n"
295  "</tr>\n";
296 
297  bool everyOther = false;
298  vector<string> names = ComponentFactory::GetAllComponentNames(false);
299  for (size_t i=0; i<names.size(); ++i) {
300  const string& componentName = names[i];
301  string treeDump;
302 
303  refcount_ptr<Component> creatable =
304  ComponentFactory::CreateComponent(componentName);
305  if (creatable.IsNULL())
306  continue;
307 
308  bool isTemplateMachine = !ComponentFactory::GetAttribute(
309  componentName, "machine").empty() &&
311  componentName, "template").empty();
312 
313  if (machines) {
314  if (!isTemplateMachine)
315  continue;
316  } else {
317  // Other components: Don't include template machines.
318  if (isTemplateMachine)
319  continue;
320  }
321 
322  // Include an ASCII tree dump for template components that
323  // have children:
325  componentName, "template").empty()) {
326  refcount_ptr<Component> component =
327  ComponentFactory::CreateComponent(componentName);
328 
329  if (!component.IsNULL() &&
330  component->GetChildren().size() != 0)
331  treeDump = "<pre>" +
332  component->GenerateTreeDump("", true)
333  + "</pre>";
334  }
335 
336  // Some distance between table entries:
337  std::cout <<
338  "<tr>\n"
339  " <td></td>"
340  "</tr>\n";
341 
342  std::cout <<
343  "<tr bgcolor=" <<
344  (everyOther? "#f2f2f2" : "#e4e4e4") << ">\n";
345 
346  // Include a href link to a "full html page" for a component,
347  // if it exists:
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());
354 
355  if (documentationComponentFile.is_open())
356  std::cout <<
357  " <td valign=top>"
358  "<a href=\"components/component_" <<
359  componentName
360  << ".html\"><tt>" << componentName <<
361  "</tt></a></td>\n";
362  else if (documentationMachineFile.is_open())
363  std::cout <<
364  " <td valign=top>"
365  "<a href=\"machines/machine_" <<
366  componentName
367  << ".html\"><tt>" << componentName <<
368  "</tt></a></td>\n";
369  else
370  std::cout <<
371  " <td valign=top><tt>" << componentName
372  << "</tt></td>\n";
373 
374  if (machines) {
375  // Include an img and a href link to a screenshot for a component,
376  // if it exists:
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());
383 
384  std::cout << " <td valign=top align=center><tt>";
385 
386  if (screenshotLargeFile.is_open())
387  std::cout << "<a href=machines/machine_" <<
388  componentName << ".png>";
389 
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)";
395 
396  if (screenshotLargeFile.is_open())
397  std::cout << "</a>";
398 
399  std::cout << "</tt></td>\n";
400  }
401 
402  std::cout <<
403  " <td valign=top>" << ComponentFactory::GetAttribute(
404  componentName, "description") <<
405  treeDump << "</td>\n"
406  " <td valign=top>" << ComponentFactory::GetAttribute(
407  componentName, "comments") << "</td>\n"
408  " <td valign=top>" << ComponentFactory::GetAttribute(
409  componentName, "contributors") << "</td>\n"
410  "</tr>\n";
411 
412  everyOther = !everyOther;
413  }
414 
415  std::cout << "</table><p>\n";
416 }
417 
418 
419 bool GXemul::ParseFilenames(string templateMachine, int filenameCount, char *filenames[])
420 {
421  bool optionsEnoughToStartRunning = false;
422 
423  if (templateMachine != "") {
424  if (CreateEmulationFromTemplateMachine(templateMachine)) {
425  // A template is now being used.
426  } else {
427  std::cerr << "Failed to create configuration from "
428  "template: " << templateMachine << "\n" <<
429  "Aborting." << "\n";
430  return false;
431  }
432  }
433 
434  // 1. If a machine template has been selected, then treat the following
435  // arguments as arguments to the 'add' command.
436  //
437  // 2. Otherwise, treat the argument as a configuration file.
438 
439  if (filenameCount > 0) {
440  if (templateMachine != "") {
441  // Machine template.
442  while (filenameCount > 0) {
443  stringstream cmd;
444 
445  // TODO: Different syntax!
446  // Use "add" with different syntax here...
447 
448  cmd << "load " << filenames[0]
449  << " root.machine0.mainbus0.cpu0";
450 
451  // TODO: Get rid of this onReset mechanism!
452  m_onResetCommands.push_back(cmd.str());
453 
454  filenameCount --;
455  filenames ++;
456  }
457 
458  optionsEnoughToStartRunning = true;
459  } else {
460  // Config file.
461  if (filenameCount == 1) {
462  string configfileName = filenames[0];
463  optionsEnoughToStartRunning = true;
464 
465  string cmd = "load " + configfileName;
466  m_onResetCommands.push_back(cmd);
467  } else {
468  std::cerr << "More than one configfile name "
469  "supplied on the command line?" << "\n" <<
470  "Aborting." << "\n";
471  return false;
472  }
473  }
474  }
475 
476  if (optionsEnoughToStartRunning) {
477  return true;
478  } else {
479  if (templateMachine != "") {
480  if (GetRunState() == Paused)
481  return true;
482 
483  std::cerr <<
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"
487  "\n"
488  "You can also use the -V option to start in paused mode, and load binaries\n"
489  "interactively.\n"
490  "\n"
491  "(Run gxemul -h for more help on command line options.)\n";
492  return false;
493  }
494 
495  PrintUsage();
496  return false;
497  }
498 }
499 
500 
502 {
503  stringstream ss;
504  ss << "GXemul "
505 #ifdef VERSION
506  << VERSION
507 #else
508  << "(unknown version)"
509 #endif
510  << " " COPYRIGHT_MSG"\n" SECONDARY_MSG;
511 
512  return ss.str();
513 }
514 
515 
516 void GXemul::PrintUsage() const
517 {
518  std::cout << Version() << "\n";
519 
520  std::cout << "Insufficient command line arguments given to"
521  " start an emulation. You have\n"
522  "the following alternatives:\n" <<
523  "\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" <<
532  "\n" <<
533  "Run gxemul -h for help on command line options.\n\n";
534 }
535 
536 
538 {
539  // Default to the console UI:
540  m_ui = new ConsoleUI(this);
541 
542  // Once a GUI has been implemented, this is the
543  // place to call its constructor. TODO
544 
545  GetUI()->Initialize();
546 }
547 
548 
550 {
551  // Not really running yet:
552  RunState savedRunState = GetRunState();
554 
555  if (!GetQuietMode()) {
557 
558  // Dump (a suitable part of) the configuration tree at startup.
559  const Component* component = GetRootComponent();
560  if (component->GetChildren().size() > 0) {
561  while (true) {
562  int nChildren = component->GetChildren().size();
563  if (nChildren == 0 || nChildren > 1)
564  break;
565 
566  component = component->GetChildren()[0];
567  }
568 
569  GetUI()->ShowDebugMessage(component->GenerateTreeDump("") + "\n");
570  }
571  }
572 
573  if (!Reset()) {
574  GetUI()->ShowDebugMessage("Aborting.\n");
575  return 1;
576  }
577 
578  if (!GetQuietMode()) {
579  // A separator line, if we start emulating directly without dropping
580  // into the interactive debugger. (To mimic pre-0.6.0 appearance.)
581  if (savedRunState == Running)
582  GetUI()->ShowDebugMessage("--------------------------------"
583  "-----------------------------------------------\n\n");
584  }
585 
586  SetRunState(savedRunState);
587 
588 
589  try {
590  GetUI()->MainLoop();
591  } catch (std::exception& ex) {
592  stringstream ss;
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";
599 
600  GetUI()->FatalError(ss.str());
601 
602  return 1;
603  }
604 
605  return 0;
606 }
607 
608 
609 const string& GXemul::GetEmulationFilename() const
610 {
611  return m_emulationFileName;
612 }
613 
614 
615 void GXemul::SetEmulationFilename(const string& filename)
616 {
617  m_emulationFileName = filename;
618 
619  GetUI()->UpdateUI();
620 }
621 
622 
624 {
625  return m_commandInterpreter;
626 }
627 
628 
629 uint64_t GXemul::GetStep() const
630 {
631  const StateVariable* step = GetRootComponent()->GetVariable("step");
632  if (step == NULL) {
633  std::cerr << "root component has no 'step' variable? aborting.\n";
634  throw std::exception();
635  }
636 
637  return step->ToInteger();
638 }
639 
640 
641 void GXemul::SetStep(uint64_t step)
642 {
643  StateVariable* stepVariable = GetRootComponent()->GetVariable("step");
644  if (stepVariable == NULL) {
645  std::cerr << "root component has no 'step' variable? aborting.\n";
646  throw std::exception();
647  }
648 
649  stepVariable->SetValue(step);
650 }
651 
652 
654 {
655  return m_ui;
656 }
657 
658 
660 {
661  return m_rootComponent;
662 }
663 
664 
666 {
667  return m_rootComponent;
668 }
669 
670 
672 {
673  if (newRootComponent.IsNULL()) {
674  std::cerr << "GXemul::SetRootComponent: NULL\n";
675  throw std::exception();
676  }
677 
678  RootComponent* rootComponent = newRootComponent->AsRootComponent();
679  if (rootComponent == NULL) {
680  std::cerr << "GXemul::SetRootComponent: not a RootComponent\n";
681  throw std::exception();
682  }
683 
684  rootComponent->SetOwner(this);
685 
686  m_rootComponent = newRootComponent;
687 
688  GetUI()->UpdateUI();
689 }
690 
691 
693 {
694  // 1. Reset all components in the tree.
695  GetRootComponent()->Reset();
696 
697  // 2. Run "on reset" commands. (These are usually commands to load
698  // binaries into CPUs.)
699  vector<string>::const_iterator it = m_onResetCommands.begin();
700  for (; it != m_onResetCommands.end(); ++it) {
701  string cmd = *it;
702  bool success = false;
703 
704  GetCommandInterpreter().RunCommand(cmd, &success);
705 
706  if (!GetQuietMode())
707  GetUI()->ShowDebugMessage("\n");
708 
709  if (!success) {
710  GetUI()->ShowDebugMessage("Failing on-reset command:\n"
711  " " + cmd + "\n");
712  return false;
713  }
714  }
715 
716  return true;
717 }
718 
719 
721 {
722  switch (GetRunState()) {
723  case SingleStepping:
724  case Running:
725  m_interrupting = true;
726  break;
727  default:
728  m_interrupting = false;
729  }
730 }
731 
732 
734 {
735  m_runState = newState;
736 
737  GetUI()->UpdateUI();
738 }
739 
740 
742 {
743  return m_runState;
744 }
745 
746 
748 {
749  switch (m_runState) {
750  case Paused:
751  return "Paused";
752  case SingleStepping:
753  return "Single-stepping";
754  case Running:
755  return "Running";
756  case Quitting:
757  return "Quitting";
758  }
759 
760  return "Unknown RunState";
761 }
762 
763 
765 {
766  return m_snapshottingEnabled;
767 }
768 
769 
771 {
772  if (enabled)
773  GetUI()->ShowDebugMessage("(Enabling "
774  "snapshotting/reverse execution support.)\n");
775 
776  m_snapshottingEnabled = enabled;
777 }
778 
779 
781 {
782  return m_quietMode;
783 }
784 
785 
786 void GXemul::SetQuietMode(bool quietMode)
787 {
788  m_quietMode = quietMode;
789 }
790 
791 
793 {
794  if (steps < 1)
795  steps = 1;
796 
797  m_nrOfSingleStepsLeft = steps;
798 }
799 
800 
801 bool GXemul::ModifyStep(int64_t oldStep, int64_t newStep)
802 {
803  if (!GetSnapshottingEnabled())
804  return false;
805 
806  if (oldStep == newStep)
807  return true;
808 
809  if (newStep < oldStep) {
810  // Run in reverse, by running forward from the most suitable
811  // snapshot.
812 
813  // TODO: Multiple snapshots!
814  refcount_ptr<Component> newRoot = m_snapshot->Clone();
815  SetRootComponent(newRoot);
816 
817  // GetStep will now return the step count for the new root.
818  int64_t nrOfStepsToRunFromSnapshot = newStep - GetStep();
819 
820  RunState oldRunState = GetRunState();
822 
823  Execute(nrOfStepsToRunFromSnapshot);
824 
825  SetRunState(oldRunState);
826  } else {
827  // Run forward, by setting a step breakpoint.
828  GetUI()->ShowDebugMessage("TODO: run forward by setting a step breakpoint!\n");
829  return false;
830  }
831 
832  return true;
833 }
834 
835 
836 void GXemul::TakeSnapshot()
837 {
838  // TODO: Multiple snapshots!
839 
840  if (m_snapshot.IsNULL()) {
841  stringstream ss;
842  ss << "(snapshot at step " << GetStep() << ")\n";
843  GetUI()->ShowDebugMessage(ss.str());
844 
845  m_snapshot = GetRootComponent()->Clone();
846  }
847 }
848 
849 
851 {
853  double frequency;
855 
857 };
858 
859 
860 // Gathers a list of components and their frequencies. (Only components that
861 // have a variable named "frequency" are executable.)
862 static void GetComponentsAndFrequencies(refcount_ptr<Component> component,
863  vector<ComponentAndFrequency>& componentsAndFrequencies)
864 {
865  const StateVariable* paused = component->GetVariable("paused");
866  const StateVariable* freq = component->GetVariable("frequency");
867  StateVariable* step = component->GetVariable("step");
868  if (freq != NULL && step != NULL &&
869  (paused == NULL || paused->ToInteger() == 0)) {
870  struct ComponentAndFrequency caf;
871 
872  caf.component = component;
873  caf.frequency = freq->ToDouble();
874  caf.step = step;
875  caf.nextTimeToExecute = 0;
876 
877  componentsAndFrequencies.push_back(caf);
878  }
879 
880  Components children = component->GetChildren();
881  for (size_t i=0; i<children.size(); ++i)
882  GetComponentsAndFrequencies(children[i], componentsAndFrequencies);
883 }
884 
885 
886 void GXemul::Execute(const int longestTotalRun)
887 {
888  vector<ComponentAndFrequency> componentsAndFrequencies;
889  GetComponentsAndFrequencies(GetRootComponent(), componentsAndFrequencies);
890 
891  if (componentsAndFrequencies.size() == 0) {
892  GetUI()->ShowDebugMessage("No executable components"
893  " found in the configuration.\n");
895  return;
896  }
897 
898  // Take an initial snapshot at step 0, if snapshotting is enabled:
899  if (m_snapshottingEnabled && GetStep() == 0)
900  TakeSnapshot();
901 
902  // Find the fastest component:
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;
909  }
910 
911  bool printEmptyLineBetweenSteps = false;
912 
913  switch (GetRunState()) {
914 
915  case SingleStepping:
916  if (m_nrOfSingleStepsLeft == 0)
917  m_nrOfSingleStepsLeft = 1;
918 
919  // Note that setting run state to something else, OR
920  // decreasing nr of single steps left to 0, will break the loop.
921  while (!m_interrupting && m_nrOfSingleStepsLeft > 0 && GetRunState() == SingleStepping) {
922  uint64_t step = GetStep();
923 
924  if (printEmptyLineBetweenSteps)
925  GetUI()->ShowDebugMessage("\n");
926  else
927  printEmptyLineBetweenSteps = true;
928 
929  stringstream ss;
930  ss << "step " << step << ": ";
931 
932  // Indent all debug output with message header "step X: ":
933  UI::SetIndentationMessageHelper indentationHelper(GetUI(), ss.str());
934 
935  ++ step;
936 
937  // Component X, using frequency fX, should have executed
938  // nstepsX = steps * fX / fastestFrequency nr of steps.
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));
942 
943  uint64_t stepsExecutedSoFar = componentsAndFrequencies[k].step->ToInteger();
944 
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();
950  }
951 
952  if (stepsExecutedSoFar < nsteps) {
953  ++ stepsExecutedSoFar;
954 
955  const refcount_ptr<Component> lightClone =
957 
958  // Execute one step...
959  int n = componentsAndFrequencies[k].component->Execute(this, 1);
960  if (n != 1) {
961  GetUI()->ShowDebugMessage("Single-stepping aborted.\n");
963  return;
964  }
965 
966  // ... and write back the number of executed steps:
967  componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar);
968 
969  // Now, let's compare the clone of the component tree
970  // before execution with what we have now.
971  stringstream changeMessages;
972  GetRootComponent()->DetectChanges(lightClone, changeMessages);
973  string msg = changeMessages.str();
974  if (msg.length() > 0)
975  GetUI()->ShowDebugMessage(msg);
976  }
977  }
978 
979  SetStep(step);
980  -- m_nrOfSingleStepsLeft;
981  }
982 
983  // Done. Let's pause again.
985  m_nrOfSingleStepsLeft = 0;
986  break;
987 
988  case Running:
989  {
990  uint64_t step = GetStep();
991  uint64_t startingStep = step;
992 
993  // TODO: sloppy vs cycle accuracy.
994  if (GetRootComponent()->GetVariable("accuracy")->ToString() != "cycle") {
995  std::cerr << "GXemul::Execute(): TODO: Only "
996  "root.accuracy=\"cycle\" is currently supported\n";
998  return;
999  }
1000 
1001  // The following code is for cycle accurate emulation:
1002 
1003  while (step < startingStep + longestTotalRun) {
1004  if (m_interrupting || GetRunState() != Running)
1005  break;
1006 
1007  int toExecute = -1;
1008 
1009  if (componentsAndFrequencies.size() == 1) {
1010  toExecute = longestTotalRun;
1011  componentsAndFrequencies[0].nextTimeToExecute = step;
1012  } else {
1013  // First, calculate the next time step when each
1014  // component k will execute.
1015  //
1016  // For n = 0,1,2,3, ...
1017  // n * fastestFrequency / componentsAndFrequencies[k].frequency
1018  // are the steps at which the component executes
1019  // (when rounded UP! i.e. executing at step 4.2 means that it
1020  // did not execute at step 4, but will at step 5).
1021 
1022  for (size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1023  double q = (k == fastestComponentIndex ? 1.0
1024  : fastestFrequency / componentsAndFrequencies[k].frequency);
1025 
1026  double c = (componentsAndFrequencies[k].step->ToInteger()+1) * q;
1027  componentsAndFrequencies[k].nextTimeToExecute = (uint64_t) ceil(c) - 1;
1028  }
1029 
1030  // std::cerr << "step " << step << " debug:\n";
1031  for (size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1032  // std::cerr << " next step for component " <<
1033  // componentsAndFrequencies[k].component->GetVariable("name")->ToString()
1034  // << ": " << componentsAndFrequencies[k].nextTimeToExecute << "\n";
1035 
1036  int diff = componentsAndFrequencies[k].nextTimeToExecute -
1037  componentsAndFrequencies[fastestComponentIndex].nextTimeToExecute;
1038  if (k != fastestComponentIndex) {
1039  if (toExecute == -1 || diff < toExecute)
1040  toExecute = diff;
1041  }
1042  }
1043 
1044  if (toExecute < 1)
1045  toExecute = 1;
1046  }
1047 
1048  if (step + toExecute > startingStep + longestTotalRun)
1049  toExecute = startingStep + longestTotalRun - step;
1050 
1051  // std::cerr << " toExecute = " << toExecute << "\n";
1052 
1053  // Run the components.
1054  // If multiple components are to run at the same time (i.e.
1055  // same nextTimeToExecute), toExecute will be exactly 1.
1056  int maxExecuted = 0;
1057  bool abort = false;
1058  for (size_t k=0; k<componentsAndFrequencies.size(); ++k) {
1059  if (step != componentsAndFrequencies[k].nextTimeToExecute)
1060  continue;
1061 
1062  // Execute the calculated number of steps...
1063  int n = componentsAndFrequencies[k].component->Execute(this, toExecute);
1064 
1065  // ... and write back the number of executed steps:
1066  uint64_t stepsExecutedSoFar = n +
1067  componentsAndFrequencies[k].step->ToInteger();
1068  componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar);
1069 
1070  if (k == fastestComponentIndex)
1071  maxExecuted = n;
1072 
1073  if (n != toExecute) {
1074  abort = true;
1075 
1076  if (n > toExecute) {
1077  std::cerr << "Internal error: " << n <<
1078  " steps executed, toExecute = " << toExecute << "\n";
1079  throw std::exception();
1080  }
1081 
1082  stringstream ss;
1083  ss << "only " << n << " steps of " << toExecute << " executed.";
1084  GetUI()->ShowDebugMessage(componentsAndFrequencies[k].component, ss.str());
1085  }
1086  }
1087 
1088  if (abort) {
1089  GetUI()->ShowDebugMessage("Continuous execution aborted.\n");
1091  }
1092 
1093  if (maxExecuted == 0 && GetRunState() == Running) {
1094  std::cerr << "maxExecuted=0. internal error\n";
1095  throw std::exception();
1096  }
1097 
1098  step += maxExecuted;
1099  SetStep(step);
1100  }
1101 
1102  // Output nr of steps (and speed) every second:
1103  struct timeval tvend;
1104  gettimeofday(&tvend, NULL);
1105 
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);
1109 
1110  if (secondsSinceLastOutput > 1.0 && (step - m_lastOutputStep) > 10000) {
1111  m_lastOutputTime = tvend;
1112 
1113  int64_t stepsPerSecond = (int64_t)
1114  ( (double)(step - m_lastOutputStep) / secondsSinceLastOutput );
1115  m_lastOutputStep = step;
1116 
1117  stringstream ss;
1118  ss << step << " steps";
1119  if (stepsPerSecond > 0)
1120  ss << " (" << stepsPerSecond << " steps/second)";
1121 
1122  GetUI()->ShowDebugMessage(ss.str());
1123  }
1124  }
1125  break;
1126 
1127  default:
1128  std::cerr << "GXemul::Execute() called without being in a"
1129  " running state. Internal error?\n";
1130  throw std::exception();
1131  }
1132 
1133  if (m_interrupting) {
1134  m_interrupting = false;
1136  }
1137 }
1138 
1139 
1140 /*****************************************************************************/
1141 
1142 #ifdef WITHUNITTESTS
1143 
1144 static void Test_Construction()
1145 {
1146  GXemul gxemul;
1147 }
1148 
1150 {
1151  UNITTEST(Test_Construction);
1152 
1153  // Note: Most execution tests are in DummyComponent.cc, because they
1154  // test component behavior. But they also test GXemul::Execute etc.
1155 }
1156 
1157 
1158 #endif
1159 
Component::GetChildren
Components & GetChildren()
Gets pointers to child components.
Definition: Component.cc:674
GXemul::SetSnapshottingEnabled
void SetSnapshottingEnabled(bool enabled)
Sets whether or not to use snapshots.
Definition: GXemul.cc:770
UI::UpdateUI
virtual void UpdateUI()=0
Updates various UI elements.
refcount_ptr::IsNULL
bool IsNULL() const
Checks whether or not an object is referenced by the reference counted pointer.
Definition: refcount_ptr.h:218
Component::GenerateTreeDump
string GenerateTreeDump(const string &branchTemplate, bool htmlLinksForClassNames=false, string prefixForComponentUrls="") const
Generates an ASCII tree dump of a component tree.
Definition: Component.cc:459
ConsoleUI.h
GXemul::Running
@ Running
Definition: GXemul.h:61
Component::AddChild
void AddChild(refcount_ptr< Component > childComponent, size_t insertPosition=(size_t) -1)
Adds a reference to a child component.
Definition: Component.cc:595
ComponentFactory.h
UI::MainLoop
virtual int MainLoop()=0
Runs the UI's main loop.
GXemul::ParseFilenames
bool ParseFilenames(string templateMachine, int filenameCount, char *filenames[])
Parses command line arguments (file names).
Definition: GXemul.cc:419
GXemul::GetSnapshottingEnabled
bool GetSnapshottingEnabled() const
Checks whether snapshots are currently enabled or not.
Definition: GXemul.cc:764
GXemul
The main emulator class.
Definition: GXemul.h:55
GXemul::SetNrOfSingleStepsInARow
void SetNrOfSingleStepsInARow(uint64_t steps)
Sets the nr of single-steps to perform in a row.
Definition: GXemul.cc:792
GXemul::ClearEmulation
void ClearEmulation()
Discards the current emulation, and starts anew with just an empty root component.
Definition: GXemul.cc:192
NullUI.h
UI::SetIndentationMessageHelper
Definition: UI.h:45
GXemul::GetCommandInterpreter
CommandInterpreter & GetCommandInterpreter()
Gets a reference to the CommandInterpreter.
Definition: GXemul.cc:623
GXemul::Quitting
@ Quitting
Definition: GXemul.h:62
StateVariable
StateVariables make up the persistent state of Component objects.
Definition: StateVariable.h:69
ComponentAndFrequency::step
StateVariable * step
Definition: GXemul.cc:854
refcount_ptr< Component >
StateVariable::ToInteger
uint64_t ToInteger() const
Returns the variable as an unsignedinteger value.
Definition: StateVariable.cc:280
ComponentFactory::GetAllComponentNames
static vector< string > GetAllComponentNames(bool onlyTemplates)
Returns a vector of all available component names.
Definition: ComponentFactory.cc:212
UNITTESTS
#define UNITTESTS(class)
Helper for unit test case execution.
Definition: UnitTest.h:184
GXemul::Run
int Run()
Runs GXemul's main loop.
Definition: GXemul.cc:549
GXemul::InitUI
void InitUI()
Initializes the UI.
Definition: GXemul.cc:537
GXemul::IsTemplateMachine
bool IsTemplateMachine(const string &templateName) const
Definition: GXemul.cc:204
cmd
Definition: debugger_cmds.cc:1189
NullUI
Dummy UI, which does not do anything.
Definition: NullUI.h:39
ComponentAndFrequency::component
refcount_ptr< Component > component
Definition: GXemul.cc:852
GXemul::GetRootComponent
refcount_ptr< Component > GetRootComponent()
Gets a pointer to the root configuration component.
Definition: GXemul.cc:659
RootComponent.h
UNITTEST
#define UNITTEST(functionname)
Helper for unit test case execution.
Definition: UnitTest.h:217
UI
Base class for a User Interface.
Definition: UI.h:42
StateVariable::ToDouble
double ToDouble() const
Returns the variable as a double value.
Definition: StateVariable.cc:321
GXemul::SetRunState
void SetRunState(RunState newState)
Sets the RunState.
Definition: GXemul.cc:733
GXemul::SetEmulationFilename
void SetEmulationFilename(const string &filename)
Sets the current emulation setup's filename.
Definition: GXemul.cc:615
UI::ShowDebugMessage
virtual void ShowDebugMessage(const string &msg)=0
Shows a debug message.
Component::DetectChanges
void DetectChanges(const refcount_ptr< Component > &oldClone, ostream &changeMessages) const
Compare an older clone to the current tree, to find changes.
Definition: Component.cc:198
machine
Definition: machine.h:97
UI::FatalError
virtual void FatalError(const string &msg)=0
Shows a fatal error message.
GXemul::GetRunStateAsString
string GetRunStateAsString() const
Gets the current RunState as a string.
Definition: GXemul.cc:747
GXemul::Execute
void Execute(const int longestTotalRun=100000)
Run the emulation for "a while".
Definition: GXemul.cc:886
ConsoleUI
Text-terminal based User Interface.
Definition: ConsoleUI.h:41
ComponentAndFrequency::nextTimeToExecute
uint64_t nextTimeToExecute
Definition: GXemul.cc:856
GXemul::ModifyStep
bool ModifyStep(int64_t oldStep, int64_t newStep)
Change step either forwards or backwards.
Definition: GXemul.cc:801
GXemul::GXemul
GXemul()
Creates a GXemul instance.
Definition: GXemul.cc:175
StateVariable::SetValue
bool SetValue(const string &expression)
Set the variable's value, using a string expression.
Definition: StateVariable.cc:412
UnitTest.h
Component::AsRootComponent
virtual RootComponent * AsRootComponent()
Returns the component's RootComponent interface.
Definition: Component.cc:353
ComponentFactory::CreateComponent
static refcount_ptr< Component > CreateComponent(const string &componentNameAndOptionalArgs, GXemul *gxemul=NULL)
Creates a component given a short component name.
Definition: ComponentFactory.cc:87
COPYRIGHT_MSG
#define COPYRIGHT_MSG
Definition: misc.h:46
GXemul::Reset
bool Reset()
Resets the emulation.
Definition: GXemul.cc:692
CommandInterpreter::RunCommand
bool RunCommand(const string &command, bool *pSuccess=NULL)
Runs a command, given as a string.
Definition: CommandInterpreter.cc:958
GXemul::ListTemplates
static void ListTemplates()
Dump a list to stdout with all available machine templates.
Definition: GXemul.cc:239
UI::ShowStartupBanner
virtual void ShowStartupBanner()=0
Shows a startup banner.
GXemul::GetRunState
RunState GetRunState() const
Gets the current RunState.
Definition: GXemul.cc:741
ComponentFactory::GetAttribute
static string GetAttribute(const string &name, const string &attributeName)
Gets a specific attribute value for a component.
Definition: ComponentFactory.cc:184
SECONDARY_MSG
#define SECONDARY_MSG
Definition: misc.h:54
GXemul::SetQuietMode
void SetQuietMode(bool quietMode)
Sets whether or not to run in quiet mode.
Definition: GXemul.cc:786
CommandInterpreter
An interactive command interpreter, which run Commands.
Definition: CommandInterpreter.h:50
RootComponent
A Component which is the default root node in the configuration.
Definition: RootComponent.h:60
GXemul::GenerateHTMLListOfComponents
static void GenerateHTMLListOfComponents(bool machines)
Definition: GXemul.cc:279
GXemul::GetUI
UI * GetUI()
Gets a pointer to the GXemul instance' active UI.
Definition: GXemul.cc:653
GXemul::Paused
@ Paused
Definition: GXemul.h:59
Component
A Component is a node in the configuration tree that makes up an emulation setup.
Definition: Component.h:64
GXemul::SingleStepping
@ SingleStepping
Definition: GXemul.h:60
GXemul::GetStep
uint64_t GetStep() const
Gets the current step of the emulation.
Definition: GXemul.cc:629
Component::LightClone
const refcount_ptr< Component > LightClone() const
Makes a light clone of the component and all its children.
Definition: Component.cc:192
GXemul::DumpMachineAsHTML
static void DumpMachineAsHTML(const string &machineName)
Definition: GXemul.cc:266
Components
vector< refcount_ptr< Component > > Components
Definition: Component.h:43
Component::GetVariable
StateVariable * GetVariable(const string &name)
Gets a pointer to a state variable.
Definition: Component.cc:949
ComponentFactory::HasAttribute
static bool HasAttribute(const string &name, const string &attributeName)
Checks if a component has a specific attribute.
Definition: ComponentFactory.cc:205
GXemul::GetEmulationFilename
const string & GetEmulationFilename() const
Gets the current emulation setup's filename.
Definition: GXemul.cc:609
new
#define new
Definition: debug_new.h:127
UI::Initialize
virtual void Initialize()=0
Initializes the UI.
Component::Clone
refcount_ptr< Component > Clone() const
Clones the component and all its children.
Definition: Component.cc:76
GXemul::RunState
RunState
Definition: GXemul.h:58
ComponentAndFrequency::frequency
double frequency
Definition: GXemul.cc:853
GXemul::Version
static string Version()
Returns the GXemul version string.
Definition: GXemul.cc:501
GXemul::SetRootComponent
void SetRootComponent(refcount_ptr< Component > newRootComponent)
Sets the root component, discarding the previous one.
Definition: GXemul.cc:671
GXemul::GetQuietMode
bool GetQuietMode() const
Gets the current quiet mode setting.
Definition: GXemul.cc:780
GXemul::Interrupt
void Interrupt()
Interrupts emulation.
Definition: GXemul.cc:720
GXemul.h
ComponentAndFrequency
Definition: GXemul.cc:851
Component::Reset
void Reset()
Resets the state of this component and all its children.
Definition: Component.cc:281
RootComponent::SetOwner
void SetOwner(GXemul *owner)
Definition: RootComponent.cc:55

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