Skip to content

Supporting non Simics simulators

Erik Carstensen edited this page Mar 16, 2022 · 2 revisions

DML currently only supports writing models for the Simics simulator.

This page discusses how additional simulator back-ends would affect the language.

Properties of DML

A DML model is fundamentally event driven. Any call into a DML device should return without advancing simulated time. Also, a DML device is a serial domain; concurrent access from two threads cannot happen. While there is a small set of exceptions to this rule, one of DML's core strengths is that we make it easy to develop event driven devices. This makes all simulation state explicit and visible, which avoids bugs and makes checkpointing cheap and easy. This contrasts with SystemC, which encourages a programming model where much of the device logic is run in threads that often survive over simulated time.

When writing a back-end for another simulator, we need to embrace this property of DML, and make sure DML models can be integrated in the simulator without extending DML with e.g. constructs to create threads.

Simulator specific bindings

We strive to avoid requiring the use of Simics specific types and API functions in DML code, but exceptions exist. Generally, #if

Logging

The concept of log types and log groups in DML correspond directly to log types and log groups in Simics. Other simulators may have other logging mechanisms

Attributes

The get and set methods rely on the highly Simics specific type attr_value_t. This does not make sense for other simulators, where the signatures of get and set should be different. Currently, the best way to address this would be

  • only use attributes where needed (e.g. configuration that needs documentation, or pseudo-attributes for inspection); use saved variables for state.
  • use standard templates (uint64_attr etc) when possible; these should be implemented with the same semantics on all simulators
  • when standard templates are insufficient, then write your own attribute templates, where the set/get implementation is surrounded with a simulator-dependent #if.

Interfaces and implements

The definitions of interfaces is highly simulator specific, so interconnects need separate definitions for different simulators. An agnostic device model will need to wrap implement objects in simulator-dependent #ifs. Normally, the implementation of an interface method should be a shim layer that calls to a functional implementation on port level that can be shared across simulators. Likewise, interface objects will likely be conditional, and the parent connect object will provide a shim layer of simulator-agnostic methods that forwards calls depending on simulator back-end.

When compiling for Simics, it is permitted to have implement objects directly in a device or subdevice objects. We can allow other simulator back-ends to forbid this.

Banks

In Simics, banks implement the io_memory or transaction interface, and have a bank-level method io_memory_access or transaction_access. Another simulator will have a different interface, and a different method as entry point. Agnostic models that override this entry point will need to surround the override with a simulator-dependent #if.

Memory transactions that contain additional metadata, like access control, should be handled by extracting the metadata in an override of transaction_access or equivalent, convert that into a model-specific simulator-agnostic format, and pass that in the aux argument of the default implementation. This allows registers and fields to access the metadata in a simulator-agnostic (albeit model-specific) fashion.

dev.obj

Today, dev.obj is defined as having the type conf_object_t.

When adding a different simulator back-end, we will likely preserve the parameter named dev.obj, but introduce a new type, e.g. device_instance_t, which will have no simulator-agnostic properties, but will be typedef:ed to conf_object_t when compiling for Simics.

Likewise, the obj parameter of port, bank and subobject objects will remain. When compiling for Simics, these will continue to have the same type as dev.obj, but in other simulators it may make sense to have separate types (e.g., Simics 5 did not have separate objects for ports). We can consider defining separate types for port_instance_t, bank_instance_t subobject_instance_t, similar to device_instance_t. It is permitted for other simulator back-ends to specify these as opaque bogus types, and use NULL as the value of obj parameters.

Imports

In a typical Simics device, many import statements mirror the structure of Simics header files import "simics/devs/signal.dml";.

In an agnostic device, such imports must be moved inside #if blocks.

map_target template

The map_target template in utility.dml is mostly simulator agnostic, but contains some Simics-specific elements, such as the issue method. We will likely make map_target a Simics specific template, and extract a super-template that lacks the issue method and is simulator-agnostic.