Advertisement
Guest User

Untitled

a guest
Feb 1st, 2015
314
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 14.38 KB | None | 0 0
  1. module util.memory;
  2.  
  3. import gcc.builtins, gcc.attribute;
  4. //import std.traits;
  5.  
  6. /**
  7.  * Treat storage of T as volatile. This means all modify operations
  8.  * are rewritten to load-modify-store and loads and stores
  9.  * are not optimized by the compiler (no reordering, no merging/elimination
  10.  * of loads or stores).
  11.  *
  12.  * This does neither guarantee that loads and stores are atomic
  13.  * nor does it guarantee that CPUs do not reorder or merge loads
  14.  * and stores.
  15.  */
  16. @attribute("noinit") struct Volatile(T) //if(isIntegral!T)
  17. {
  18. private:
  19.     T _store;
  20.  
  21. public:
  22.     @disable this(this);
  23.  
  24.     /**
  25.      * Performs 1 load followed by 1 store
  26.      */
  27.     @attribute("inlineonly") void opOpAssign(string op)(in T rhs) nothrow @trusted
  28.     {
  29.         T val = __builtin_volatile_load(&_store);
  30.         mixin("val" ~ op ~ "= rhs;");
  31.         __builtin_volatile_store(&_store, val);
  32.     }
  33.  
  34.     /**
  35.      * Performs 1 store
  36.      */
  37.     @attribute("inlineonly") void opAssign()(const T rhs) nothrow @trusted
  38.     {
  39.         __builtin_volatile_store(&_store, rhs);
  40.     }
  41.  
  42.     /**
  43.      * Performs 1 load
  44.      */
  45.     @attribute("inlineonly") T load() nothrow @trusted const
  46.     {
  47.         return __builtin_volatile_load(&_store);
  48.     }
  49.  
  50.     /**
  51.      * Performs 1 load
  52.      */
  53.     @attribute("inlineonly") bool opEquals()(const T rhs) nothrow @trusted const
  54.     {
  55.         return __builtin_volatile_load(&_store) == rhs;
  56.     }
  57.  
  58.     /**
  59.      * Performs 1 load
  60.      */
  61.     @attribute("inlineonly") int opCmp()(const T rhs) nothrow @trusted const
  62.     {
  63.         T val = __builtin_volatile_load(&_store);
  64.         if(val == rhs)
  65.             return 0;
  66.         else if(val < rhs)
  67.             return -1;
  68.         else
  69.             return 1;
  70.     }
  71. }
  72.  
  73. unittest
  74. {
  75.     Volatile!size_t value;
  76.     assert(value == 0);
  77.     assert(value.sizeof == size_t.sizeof);
  78.  
  79.     Volatile!size_t value2;
  80.     assert(!__traits(compiles, value2 = value));
  81.  
  82.     size_t b = value.load();
  83. }
  84.  
  85. unittest
  86. {
  87.     // opOpAssign
  88.     Volatile!size_t value;
  89.  
  90.     value += 1;
  91.     assert(value == 1);
  92.     value *= 2;
  93.     assert(value == 2);
  94.     value /= 2;
  95.     assert(value == 1);
  96.     value %= 2;
  97.     assert(value == 1);
  98.     value ^^= 2;
  99.     assert(value == 1);
  100.     value &= 0b10;
  101.     assert(value == 0);
  102.     value |= 0b10;
  103.     assert(value == 2);
  104.     value ^= 0b11;
  105.     assert(value == 1);
  106.     value <<= 1;
  107.     assert(value == 2);
  108.     value >>= 1;
  109.     assert(value == 1);
  110.  
  111.     assert(!__traits(compiles, value ~= 1));
  112. }
  113.  
  114. unittest
  115. {
  116.     //opCmp
  117.     Volatile!size_t value;
  118.     value = 42;
  119.  
  120.     assert(value <= 42);
  121.     assert(value >= 42);
  122.     assert(value < 43);
  123.     assert(value > 41);
  124.     assert(value == 42);
  125. }
  126.  
  127. enum Access
  128. {
  129.     read,
  130.     write,
  131.     readWrite
  132. }
  133. @attribute("noinit") struct Field
  134. {
  135.     string name;
  136.     size_t startBit, endBit;
  137.     bool toggle;
  138.     string type;
  139.     Access access;
  140. }
  141.  
  142.  
  143. /**
  144.  * Register Type generator
  145.  *
  146.  * TODO: Use Volatile!T as store + alias this to avoid some code duplication
  147.  * TODO: verify function: only single bits can be toggled, no overlapping fields,
  148.  *       no fields outside of storeType length
  149.  */
  150. @attribute("nocode") string generateRegisterType(BaseType)(string regName, Field[] fields)
  151. {
  152.     string storeType = BaseType.stringof;
  153.  
  154.     // Helper function to convert positive number to string
  155.     string numToString(size_t num)
  156.     {
  157.         if(num == 0)
  158.             return "0";
  159.         string result;
  160.         while(num != 0)
  161.         {
  162.             auto remainder = num % 10;
  163.             num /= 10;
  164.             result = cast(char)('0' + remainder) ~ result;
  165.         }
  166.         return result;
  167.     }
  168.  
  169.     // Generate the constraint for the toggle function
  170.     // if (name == "PIN0" || name == "PIN1")
  171.     string toggleConstraint = "if (";
  172.     bool first = true;
  173.     foreach(field; fields)
  174.     {
  175.         if(field.toggle)
  176.         {
  177.             if(first)
  178.             {
  179.                 first = false;
  180.                 toggleConstraint ~= "name == \"" ~ field.name ~ "\"";
  181.             }
  182.             else
  183.             {
  184.                 toggleConstraint ~= " || name == \"" ~ field.name ~ "\"";
  185.             }
  186.         }
  187.     }
  188.     toggleConstraint ~= ")";
  189.  
  190.     // The final output
  191.     string result =
  192. "/*@attribute(\"noinit\")*/ struct " ~ regName ~ "Register
  193. {
  194.    private " ~ storeType ~ " _store = void;
  195.  
  196.    // Load/Store methods
  197.  
  198.    /**
  199.     * Toggle(invert) the bit representing a field.
  200.     *
  201.     * Note: Performs exactly one load followed by one store
  202.     */
  203.    @attribute(\"inlineonly\") void toggle(string name)() nothrow @trusted " ~ toggleConstraint ~ "
  204.    {
  205.        " ~ storeType ~ " val = __builtin_volatile_load(&_store);
  206.        mixin(\"enum rhs = mask\" ~ name ~ \" << shift\" ~ name ~ \";\");
  207.        mixin(\"val ^= rhs;\");
  208.        __builtin_volatile_store(&_store, val);
  209.    }
  210.  
  211.    /**
  212.     * Load the complete register and return the value
  213.     *
  214.     * Note: Performs exactly one load
  215.     */
  216.    @attribute(\"inlineonly\") " ~ storeType ~ " load()() nothrow @trusted const
  217.    {
  218.        return __builtin_volatile_load(&_store);
  219.    }
  220.  
  221.    /**
  222.     * Store value into register.
  223.     *
  224.     * Note: Performs exactly one store
  225.     */
  226.    @attribute(\"inlineonly\") void store()(const " ~ storeType ~ " value) nothrow @trusted
  227.    {
  228.        __builtin_volatile_store(&_store, cast(" ~ storeType ~ ")value);
  229.    }
  230.  
  231.    // Operator overloading
  232.  
  233.    /**
  234.     * Operator overload for Read-Modify-Write operators
  235.     *
  236.     * Note: Performs exactly one load followed by one store
  237.     */
  238.    @attribute(\"inlineonly\") void opOpAssign(string op)(in " ~ storeType ~ " rhs) nothrow @trusted
  239.    {
  240.        " ~ storeType ~ " val = __builtin_volatile_load(&_store);
  241.        mixin(\"val\" ~ op ~ \"= rhs;\");
  242.        __builtin_volatile_store(&_store, val);
  243.    }
  244.  
  245.    /**
  246.     * Operator overload for assignment
  247.     *
  248.     * Note: Performs exactly one store
  249.     */
  250.    @attribute(\"inlineonly\") void opAssign()(const " ~ storeType ~ " rhs) nothrow @trusted
  251.    {
  252.        __builtin_volatile_store(&_store, rhs);
  253.    }
  254.  
  255.    /**
  256.     * Operator overload for equality check
  257.     *
  258.     * Note: Performs exactly one load
  259.     */
  260.    @attribute(\"inlineonly\") bool opEquals()(const " ~ storeType ~ " rhs) nothrow @trusted const
  261.    {
  262.        return __builtin_volatile_load(&_store) == rhs;
  263.    }
  264.  
  265.    /**
  266.     * Operator overload for comparison
  267.     *
  268.     * Note: Performs exactly one load
  269.     */
  270.    @attribute(\"inlineonly\") int opCmp()(const " ~ storeType ~ " rhs) nothrow @trusted const
  271.    {
  272.        " ~ storeType ~ " val = __builtin_volatile_load(&_store);
  273.        if(val == rhs)
  274.            return 0;
  275.        else if(val < rhs)
  276.            return -1;
  277.        else
  278.            return 1;
  279.    }
  280.  
  281. ";
  282.  
  283.     // Generate shift & mask entries
  284.     // enum shiftPIN0 = 0;
  285.     foreach(field; fields)
  286.     {
  287.         result ~= "    /// Shift constant for " ~ field.name ~ " field\n";
  288.         result ~= "    enum shift" ~ field.name ~ " = " ~ numToString(field.startBit) ~ ";\n";
  289.     }
  290.     // enum maskPIN0 = 0b1;
  291.     foreach(field; fields)
  292.     {
  293.         result ~= "    /// Mask constant for " ~ field.name ~ " field\n";
  294.         result ~= "    enum mask" ~ field.name ~ " = 0b";
  295.         for(size_t i = 0; i <= field.endBit - field.startBit; i++)
  296.             result ~= "1";
  297.         result ~= ";\n";
  298.     }
  299.  
  300.     // Now generate the properties
  301.     foreach(field; fields)
  302.     {
  303.         if(field.access == Access.read || field.access == Access.readWrite)
  304.         {
  305.             result ~= "
  306.    /**
  307.     *
  308.     */
  309.    @attribute(\"inlineonly\") @property " ~ field.type ~ " " ~ field.name ~ "()() nothrow @trusted const
  310.    {
  311.         auto val = __builtin_volatile_load(&_store);
  312.         return cast(" ~ field.type ~ ")((val >> shift" ~ field.name ~ ") & mask" ~ field.name ~ ");
  313.    }
  314. ";
  315.         }
  316.         if(field.access == Access.write || field.access == Access.readWrite)
  317.         {
  318.             result ~= "
  319.    /**
  320.     *
  321.     */
  322.    @attribute(\"inlineonly\") @property void " ~ field.name ~ "()(" ~ field.type ~ " value) nothrow @trusted
  323.    {
  324.        auto val = __builtin_volatile_load(&_store);
  325.        auto maskOR = cast(typeof(val))((value & mask" ~ field.name ~ ") << shift" ~ field.name ~ ");
  326.        auto maskAND = ~cast(typeof(val))((~value & mask" ~ field.name ~ ") << shift" ~ field.name ~ ");
  327.        val |= maskOR;
  328.        val &= maskAND;
  329.        __builtin_volatile_store(&_store, val);
  330.    }
  331. ";
  332.         }
  333.  
  334.     }
  335.  
  336.     // Finish the struct definition
  337.     result ~=
  338. "}";
  339.     return result;
  340. }
  341.  
  342. enum Level : ubyte
  343. {
  344.     low = 0,
  345.     high = 1
  346. }
  347.  
  348. enum fields = [
  349.     Field("PIN0", 0, 0, true, "Level", Access.readWrite),
  350.     Field("PIN1", 1, 1, true, "Level", Access.readWrite),
  351.     Field("TEST", 2, 4, false, "ubyte", Access.readWrite)];
  352.  
  353. //mixin(generateRegisterType!ubyte("PORT", fields));
  354. //pragma(msg, generateRegisterType!ubyte("PORT", fields));
  355.  
  356. /*@attribute("noinit")*/ struct PORTRegister
  357. {
  358.     private ubyte _store = void;
  359.    
  360.     // Load/Store methods
  361.    
  362.     /**
  363.      * Toggle(invert) the bit representing a field.
  364.      *
  365.      * Note: Performs exactly one load followed by one store
  366.      */
  367.     @attribute("inlineonly") void toggle(string name)() nothrow @trusted if (name == "PIN0" || name == "PIN1")
  368.     {
  369.         ubyte val = __builtin_volatile_load(&_store);
  370.         mixin("enum rhs = mask" ~ name ~ " << shift" ~ name ~ ";");
  371.         mixin("val ^= rhs;");
  372.         __builtin_volatile_store(&_store, val);
  373.     }
  374.    
  375.     /**
  376.      * Load the complete register and return the value
  377.      *
  378.      * Note: Performs exactly one load
  379.      */
  380.     @attribute("inlineonly") ubyte load()() nothrow @trusted const
  381.     {
  382.         return __builtin_volatile_load(&_store);
  383.     }
  384.    
  385.     /**
  386.      * Store value into register.
  387.      *
  388.      * Note: Performs exactly one store
  389.      */
  390.     @attribute("inlineonly") void store()(const ubyte value) nothrow @trusted
  391.     {
  392.         __builtin_volatile_store(&_store, cast(ubyte)value);
  393.     }
  394.    
  395.     // Operator overloading
  396.    
  397.     /**
  398.      * Operator overload for Read-Modify-Write operators
  399.      *
  400.      * Note: Performs exactly one load followed by one store
  401.      */
  402.     @attribute("inlineonly") void opOpAssign(string op)(in ubyte rhs) nothrow @trusted
  403.     {
  404.         ubyte val = __builtin_volatile_load(&_store);
  405.         mixin("val" ~ op ~ "= rhs;");
  406.         __builtin_volatile_store(&_store, val);
  407.     }
  408.    
  409.     /**
  410.      * Operator overload for assignment
  411.      *
  412.      * Note: Performs exactly one store
  413.      */
  414.     @attribute("inlineonly") void opAssign()(const ubyte rhs) nothrow @trusted
  415.     {
  416.         __builtin_volatile_store(&_store, rhs);
  417.     }
  418.    
  419.     /**
  420.      * Operator overload for equality check
  421.      *
  422.      * Note: Performs exactly one load
  423.      */
  424.     @attribute("inlineonly") bool opEquals()(const ubyte rhs) nothrow @trusted const
  425.     {
  426.         return __builtin_volatile_load(&_store) == rhs;
  427.     }
  428.    
  429.     /**
  430.      * Operator overload for comparison
  431.      *
  432.      * Note: Performs exactly one load
  433.      */
  434.     @attribute("inlineonly") int opCmp()(const ubyte rhs) nothrow @trusted const
  435.     {
  436.         ubyte val = __builtin_volatile_load(&_store);
  437.         if(val == rhs)
  438.             return 0;
  439.         else if(val < rhs)
  440.             return -1;
  441.         else
  442.             return 1;
  443.     }
  444.    
  445.     /// Shift constant for PIN0 field
  446.     enum shiftPIN0 = 0;
  447.     /// Shift constant for PIN1 field
  448.     enum shiftPIN1 = 1;
  449.     /// Shift constant for TEST field
  450.     enum shiftTEST = 2;
  451.     /// Mask constant for PIN0 field
  452.     enum maskPIN0 = 0b1;
  453.     /// Mask constant for PIN1 field
  454.     enum maskPIN1 = 0b1;
  455.     /// Mask constant for TEST field
  456.     enum maskTEST = 0b111;
  457.    
  458.     /**
  459.      *
  460.      */
  461.     @attribute("inlineonly") @property Level PIN0()() nothrow @trusted const
  462.     {
  463.         auto val = __builtin_volatile_load(&_store);
  464.         return cast(Level)((val >> shiftPIN0) & maskPIN0);
  465.     }
  466.    
  467.     /**
  468.      *
  469.      */
  470.     @attribute("inlineonly") @property void PIN0()(Level value) nothrow @trusted
  471.     {
  472.         auto val = __builtin_volatile_load(&_store);
  473.         auto maskOR = cast(typeof(val))((value & maskPIN0) << shiftPIN0);
  474.         auto maskAND = ~cast(typeof(val))((~value & maskPIN0) << shiftPIN0);
  475.         val |= maskOR;
  476.         val &= maskAND;
  477.         __builtin_volatile_store(&_store, val);
  478.     }
  479.    
  480.     /**
  481.      *
  482.      */
  483.     @attribute("inlineonly") @property Level PIN1()() nothrow @trusted const
  484.     {
  485.         auto val = __builtin_volatile_load(&_store);
  486.         return cast(Level)((val >> shiftPIN1) & maskPIN1);
  487.     }
  488.    
  489.     /**
  490.      *
  491.      */
  492.     @attribute("inlineonly") @property void PIN1()(Level value) nothrow @trusted
  493.     {
  494.         auto val = __builtin_volatile_load(&_store);
  495.         auto maskOR = cast(typeof(val))((value & maskPIN1) << shiftPIN1);
  496.         auto maskAND = ~cast(typeof(val))((~value & maskPIN1) << shiftPIN1);
  497.         val |= maskOR;
  498.         val &= maskAND;
  499.         __builtin_volatile_store(&_store, val);
  500.     }
  501.    
  502.     /**
  503.      *
  504.      */
  505.     @attribute("inlineonly") @property ubyte TEST()() nothrow @trusted const
  506.     {
  507.         auto val = __builtin_volatile_load(&_store);
  508.         return cast(ubyte)((val >> shiftTEST) & maskTEST);
  509.     }
  510.    
  511.     /**
  512.      *
  513.      */
  514.     @attribute("inlineonly") @property void TEST()(ubyte value) nothrow @trusted
  515.     {
  516.         auto val = __builtin_volatile_load(&_store);
  517.         auto maskOR = cast(typeof(val))((value & maskTEST) << shiftTEST);
  518.         auto maskAND = ~cast(typeof(val))((~value & maskTEST) << shiftTEST);
  519.         val |= maskOR;
  520.         val &= maskAND;
  521.         __builtin_volatile_store(&_store, val);
  522.     }
  523. }
  524.  
  525. pragma(address, 0x25) extern __gshared PORTRegister PORTB;
  526. void test()
  527. {
  528.  
  529.     //auto b = PORTB.load();
  530.     //writeln(PORTB.load());
  531.     //PORTB.toggle!"PIN0";
  532.     //PORTB.PIN0 = Level.low;
  533.     //writeln(PORTB.load());
  534.     //writeln(PORTB.load());
  535.     //auto x = PORTRegister.shiftPIN1;
  536.     //x = PORTB.shiftPIN1;
  537.     //auto bit1 = PORTB.PIN0;
  538.     //PORTB.PIN1 = Level.low;
  539.     PORTB.TEST = 0b000;
  540.  
  541.     //writeln(PORTB.load());
  542.     //PORTB.TEST = 0b011;
  543.     //writeln(PORTB.load());
  544.     //writeln(PORTB.TEST);
  545.     //PORTB.TEST = 0b000;
  546.     //writeln(PORTB.load());
  547.     //PORTB.TEST = 0b111;
  548.     //writeln(PORTB.load());
  549. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement