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:
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:
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
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);
}
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:
- 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
- Is there any way to improve attempt #2 to make field declaration cleaner than
mixin volatile_uint!"reg"
? - Is there any other way of achieving what I'm trying to achieve different from these two methods?