GXemul: Description of the framework

Back to the index.



Introduction:

GXemul 0.6.0 is a complete redesign, compared to the 0.4.x series. This chapter of the documentation describes the core concepts of the new framework.

(For various reasons, most of the old emulation modes are still included in the source code, and may be run by users, but the intention is to either rewrite them to use the new framework, or remove them.)

The new framework is written in C++ (whereas previous versions were written in C).


Components:

The most important concept in the GXemul framework is that of the component. A component can have sub-components (children) and a parent, so the components make up a configuration tree:

Component classes are registered in a component registry.

Each component in the emulation setup has a path, e.g. root.machine1.mainbus0.cpu0 for the CPU in the right-most machine in the example above. Often, shorter paths can be used, such as machine1 instead of root.machine1, if there is no ambiguity.

Each component has state, which is a collection of variables. For e.g. a CPU component, the state is usually a set of registers. Each component also has a set of methods which can be executed. A CPU may disassemble instructions using its unassemble method:

 
GXemul> root
  root
  \-- machine0  [testmips]
      \-- mainbus0
          |-- ram0  (32 MB at offset 0)
          |-- rom0  (16 MB at offset 0x1fc00000)
          \-- cpu0  (5KE, 100 MHz)

  accuracy = cycle
  step     = 0
GXemul> cpu0.unassemble
<f>
0xffffffff800100f8 <- 27bdffd0   addiu   sp,sp,-48    
0xffffffff800100fc    3c03cccc   lui     v1,0xcccc    
0xffffffff80010100    3c028888   lui     v0,0x8888    
0xffffffff80010104    8f8b8008   lw      t3,-32760(gp)
0xffffffff80010108    8f8a8004   lw      t2,-32764(gp)
0xffffffff8001010c    afb60028   sw      s6,40(sp)    
0xffffffff80010110    afb50024   sw      s5,36(sp)    
...

When single-stepping, all state change is displayed. (In the old framework, it was up to individual device/component implementations to print debug messages.)

 
GXemul> step
step 0: cpu0: <f>
              0xffffffff800100f8    27bdffd0   addiu   sp,sp,-48
        => cpu0.pc: 0xffffffff800100f8 -> 0xffffffff800100fc
        => cpu0.sp: 0xffffffffa0007f00 -> 0xffffffffa0007ed0
GXemul> 
step 1: cpu0: 0xffffffff800100fc    3c03cccc   lui   v1,0xcccc
        => cpu0.pc: 0xffffffff800100fc -> 0xffffffff80010100
        => cpu0.v1: 0 -> 0xffffffffcccc0000
GXemul> 

The example above may not be that interesting, but imagine that the CPU reads from a device which has a zero-on-read status register. Then the output may look something like this: (this is a made-up example, for now)

 
GXemul> step
step 2: cpu0: 0xffffffff800101f4    12345678   lw   t3,256(a1)
        => cpu0.pc: 0xffffffff800101f4 -> 0xffffffff800101f8
        => cpu0.t3: 0 -> 0x2200
        => intcontroller.status: 0x2200 -> 0
GXemul> 

Components that have a frequency are executed in steps. Those that do not have a frequency only do things if triggered by some other means (i.e. another component). The components' relative frequencies determine how many steps they will run at a time. For example, if we have component A running at 100 MHz, and component B running at 1 MHz, then in 100 steps A will be executing 100 cycles and B only 1. The GXemul framework makes sure that the exact sequence of cycles is the same nomatter if the user is single-stepping, or running the simulation continuously.

The frequency mentioned above does not have anything at all to do with how fast a particular host executes the simulation. The frequencies are only relative to each other.

Is the new framework cycle-accurate? Both yes and no. The framework itself aims to be step/cycle accurate, but it is of course up to the implementation of individual components to also be cycle accurate. For example, the CPU components that are available out-of-the-box in GXemul do not try to simulate out-of-order execution, or pipe-line stalls, or other effects that happen in a real processor, so even though the aim is that the implementation should be cycle accurate, it does not simulate any existing real-world processor in a cycle-accurate manner.

(Is it theoretically possible to implement pipe-lined and/or out-of-order CPU models for GXemul's new framework? Maybe. But that has not been done.)


Machine templates:

Although the framework is generic enough to simulate/emulate many kinds of components, the focus is on emulating components found in electronic computers, such as processors, RAM, caches, graphics cards, etc. In most cases, these components are naturally contained in a machine.

Before GXemul 0.6.0, machines were a special type of entity in the emulator, which held one or more CPUs of a particular architecture, e.g. MIPS. In fact, the entire machine was of that architecture. The machine also had hardcoded RAM. While this worked well, it was not generic enough to support some cases that occur in the real world:

The 0.6.0 framework thus has a somewhat generalized view of what a machine is. Machines are simply templates for how components are configured. When adding such a template machine to the configuration tree, the result is a complete tree of components:

	GXemul> add testmips 
	GXemul> root 
	  root
	  \-- machine0  [testmips]
	      \-- mainbus0
	          |-- ram0  (32 MB at offset 0)
	          |-- rom0  (16 MB at offset 0x1fc00000)
	          \-- cpu0  (5KE, 100 MHz)
Here, a testmips machine template was added to the root component. The name of the machine in the component tree is root.machine0. The tree dump shows that it was created using the testmips template.

The same machine configuration can be set up by hand as well:

	GXemul> add machine root 
	GXemul> add mainbus machine0 
	GXemul> add ram mainbus0 
	GXemul> ram0.memoryMappedSize = 0x2000000 
	GXemul> add mips_cpu mainbus0 
	GXemul> root 
	  root
	  \-- machine0
	      \-- mainbus0
	          |-- ram0  (32 MB at offset 0)
	          \-- cpu0  (5KE, 100 MHz)

(Omitting rom0 for brevity.)