digitalmars.D.learn - volatile struct definition for peripheral control registers
- Josh Holtrop (115/115) Dec 02 2024 I'm working on an embedded project writing some device drivers to
- =?UTF-8?Q?Ali_=C3=87ehreli?= (6/8) Dec 02 2024 'alias this' may help:
- Josh Holtrop (3/13) Dec 02 2024 If I use `alias this` I don't know how I can get `volatileLoad()`
- Salih Dincer (51/54) Dec 02 2024 Please allow me to illustrate the point with a simple example so
- =?UTF-8?Q?Ali_=C3=87ehreli?= (4/7) Dec 02 2024 Note that alias this is used with your 'get' function, which still calls...
- Josh Holtrop (6/15) Dec 02 2024 Ah... very nice. I completely missed that "alias this" could be
- Josh Holtrop (35/35) Dec 02 2024 Just to follow up, I introduced the `Volatile` struct to my
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...
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.
```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.
of the easier user syntax to read/write the fields.
I am wondering:
.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
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?
Dec 02 2024
On 12/2/24 11:10 AM, Josh Holtrop wrote:This works but requires that ugly .get call rather than just accessing it directly.'alias this' may help: https://dlang.org/spec/struct.html#alias-this All you need to do is to add the following line to the Volatile template: alias get this; Ali
Dec 02 2024
On Monday, 2 December 2024 at 19:30:06 UTC, Ali Çehreli wrote:On 12/2/24 11:10 AM, Josh Holtrop wrote:If I use `alias this` I don't know how I can get `volatileLoad()` to be called.This works but requires that ugly .get call rather than justaccessingit directly.'alias this' may help: https://dlang.org/spec/struct.html#alias-this All you need to do is to add the following line to the Volatile template: alias get this; Ali
Dec 02 2024
On Monday, 2 December 2024 at 20:27:23 UTC, Josh Holtrop wrote:If I use `alias this` I don't know how I can get `volatileLoad()` to be called.Please allow me to illustrate the point with a simple example so that you can visualize it: ```d struct FixedStr(size_t capacity) { char[capacity] data = ' '; char[] buff; size_t titleLength; this(string _data) { buff = data[]; this ~= _data; titleLength = _data.length; } alias opReturn this; property auto opReturn() inout => data[titleLength..$]; // cuts off the title auto ref opOpAssign(string op)(string arr) if(op == "~") => buff.put(arr); // add in the data } import std.range : chunks, put; import std.string : format; import std.stdio : writeln; void main() { enum text = "sixtwoone"; auto test = FixedStr!22("Nums : "); assert(is(typeof(test) == struct)); // not a string ------------^ foreach(num; text.chunks(3)) { test ~= num.format!"%s, "; } test.writeln; // six, two, one, test[5..8].writeln; // two } ``` Let's have a 2-function struct as above. In fact, the functions do not have a feature that is open to direct use. There's not even an overload like `opReturn()`, it's my made :) To rotate a fixed string (char[]) by cropping it from the beginning (open it to the outside world) and to add data sequentially (via `std.range.put`) to its limit. But we also want to use it like the familiar string (e.g. line 2 output: "two"). And that's what we do easily with `alias ... this`. However, in this example, it is necessary to use property and inout; keep in mind... It's also a good idea to keep this in mind: https://dlang.org/changelog/2.100.0.html#alias_this_assignment SDB 79
Dec 02 2024
On 12/2/24 12:27 PM, Josh Holtrop wrote:Note that alias this is used with your 'get' function, which still calls volatileLoad(). Alialias get this;If I use `alias this` I don't know how I can get `volatileLoad()` to be called.
Dec 02 2024
On Monday, 2 December 2024 at 22:44:24 UTC, Ali Çehreli wrote:On 12/2/24 12:27 PM, Josh Holtrop wrote:Ah... very nice. I completely missed that "alias this" could be used with a function. This works great and lets me use a nicer syntax to declare the fields. Thank you both. :)`volatileLoad()` to bealias get this;If I use `alias this` I don't know how I can getcalled.Note that alias this is used with your 'get' function, which still calls volatileLoad(). Ali
Dec 02 2024
Just to follow up, I introduced the `Volatile` struct to my
project and had to add a couple extra functions to make
everything happy:
```d
module myproj.volatile;
import core.volatile;
struct Volatile(T)
{
private T value;
public property T read()
{
return volatileLoad(&value);
}
alias read this;
public void opAssign(T value)
{
volatileStore(&this.value, value);
}
public T opUnary(string s)()
{
T v = read();
mixin(s ~ "v;");
volatileStore(&this.value, v);
return v;
}
public T opOpAssign(string s)(T rhs)
{
T v = read();
mixin("v " ~ s ~ "= rhs;");
volatileStore(&this.value, v);
return v;
}
}
```
So far it is working great!
Dec 02 2024









Salih Dincer <salihdb hotmail.com> 