DMD hackers: pragma(address): Is this possible?
Johannes Pfau via Digitalmars-d
digitalmars-d at puremagic.com
Tue Nov 25 05:04:49 PST 2014
I've tested some ideas with Volatile!T but there's always one remaining
problem:
In C people often define a macro to describe a MMIO location:
#define PORTB *((ubyte*)0x05)
which can then be used like this:
PORTB |= 0b1000_0000;
It's not really possible to represent this in D. There are workarounds,
but all have drawbacks. Naive approaches require space in the data
section. Defining PORTB as an enum ubyte* is working, but then operator
overloading doesn't work correctly (or the user always has to
dereference manually). immutable ubyte* also doesn't work because of
transitivity.
So I think we do need a way to specify this: I've got an extern
variable, and it's at this address. This is quite similar to
pragma(mangle), so in some way it seems natural to use this:
pragma(address, 0x05) extern ubyte PORTB;
But does this really make sense? What makes a variable a variable? For
example the GCC backends has builtin support for extern, static, const,
manifest variables, but no way to specify an address for an extern
variable. Is there a reason for this?
(Another solution are alias expressions but that's much more invasive.)
I've also implemented a small proof-of concept for this idea: Right now
I simply implemented the pragma and return a pointer dereference
expression from VarExp::sematic. This seems to work fine so far, but
are there other ways to access a variable without a VarExp or could
there be any other problems?
---------
import gcc.builtins;
struct Noop
{
ubyte _data;
void opOpAssign(string op)(in ubyte rhs) nothrow
{
ubyte val = __builtin_volatile_load(&_data);
mixin("val" ~ op ~ "= rhs;");
__builtin_volatile_store(&_data, val);
}
}
pragma(address, 0x1000) extern Noop PORTB;
void main()
{
auto addr = &PORTB;
PORTB |= 0b1000_000;
}
;; Function D main (_Dmain)
;; enabled by -tree-original
{
struct Noop * addr;
(void) (addr = 4096B);
opOpAssign (4096B, 64);
return <retval> = 0;
}
;; Function opOpAssign
(_D4test4Noop25__T10opOpAssignVAyaa1_7cZ10opOpAssignMFNbxhZv) ;;
enabled by -tree-original
{
ubyte val;
if (this != 0)
{
<<< Unknown tree: void_cst >>>
}
else
{
_d_assert_msg ({.length=9, .ptr="null this"},
{.length=9, .ptr="../test.d"}, 7); }
(void) (val = (ubyte) *(volatile ubyte *) &this->_data);
(void) (val = val | (ubyte) rhs);
(void) (*(volatile ubyte *) &this->_data = val);
}
(With -O1 this generates perfect ASM. Of course once we have this
working there are much better ways to access the registers than
simple bit manipulation)
More information about the Digitalmars-d
mailing list