volatile struct definition for peripheral control registers
Josh Holtrop
jholtrop at gmail.com
Mon Dec 2 19:10:22 UTC 2024
I'm working on an embedded project writing some device drivers to
access peripheral control registers as MMIO addresses. Due to D's
lack of a `volatile` keyword, I'm trying to come up with a way to
define these peripheral control register structures in a way that
doesn't require the user of the structure to have to remember to
call `volatileStore()` or `volatileLoad()` for each register
access separately and I want the interface to be as clean as
possible.
In C I would have just declared the entire structure to be
`volatile` since the entire thing lives in MMIO address range,
and I suppose I'm trying to achieve something close to that...
# Attempt #1
Declare a `Volatile(T)` struct template:
```d
module myproj.volatile;
import core.volatile;
struct Volatile(T)
{
T v;
T get()
{
return volatileLoad(&v);
}
void opAssign(T v)
{
volatileStore(&this.v, v);
}
}
```
Use as:
```d
import myproj.volatile;
struct S
{
Volatile!uint reg;
Volatile!uint reg2;
struct
{
Volatile!uint subreg;
};
}
void vtest()
{
S * s = cast(S *)0xDEADBEEF;
while (s.reg.get == 0)
{
s.subreg = 1;
}
}
```
This works but requires that ugly .get call rather than just
accessing it directly.
# Attempt #2
```d
module myproj.volatile;
public import core.volatile;
template volatile_field(string type, string name)
{
mixin("private "~type~" v_"~name~";");
mixin("public @property "~type~" "~name~"() { return
volatileLoad(&v_"~name~"); }");
mixin("public @property void "~name~"("~type~" v) {
volatileStore(&v_"~name~", v); }");
}
template volatile_ubyte(string name)
{
mixin volatile_field!("ubyte", name);
}
template volatile_ushort(string name)
{
mixin volatile_field!("ushort", name);
}
template volatile_uint(string name)
{
mixin volatile_field!("uint", name);
}
template volatile_ulong(string name)
{
mixin volatile_field!("ulong", name);
}
```
```d
import myproj.volatile;
struct S
{
mixin volatile_uint!"reg";
mixin volatile_uint!"reg2";
struct
{
mixin volatile_uint!"subreg";
};
}
void vtest()
{
S * s = cast(S *)0xDEADBEEF;
while (s.reg == 0)
{
s.subreg = 1;
}
}
```
This works and I like from the user side being able to access
each field as if it was just the normal field. However, declaring
the fields is a bit uglier syntax.
# Questions
Between the two of these attempts I'm leaning toward #2 because
of the easier user syntax to read/write the fields.
I am wondering:
1. Is there any way to improve attempt #1 to not require the
.get() call? I tried with opCast() but that requires the user to
do an explicit cast which I felt was even worse than the .get
1. Is there any way to improve attempt #2 to make field
declaration cleaner than `mixin volatile_uint!"reg"`?
1. Is there any other way of achieving what I'm trying to achieve
different from these two methods?
More information about the Digitalmars-d-learn
mailing list