B Provisional language features D Changes from DML 1.2 to DML 1.4
Device Modeling Language 1.4 Reference Manual  / 

C Managing deprecated language features

As the DML language evolves, we sometimes need to change the language in incompatible ways, which requires DML users to migrate their code. This appendix describes the mechanisms we provide to make this migration process smooth for users with large DML code bases.

In DML, breaking changes can come in many forms. Breaking changes in the form of removed or renamed symbols in libraries are rather easy to manage, since they give clear compile errors that often are straightforward to fix. A slightly harder type of breaking change is when some language construct or API function adjusts its semantics; this can make the model behave differently without signalling error messages. A third kind of change is when DML changes how compiled models appear in Simics, typically to adjust changes in the Simics API. Such changes add another dimension because they typically affect the end-users of the DML models, rather than the authors of the models. Thus, as an author of a model you may need to synchronize your migration of such features with your end-users, to ease their transition to a new major version.

C.1 Simics API versions

The simplest deprecation mechanism is Simics API versions: Each breaking change is associated with a Simics API version, and each Simics version supports a number of such API versions. When moving to a new Simics major version, support for the oldest API version is dropped which means the corresponding changes become mandatory. Since Simics is currently the primary distribution channel for DML, this scheme is used for DML features as well.

This scheme allows users with a large code base to smoothly migrate from one Simics major version, N, to the next, N+1:

C.2 Breaking changes

DML supports a more fine-grained mechanism for managing breaking changes, where each individual change in a new API version can be enabled individually, without enabling the full API version. This has the following uses:

C.3 Controlling deprecation on the DML command-line

DMLC provides a command-line flag --api-version to specify the API version to be used for a model. When building with the CMake based build system in Simics, this is controlled by the SIMICS_API parameter of the simics_add_module function.

DMLC also provides a flag --breaking-change=TAG, which enables the breaking change represented by TAG. The valid tags are listed in the next section.

C.4 List of breaking changes

Each breaking change has an associated tag, which is passed to the --breaking-change flag. Each tag also comes with a top-level DML parameter, which DML code can use to check if a change is enabled or not. A section with title foo-bar corresponds to the DMLC flag --breaking-change=foo-bar, and when that flag is passed, the global parameter _breaking_change_foo_bar to true.

Each breaking change is also implicitly enabled when compiling with a Simics API version above a certain threshold. The breaking changes under the section for API n are useful when migrating to API n+1.

C.4.1 Changes for migrating from --simics-api=6

These changes are enabled automatically when compiling using Simics API 7 or newer. With older Simics API versions, the changes can be enabled individually by passing --breaking-change=TAG to the dmlc compiler.

dml12-disable-inline-constants

When using inline in DML 1.2, constant arguments passed in typed parameters were inlined as constants, which had some unintuitive semantic implications. In DML 1.4, constants are only inlined in parameters declared using inline as quasi-type. When this change is enabled, DML 1.2 only inlines constants in untyped method parameters, causing its behaviour to closer resemble DML 1.4.

dml12-modern-int

Up to Simics 6, DML 1.2 used legacy integer semantics, translating most operations directly into C without compensating for DML-specifics like the support for odd-sized uintNN types. This can sometimes have unexpected consequences. When this change is enabled, modern DML 1.4 integer semantics is used.

The most immediate effect of enabling this change is that DMLC will report errors on statements like assert 0; and while (1) { ... }, which need to change into assert false; and while (true) { ... }, respectively. Other effects include:

dml12-remove-goto

Up to Simics 6, the goto statement was allowed in DML 1.2. The statement is not allowed in DML 1.4. When this change is enabled, goto is disallowed also in DML 1.2. Most goto-based control structures can be rewritten using throw and catch blocks.

dml12-remove-misc-quirks

DML 1.2 had several quirks that inadvertedly caused it to permit some strange patterns. In DML 1.4 this was cleaned up and some patterns were disallowed. When this change is enabled, the DML 1.4 behaviour applies also in DML 1.2.

Examples of forbidden patterns include:

enable-WLOGMIXUP

Up to Simics 6, the warning WLOGMIXUP was suppressed by default to avoid overwhelming users, as the faulty pattern it reports was common. When this change is enabled, WLOGMIXUP is reported by default. Code using the faulty pattern should be fixed before enabling this change.

shared-logs-locally

Up to Simics 6, log statements inside shared methods always logged on the device object instead of the nearest enclosing configuration object. This was a bug that many scripts relied on. When this change is enabled, logs inside shared methods behave consistently with non-shared methods and log on the nearest enclosing configuration object.

transaction-by-default

Up to Simics 6, the top-level parameter use_io_memory defaulted to true, causing bank objects to implement io_memory instead of transaction by default. When this change is enabled, banks will implement transaction by default, and use_io_memory must be set explicitly to true if the old behavior is desired.

C.4.2 Changes for migrating from --simics-api=7

These changes are enabled automatically when compiling using Simics API 8 or newer. With older Simics API versions, the changes can be enabled individually by passing --breaking-change=TAG to the dmlc compiler.

forbid-broken-conditional-is

Up to Simics 7, a bug prevented DMLC from reporting an error when instantiating a nonexistent template within an #if block. For example, the following would compile without errors:

#if (true) {
group g {
    // should be an error, but silently ignored when this
    // feature is enabled
    is nonexisting_template;
}
}

This change causes DMLC to report an error on such code.

forbid-broken-unused-types

Up to Simics 7, a bug prevented DMLC from reporting certain errors on unused unused extern-declared types. For example, the following would compile without errors:

extern typedef struct {
undefined_type_t member;
} never_used_t;

This change causes DMLC to report an error on such code.

forbid-function-in-extern-struct

Up to Simics 7, a bug allowed omitting the * in function pointer members of extern typedef struct declarations. For example, the following would compile without errors:

extern typedef struct {
void m(conf_object_t *);
} my_interface_t;

This change causes DMLC to report an error on such code. To fix it, use the standard C form:

extern typedef struct {
void (*m)(conf_object_t *);
} my_interface_t;
forbid-warning-statement

Up to Simics 7, the _warning statement was allowed, though rarely useful. When this change is enabled, _warning statements are disallowed.

modern-attributes

Up to Simics 7, attributes were registered using the legacy SIM_register_typed_attribute API, which supported the dictionary type (“D” in type strings). When this change is enabled, attributes are registered using the modern SIM_register_attribute family, and the dictionary type becomes unsupported. Models using dictionary attributes must migrate to another representation, such as a list of two-element lists. E.g., a dict from integers to strings can be represented as an attribute of type [[is]*] instead of D. The outer list is created using SIM_alloc_attr_list instead of SIM_alloc_attr_dict, and items are added using SIM_set_attr_list_item(&outer, i, SIM_make_attr_list(2, key, value)) rather than SIM_attr_dict_set_item(&outer, i, key, value).

range-check-method-indices

Up to Simics 7, methods defined under object arrays did not validate that indices used when calling the method were within bounds. When this change is enabled, indices are implicitly range checked. If enabling this change causes crashes, then that definitely signifies a bug in your model; a bug that would very likely result in memory corruption if the assertion were not to be made.

remove-port-proxy-attrs

In Simics 5, configuration attributes for connect, attribute and register objects inside banks and ports were registered on the device object, named like bankname_attrname.

When this change is enabled, attributes are only registered on the bank or port object itself. When the change is not yet enabled, ports and banks are also redundantly exposed through a proxy attribute on the device object.

When enabling this change, you can expect that some code that accesses some attributes directly will have to be updated. For instance, if your device has a bank regs with a register R, then

your_dev.regs_R = 4711

will give an error, and can be changed into:

your_dev.bank.regs.R = 4711

Proxy attributes are only ever created for constructs that were permitted in Simics 5. For instance, attributes under banks inside groups will not get a proxy attribute even when this change is not enabled.

remove-port-proxy-ifaces

Version 5 and earlier of Simics relied on interface ports (as registered by the SIM_register_port_interface API function) for exposing the interfaces of ports and banks. In newer versions of Simics, interfaces are instead exposed on separate configuration objects.

When this change is enabled, ports and banks will only expose interfaces through the dedicated port object. When this change is not yet enabled, ports and banks are also redundantly exposed through an old-style interface port for compatibility.

When enabling this change, you can expect that initialization of connection attributes of other objects have to be updated. For instance, if your device has a port named p, then

other_dev.target = [your_dev, "p"]

will give an error, and can be changed into:

other_dev.target = your_dev.port.p

Interface ports are only ever created for constructs that were permitted in Simics 5. For instance, interfaces in banks inside groups will not get an interface port even when this change is not enabled.

require-version-statement

Up to Simics 7, the version specification statement (dml 1.4;) at the start of each file was optional, and dml 1.3; was permitted as a deprecated alias for dml 1.4;. When this change is enabled, the version statement becomes mandatory, and dml 1.3; is no longer accepted.

restrict-log-levels

Up to Simics 7, log levels for “warning”, “error”, and “critical” logs could be any integer between 1 and 5, even though it is only meaningful to provide 1 as the primary level and 5 as the subsequent level. When this change is enabled, the primary log level must be 1, and if the subsequent level is provided it must be 5; any other values will be rejected.

strict-typechecking

Up to Simics 7, DMLC’s type checking was very lenient compared to GCC, especially for method overrides and uses of extern macros. When this change is enabled, type checking becomes more strict.

The most common type of errors triggered by enabling this change are due to discrepencies between pointer types. In particular, implicitly discarding const-qualification of a pointer’s base type will never be tolerated, and void pointers are only considered equivalent with any other pointer type in the same contexts as C.

Novel type errors from uses of C macros exposed to DML through extern declarations can often be resolved by changing the signature of the extern declaration to more accurately reflect the macro’s effective type.

vect-needs-provisional

Up to Simics 7, the vect syntax was permitted without enabling the simics_util_vect provisional feature, issuing only a warning in DML 1.4. When this change is enabled, the vect syntax is forbidden unless the provisional feature is explicitly enabled.

B Provisional language features D Changes from DML 1.2 to DML 1.4