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