Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module util.memory;
- import gcc.builtins, gcc.attribute;
- //import std.traits;
- /**
- * Treat storage of T as volatile. This means all modify operations
- * are rewritten to load-modify-store and loads and stores
- * are not optimized by the compiler (no reordering, no merging/elimination
- * of loads or stores).
- *
- * This does neither guarantee that loads and stores are atomic
- * nor does it guarantee that CPUs do not reorder or merge loads
- * and stores.
- */
- @attribute("noinit") struct Volatile(T) //if(isIntegral!T)
- {
- private:
- T _store;
- public:
- @disable this(this);
- /**
- * Performs 1 load followed by 1 store
- */
- @attribute("inlineonly") void opOpAssign(string op)(in T rhs) nothrow @trusted
- {
- T val = __builtin_volatile_load(&_store);
- mixin("val" ~ op ~ "= rhs;");
- __builtin_volatile_store(&_store, val);
- }
- /**
- * Performs 1 store
- */
- @attribute("inlineonly") void opAssign()(const T rhs) nothrow @trusted
- {
- __builtin_volatile_store(&_store, rhs);
- }
- /**
- * Performs 1 load
- */
- @attribute("inlineonly") T load() nothrow @trusted const
- {
- return __builtin_volatile_load(&_store);
- }
- /**
- * Performs 1 load
- */
- @attribute("inlineonly") bool opEquals()(const T rhs) nothrow @trusted const
- {
- return __builtin_volatile_load(&_store) == rhs;
- }
- /**
- * Performs 1 load
- */
- @attribute("inlineonly") int opCmp()(const T rhs) nothrow @trusted const
- {
- T val = __builtin_volatile_load(&_store);
- if(val == rhs)
- return 0;
- else if(val < rhs)
- return -1;
- else
- return 1;
- }
- }
- unittest
- {
- Volatile!size_t value;
- assert(value == 0);
- assert(value.sizeof == size_t.sizeof);
- Volatile!size_t value2;
- assert(!__traits(compiles, value2 = value));
- size_t b = value.load();
- }
- unittest
- {
- // opOpAssign
- Volatile!size_t value;
- value += 1;
- assert(value == 1);
- value *= 2;
- assert(value == 2);
- value /= 2;
- assert(value == 1);
- value %= 2;
- assert(value == 1);
- value ^^= 2;
- assert(value == 1);
- value &= 0b10;
- assert(value == 0);
- value |= 0b10;
- assert(value == 2);
- value ^= 0b11;
- assert(value == 1);
- value <<= 1;
- assert(value == 2);
- value >>= 1;
- assert(value == 1);
- assert(!__traits(compiles, value ~= 1));
- }
- unittest
- {
- //opCmp
- Volatile!size_t value;
- value = 42;
- assert(value <= 42);
- assert(value >= 42);
- assert(value < 43);
- assert(value > 41);
- assert(value == 42);
- }
- enum Access
- {
- read,
- write,
- readWrite
- }
- @attribute("noinit") struct Field
- {
- string name;
- size_t startBit, endBit;
- bool toggle;
- string type;
- Access access;
- }
- /**
- * Register Type generator
- *
- * TODO: Use Volatile!T as store + alias this to avoid some code duplication
- * TODO: verify function: only single bits can be toggled, no overlapping fields,
- * no fields outside of storeType length
- */
- @attribute("nocode") string generateRegisterType(BaseType)(string regName, Field[] fields)
- {
- string storeType = BaseType.stringof;
- // Helper function to convert positive number to string
- string numToString(size_t num)
- {
- if(num == 0)
- return "0";
- string result;
- while(num != 0)
- {
- auto remainder = num % 10;
- num /= 10;
- result = cast(char)('0' + remainder) ~ result;
- }
- return result;
- }
- // Generate the constraint for the toggle function
- // if (name == "PIN0" || name == "PIN1")
- string toggleConstraint = "if (";
- bool first = true;
- foreach(field; fields)
- {
- if(field.toggle)
- {
- if(first)
- {
- first = false;
- toggleConstraint ~= "name == \"" ~ field.name ~ "\"";
- }
- else
- {
- toggleConstraint ~= " || name == \"" ~ field.name ~ "\"";
- }
- }
- }
- toggleConstraint ~= ")";
- // The final output
- string result =
- "/*@attribute(\"noinit\")*/ struct " ~ regName ~ "Register
- {
- private " ~ storeType ~ " _store = void;
- // Load/Store methods
- /**
- * Toggle(invert) the bit representing a field.
- *
- * Note: Performs exactly one load followed by one store
- */
- @attribute(\"inlineonly\") void toggle(string name)() nothrow @trusted " ~ toggleConstraint ~ "
- {
- " ~ storeType ~ " val = __builtin_volatile_load(&_store);
- mixin(\"enum rhs = mask\" ~ name ~ \" << shift\" ~ name ~ \";\");
- mixin(\"val ^= rhs;\");
- __builtin_volatile_store(&_store, val);
- }
- /**
- * Load the complete register and return the value
- *
- * Note: Performs exactly one load
- */
- @attribute(\"inlineonly\") " ~ storeType ~ " load()() nothrow @trusted const
- {
- return __builtin_volatile_load(&_store);
- }
- /**
- * Store value into register.
- *
- * Note: Performs exactly one store
- */
- @attribute(\"inlineonly\") void store()(const " ~ storeType ~ " value) nothrow @trusted
- {
- __builtin_volatile_store(&_store, cast(" ~ storeType ~ ")value);
- }
- // Operator overloading
- /**
- * Operator overload for Read-Modify-Write operators
- *
- * Note: Performs exactly one load followed by one store
- */
- @attribute(\"inlineonly\") void opOpAssign(string op)(in " ~ storeType ~ " rhs) nothrow @trusted
- {
- " ~ storeType ~ " val = __builtin_volatile_load(&_store);
- mixin(\"val\" ~ op ~ \"= rhs;\");
- __builtin_volatile_store(&_store, val);
- }
- /**
- * Operator overload for assignment
- *
- * Note: Performs exactly one store
- */
- @attribute(\"inlineonly\") void opAssign()(const " ~ storeType ~ " rhs) nothrow @trusted
- {
- __builtin_volatile_store(&_store, rhs);
- }
- /**
- * Operator overload for equality check
- *
- * Note: Performs exactly one load
- */
- @attribute(\"inlineonly\") bool opEquals()(const " ~ storeType ~ " rhs) nothrow @trusted const
- {
- return __builtin_volatile_load(&_store) == rhs;
- }
- /**
- * Operator overload for comparison
- *
- * Note: Performs exactly one load
- */
- @attribute(\"inlineonly\") int opCmp()(const " ~ storeType ~ " rhs) nothrow @trusted const
- {
- " ~ storeType ~ " val = __builtin_volatile_load(&_store);
- if(val == rhs)
- return 0;
- else if(val < rhs)
- return -1;
- else
- return 1;
- }
- ";
- // Generate shift & mask entries
- // enum shiftPIN0 = 0;
- foreach(field; fields)
- {
- result ~= " /// Shift constant for " ~ field.name ~ " field\n";
- result ~= " enum shift" ~ field.name ~ " = " ~ numToString(field.startBit) ~ ";\n";
- }
- // enum maskPIN0 = 0b1;
- foreach(field; fields)
- {
- result ~= " /// Mask constant for " ~ field.name ~ " field\n";
- result ~= " enum mask" ~ field.name ~ " = 0b";
- for(size_t i = 0; i <= field.endBit - field.startBit; i++)
- result ~= "1";
- result ~= ";\n";
- }
- // Now generate the properties
- foreach(field; fields)
- {
- if(field.access == Access.read || field.access == Access.readWrite)
- {
- result ~= "
- /**
- *
- */
- @attribute(\"inlineonly\") @property " ~ field.type ~ " " ~ field.name ~ "()() nothrow @trusted const
- {
- auto val = __builtin_volatile_load(&_store);
- return cast(" ~ field.type ~ ")((val >> shift" ~ field.name ~ ") & mask" ~ field.name ~ ");
- }
- ";
- }
- if(field.access == Access.write || field.access == Access.readWrite)
- {
- result ~= "
- /**
- *
- */
- @attribute(\"inlineonly\") @property void " ~ field.name ~ "()(" ~ field.type ~ " value) nothrow @trusted
- {
- auto val = __builtin_volatile_load(&_store);
- auto maskOR = cast(typeof(val))((value & mask" ~ field.name ~ ") << shift" ~ field.name ~ ");
- auto maskAND = ~cast(typeof(val))((~value & mask" ~ field.name ~ ") << shift" ~ field.name ~ ");
- val |= maskOR;
- val &= maskAND;
- __builtin_volatile_store(&_store, val);
- }
- ";
- }
- }
- // Finish the struct definition
- result ~=
- "}";
- return result;
- }
- enum Level : ubyte
- {
- low = 0,
- high = 1
- }
- enum fields = [
- Field("PIN0", 0, 0, true, "Level", Access.readWrite),
- Field("PIN1", 1, 1, true, "Level", Access.readWrite),
- Field("TEST", 2, 4, false, "ubyte", Access.readWrite)];
- //mixin(generateRegisterType!ubyte("PORT", fields));
- //pragma(msg, generateRegisterType!ubyte("PORT", fields));
- /*@attribute("noinit")*/ struct PORTRegister
- {
- private ubyte _store = void;
- // Load/Store methods
- /**
- * Toggle(invert) the bit representing a field.
- *
- * Note: Performs exactly one load followed by one store
- */
- @attribute("inlineonly") void toggle(string name)() nothrow @trusted if (name == "PIN0" || name == "PIN1")
- {
- ubyte val = __builtin_volatile_load(&_store);
- mixin("enum rhs = mask" ~ name ~ " << shift" ~ name ~ ";");
- mixin("val ^= rhs;");
- __builtin_volatile_store(&_store, val);
- }
- /**
- * Load the complete register and return the value
- *
- * Note: Performs exactly one load
- */
- @attribute("inlineonly") ubyte load()() nothrow @trusted const
- {
- return __builtin_volatile_load(&_store);
- }
- /**
- * Store value into register.
- *
- * Note: Performs exactly one store
- */
- @attribute("inlineonly") void store()(const ubyte value) nothrow @trusted
- {
- __builtin_volatile_store(&_store, cast(ubyte)value);
- }
- // Operator overloading
- /**
- * Operator overload for Read-Modify-Write operators
- *
- * Note: Performs exactly one load followed by one store
- */
- @attribute("inlineonly") void opOpAssign(string op)(in ubyte rhs) nothrow @trusted
- {
- ubyte val = __builtin_volatile_load(&_store);
- mixin("val" ~ op ~ "= rhs;");
- __builtin_volatile_store(&_store, val);
- }
- /**
- * Operator overload for assignment
- *
- * Note: Performs exactly one store
- */
- @attribute("inlineonly") void opAssign()(const ubyte rhs) nothrow @trusted
- {
- __builtin_volatile_store(&_store, rhs);
- }
- /**
- * Operator overload for equality check
- *
- * Note: Performs exactly one load
- */
- @attribute("inlineonly") bool opEquals()(const ubyte rhs) nothrow @trusted const
- {
- return __builtin_volatile_load(&_store) == rhs;
- }
- /**
- * Operator overload for comparison
- *
- * Note: Performs exactly one load
- */
- @attribute("inlineonly") int opCmp()(const ubyte rhs) nothrow @trusted const
- {
- ubyte val = __builtin_volatile_load(&_store);
- if(val == rhs)
- return 0;
- else if(val < rhs)
- return -1;
- else
- return 1;
- }
- /// Shift constant for PIN0 field
- enum shiftPIN0 = 0;
- /// Shift constant for PIN1 field
- enum shiftPIN1 = 1;
- /// Shift constant for TEST field
- enum shiftTEST = 2;
- /// Mask constant for PIN0 field
- enum maskPIN0 = 0b1;
- /// Mask constant for PIN1 field
- enum maskPIN1 = 0b1;
- /// Mask constant for TEST field
- enum maskTEST = 0b111;
- /**
- *
- */
- @attribute("inlineonly") @property Level PIN0()() nothrow @trusted const
- {
- auto val = __builtin_volatile_load(&_store);
- return cast(Level)((val >> shiftPIN0) & maskPIN0);
- }
- /**
- *
- */
- @attribute("inlineonly") @property void PIN0()(Level value) nothrow @trusted
- {
- auto val = __builtin_volatile_load(&_store);
- auto maskOR = cast(typeof(val))((value & maskPIN0) << shiftPIN0);
- auto maskAND = ~cast(typeof(val))((~value & maskPIN0) << shiftPIN0);
- val |= maskOR;
- val &= maskAND;
- __builtin_volatile_store(&_store, val);
- }
- /**
- *
- */
- @attribute("inlineonly") @property Level PIN1()() nothrow @trusted const
- {
- auto val = __builtin_volatile_load(&_store);
- return cast(Level)((val >> shiftPIN1) & maskPIN1);
- }
- /**
- *
- */
- @attribute("inlineonly") @property void PIN1()(Level value) nothrow @trusted
- {
- auto val = __builtin_volatile_load(&_store);
- auto maskOR = cast(typeof(val))((value & maskPIN1) << shiftPIN1);
- auto maskAND = ~cast(typeof(val))((~value & maskPIN1) << shiftPIN1);
- val |= maskOR;
- val &= maskAND;
- __builtin_volatile_store(&_store, val);
- }
- /**
- *
- */
- @attribute("inlineonly") @property ubyte TEST()() nothrow @trusted const
- {
- auto val = __builtin_volatile_load(&_store);
- return cast(ubyte)((val >> shiftTEST) & maskTEST);
- }
- /**
- *
- */
- @attribute("inlineonly") @property void TEST()(ubyte value) nothrow @trusted
- {
- auto val = __builtin_volatile_load(&_store);
- auto maskOR = cast(typeof(val))((value & maskTEST) << shiftTEST);
- auto maskAND = ~cast(typeof(val))((~value & maskTEST) << shiftTEST);
- val |= maskOR;
- val &= maskAND;
- __builtin_volatile_store(&_store, val);
- }
- }
- pragma(address, 0x25) extern __gshared PORTRegister PORTB;
- void test()
- {
- //auto b = PORTB.load();
- //writeln(PORTB.load());
- //PORTB.toggle!"PIN0";
- //PORTB.PIN0 = Level.low;
- //writeln(PORTB.load());
- //writeln(PORTB.load());
- //auto x = PORTRegister.shiftPIN1;
- //x = PORTB.shiftPIN1;
- //auto bit1 = PORTB.PIN0;
- //PORTB.PIN1 = Level.low;
- PORTB.TEST = 0b000;
- //writeln(PORTB.load());
- //PORTB.TEST = 0b011;
- //writeln(PORTB.load());
- //writeln(PORTB.TEST);
- //PORTB.TEST = 0b000;
- //writeln(PORTB.load());
- //PORTB.TEST = 0b111;
- //writeln(PORTB.load());
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement