The Object System

TEMU provides a light weight object system that all built in models are written in. The object system exist to provide a C API in which it is possible to define classes and create objects that support reflection / introspection. Conceptually this is similar to GOBJECT, but the TEMU object system is more tailored for the needs of an emulator and a lot simpler. There is also some correspondence to SMP2, but the interfaces are plain C which is needed in order to interface to the object system from the emulator core.

The key features of the object system are the following:

  • Standardized way for defining classes and models in plain C.

  • Ability to introspect models, even though they are written in C or C++.

  • Automatic save and restore of state

  • Access to object properties by name using scripts

  • Standard way for defining interfaces (such as serial port interfaces etc)

  • Easy to wrap in order to be able to write models in other languages (e.g. Python)

The object system accomplishes this by providing the following:

Class

Blueprint for objects, classes are created, registering properties and interfaces. Classes have names starting with a letter or underscore followed by any number of letters, digits and underscores.

Object

An instantiated class. Normally the TEMU object system takes care of instantiation, however externally created objects can also be registered with the object system (in order to have scripts build the object graph with external classes). Objects have names with the same naming rules as classes, except objects support object name separators with the minus character '-'. This is used to ensure objects inside components have unique global names.

Property

A named data member of a class (i.e. a field or instance variable). A property is accessible by name (e.g. using strings) and will be automatically serialized by the object system if needed. The system supports all basic fixed with integer types (from <stdint.h>), pointer sized integers (i.e. uintptr_t and intptr_t), floats, doubles and references to objects and interfaces. Property names start with a letter or underscore, followed by any number of digits, letters or underscores. Property names can be nested using a period '.' as separator.

Pseudo Property

A named data member of a class without directly backing storage. Pseudo properties are accessible by name, and will be automatically serialized by the object system if they have a set and get function associated. Pseudo properties are useful for custom check pointing logic (e.g. writing out raw data to a file) or for using external classes, or non standard layout types in the object system.

Interface

A collection of function pointers allowing classes to provide different behavior for a standardized interface. Similar to an interface in Java or an abstract class in C++. In TEMU this is implemented as structs of function pointers that are registered to a class.

Port

A property and interface with an inverse relationship. Connecting an interface property in the port to an interface in another object will automatically introduce a back link from the destination object to the original source object. If a port has been added combining property a and interface b in the source object, and property c and interface d in the destination object. Connecting a→d will introduce c→b automatically.

When setting up a simulator based on TEMU, the general approach is the following:

  1. Create all the needed classes (e.g. load plugins)

  2. Create all objects for the system (e.g. CPUs, ROM, RAM, MMIO models etc)

  3. Connect objects (build the object graph)

  4. Load target software in to RAM or ROM

  5. Run the emulator

It is possible to query a class or object for properties and interfaces at runtime by specifying the property or interface name as a string.

For example there is a CPU interface that is common to all CPU models, this contain procedures for accessing registers. In addition, there is a SPARC interface which provides SPARC specific procedures (e.g. accessing windowed registers).

The most important core interfaces are the following:

  • MemAccessIface

  • MemoryIface

  • CpuIface

An interface can be queried using the temu_getInterface function. This function takes an object pointer as first argument and the interface name as second. For example, temu_getInterface(cpu, "MemAccessIface") will return the pointer to the memory access interface structure provided by the CPU object (or NULL if not available). You need to cast the interface pointer to the correct type. The type mappings are provided in the model manuals.

Object Graph and Interface Properties

The objects created in the object system are connected together by linking interface properties to actual interfaces. That is if an object A has an interface property, this interface property can refer to an interface implemented by some other object B. Under the hood this is a pointer pair with an object pointer and an interface pointer, the interface pointer is a pointer to the struct of function pointers implementing the relevant interface.

Diagram

Object System Functions

This section lists the most important object system functions. The full documentation is in Doxygen based documentation, this is just a quick way to have an overview.

Table 1. TEMU Object System Functions
Function Description

temu_addInterface()

Add interface to class

temu_addPort()

Bind a property / interface pair as a port

temu_addProperty()

Add property to class

temu_addPseudoProperty()

Add pseudo property to class

temu_checkSanity()

Look for unconnected interface properties

temu_classForName()

Get a class object by name

temu_classForObject()

Get the class object for an object

temu_connect()

Connect an interface property to an interface

temu_createObject()

Create a new object from an internal class

temu_deserialiseJSON()

Restore the state of the emulator

temu_disposeObject()

Delete object

temu_getInterface()

Get interface pointer by name

temu_getValue()

Get property without side-effects

temu_loadPlugin()

Load a TEMU plugin

temu_nameForObject()

Get the name for the given object

temu_objectForName()

Get a named object

temu_objsysClear()

Delete all objects and classes

temu_readValue()

Get property by calling the read function

temu_registerClass()

Create a new class

temu_serialiseJSON()

Save the state of the emulator

temu_setTimeSource()

Set time source for object

temu_setValue()

Set property without side-effects

temu_writeValue()

Set property by calling the write function

Properties

Properties are registered fields in a class. They are associated with the type and not with the object instance themselves. Properties have names, types and read- and write functions. Properties are saved in snapshots. Properties are associated with an offset in the model type, meaning they have backing storage.

Property names are legal if they start with a letter or underscore followed by any number of letters, digits or underscores. Properties support nesting via dots as well.

Pseudo Properties

Pseudo properties are properties without explicit backing storage, instead they are registered with not only the read and write functions, but also optional set and get functions. Set and get functions serves the same effect as accessing the raw data in a struct, and are used for snapshots. From the user interface point of view, pseudo properties behave the same as normal properties.

Interfaces

Interfaces are structs populated with function pointers. You can query an interface by name for a given object using temu_getInterface().

Interface names are legal if they start with a letter or underscore followed by any number of letters, digits or underscores.

Ports

A very common case is where a source model is connected to a destination model, and the destination model must have a back link to the source model often to a different interface. For example, the IRQ interfaces have an upstream variant IrqIface and a downstream variant IrqClientIface. The upstream variant is used to raise interrupts, while the downstream interface have functions to acknowledge interrupts. To avoid the case where the user forgets to insert the backward link, it is possible to pair interface properties and interfaces together using temu_addPort().

When a port has been added to a class, the connect function will automatically insert the back links if connecting a port in a source object a port in the destination object.

In the interrupt controller case, assume that the class A has an interface reference property irqController and an interface IrqIface and class B an interface reference property named irq and an interface IrqClientIface. Then, the user would do the following:

  temu_addPort(A, "irqController", "IrqIface", "downstream IRQ port");
  temu_addPort(B, "irq", "IrqClientIface", "upstream IRQ port");

  // Now normally without ports two connects would be needed
  //temu_connect(a, "irqController", b, "IrqClientIface");
  //temu_connect(b, "irq", a, "IrqIface");

  // With ports, only one connect is needed, it will automatically
  // add the reverse link. so, we get both of the links on one
  // connect:
  //   a.irqConroller -> b:IrqClientIface
  //   b.irq -> a:IrqIface
  temu_connect(a, "irqController", b, "IrqClientIface");

To list available ports in a class use the class-info command.