You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When porting a DML 1.2 file to DML 1.4, most differences can be taken
8
-
care of by the automatic conversion script `port-dml`. The
9
-
script relies on the `dmlc` compiler to produce information on
10
-
what changes need to be applied.
8
+
care of by the automatic conversion script `port-dml`.
11
9
12
-
The easiest way to invoke `port-dml` is through a wrapper
13
-
script `port-dml-module`. The script ports all devices in one
14
-
SIMICS module, and all imported files it depends on. The scripts works by
15
-
invoking `make` and `port-dml`, and prints how they are invoked, which
16
-
is instructive for understanding how to use `port-dml`
17
-
standalone.
18
-
19
-
The `port-dml-module` script works well for converting most DML
20
-
devices, but has some limitations when it comes to common code that is
21
-
shared between many devices. In particular, if some parts of common
22
-
code is unused, e.g. if a provided template is never instantiated,
23
-
then it may skip some conversions. For this reason, it can be better
24
-
to use `port-dml` directly for common code.
10
+
The porting process consists of two phases: An *analysis phase*, where the
11
+
`dmlc` compiler is run to produce a *tag file*, which describes the required
12
+
changes; this is followed by a *conversion phase* where the `port-dml`
13
+
script reads the tag file and applies changes.
25
14
15
+
The easiest way to perform conversion is through the wrapper script
16
+
`port-dml-module`. This script automatizes the porting process by first running an
17
+
analysis step using `make` to build a module, and then running a conversion phase by
18
+
applying `port-dml` on the DML files that were compiled. The script relies on
19
+
rather crude heuristics which often may be
20
+
incorrect; for this reason, the script also prints exactly what lower level
21
+
commands it invokes. This allows each step to be individually rerun manually
22
+
with tweaked settings.
26
23
24
+
The `port-dml` script can also be used directly without `port-dml-module`; this
25
+
mode of operation has a steeper learning curve but provides greater control
26
+
which can be advantageous when porting a large code base.
27
27
28
28
## Using the port-dml script
29
29
In order to port a DML 1.2 file to DML 1.4, first pass the <code>-P
@@ -54,7 +54,7 @@ If you build your device from a Simics project, you can use the variable
54
54
be set to the absolute path of a file; `make` will pass that in the
55
55
-P flag to `dmlc`. Note that if you want to re-run an analysis,
56
56
then you need to first run <code>make clean-<em>module</em></code> to force
57
-
DMLC to re-run on all devices in the SIMICS module.
57
+
DMLC to re-run on all devices in the Simics module.
58
58
59
59
If parts of the device source code is unused, e.g. if a template is
60
60
never instantiated within the device, then DMLC can not perform a full
@@ -75,3 +75,99 @@ tags](changes-auto.html) and apply the change manually.
75
75
76
76
</div>
77
77
78
+
## Porting common code still used from DML 1.2 code
79
+
80
+
When porting a large code base to DML 1.4, you likely want to work
81
+
incrementally, porting some devices at a time. It can then happen that some of
82
+
your newly ported 1.4 files share common code with devices that are still in DML 1.2.
83
+
84
+
It is not allowed to import a DML 1.2 file from a DML 1.4 device, but a DML 1.2 device may import a DML 1.4 file with some caveats. Thus, any code common between DML 1.2 and 1.4 must be ported to 1.4 before any device can be converted.
85
+
There are two possible strategies for this: Either convert the common file in place,
86
+
or duplicate it into separate 1.2 and 1.4 versions.
87
+
88
+
### Keep a separate DML 1.4 copy
89
+
90
+
After letting conversion tools convert `foo.dml` to DML 1.4, you can rename the
91
+
converted file into `foo-dml14.dml`, and restore the original 1.2 version as
92
+
`foo-dml12.dml`, and finally create a trampoline file `foo.dml` containing:
93
+
94
+
```
95
+
dml 1.4;
96
+
#if (dml_1_2) {
97
+
import "foo-dml12.dml";
98
+
} #else {
99
+
import "foo-dml14.dml";
100
+
}
101
+
```
102
+
103
+
This way, existing `import "foo.dml";` statements from both DML 1.2 and 1.4 devices
104
+
will continue to work.
105
+
106
+
The apparent downside of this approach is that the logic of the common code is
107
+
duplicated across two files, which is a problem if the DML 1.2 variant is expected
108
+
to be maintained over a longer period of time. However, if all uses from DML 1.2 of
109
+
the common code are expected to be ported within a short migration period,
110
+
then this is likely the preferred approach.
111
+
112
+
After the last DML 1.2 use of the common code has been ported, `foo-dml12.dml` can be removed, and `foo-dml14.dml` can be moved back to `foo.dml`, overwriting the trampoline.
113
+
114
+
Note that the `#if` trick in the `foo.dml` trampoline above utilizes an
A common file can be ported to DML 1.4 and still be useful from DML 1.2, with a
122
+
number of caveats. For instance, devices often implement functionality by
123
+
overriding standard methods, and some methods have been renamed between DML 1.2
124
+
and 1.4. For instance, an override of the `read_access` register method in a
125
+
DML 1.2 device roughly corresponds to a `read_register` override in a DML 1.4
126
+
device, and an attribute with `parameter allocate_type = "uint64"` in DML 1.2
127
+
corresponds to an event with `is uint64_attr` in DML 1.4. Much of this can be
128
+
taken care of by the `dml12-compatibility.dml` layer: A shared DML 1.4 file can
129
+
say `import "dml12-compatibility.dml";`. This does nothing when imported from a
130
+
DML 1.4, but when imported from DML 1.2, it provides some glue that ties DML
131
+
1.4 constructs to the DML 1.2 API. For instance, it defines templates such that
132
+
`is uint64_attr` in the DML 1.4 file will expand to define `allocate_type` when
133
+
imported from DML 1.2. This file also provides some templates for explicit
134
+
instantiation. In particular, the `dml12_compat_read_register` template can be
135
+
instantiated on a DML 1.4 register that overrides the `read_register` method;
136
+
this has no effect in a DML 1.4 device, but in a DML 1.2 device it overrides
137
+
the DML 1.2 method `read_access` to call the provided override. Similarly,
138
+
the `dml12_compat_write_register` template can be used on registers that override
139
+
`write_register`; `dml12_compat_read_field` and
140
+
`dml12_compat_write_field` can be used on field that override the `read_field` or `write_field` method; and `dml12_compat_io_memory_access` can be used on banks that override the `io_memory_access` method.
141
+
142
+
Sometimes, the facilities in `dml12-compatibility.dml` are not sufficient for
143
+
full DML 1.2 compatibility. For instance, suppose you want to use the `shared` annotation on a `read` method when writing the DML 1.4 version of a template. There are fundamental limitations in DML 1.2 that prevent such overrides. This can be overcome with an `#if (dml_1_2)` block on the top level:
144
+
```
145
+
dml 1.4;
146
+
147
+
#if (dml_1_2) {
148
+
template read_twelve {
149
+
method read() -> (uint64) {
150
+
log info: "read";
151
+
return 12;
152
+
}
153
+
}
154
+
} #else {
155
+
template read_twelve is read {
156
+
shared method read() -> (uint64) {
157
+
log info: "read";
158
+
return 12;
159
+
}
160
+
}
161
+
}
162
+
```
163
+
This is somewhat similar to the `foo-dml14.dml` trampoline approach discussed above, with
164
+
the difference that it can be applied selectively only on problematic parts of the
165
+
file.
166
+
167
+
If the flag `--compat` is passed to the `port-dml` script, then the script will
168
+
automatically detect some cases where such `#if` clauses are needed for
169
+
compatibility, and insert them automatically. The script will also add an
170
+
`dml12-compatibility.dml` import. The `--compat` flag can also be passed to the
171
+
`port-dml-module` script; in this case, the script will pass on `--compat` to
172
+
`port-dml` when converting DML files that don't reside in the directory of any
0 commit comments