CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 17
  1. #1
    Join Date
    Dec 2005
    Posts
    382

    Reading/Writing to H/W registers

    I need to read and write to H/W register. Of course, I'm given an address and the representation for the data. For instance at address 0x00009 the layout is as follows:

    Spare : 16;
    Revision : 8;
    Number : 8

    To structure this in code, my current thought surrounds the use of Sets and Gets within a class. Bit Fiddling is done within the Sets and Gets to allow the user to retrieve the desired element. Now given:

    Code:
    class FPGA_Memory_Map {
    
    public : 
      void Set_Revision ( unsigned int Revision ) {
         // do some bit fiddling within a local variable - a shadow register of sorts
         // write value to the register location  
      }
      unsigned int Get_Revision ( ) {  
        // get value from register location 
        // update the local variable 
        return ( whatever ) ; 
      } 
    
      // lots more gets/sets
    
    };
    At issue: I'll need to have a Write and Read method in every Set and Get respectively. The Read and Write methods provides the interface to the H/W register. Clearly this is starting to look like a recipe for disaster especially when each bit within a 32 bit value means something different: i.e

    MBC1 : 1
    MBC2 : 1
    MBC3 : 1
    // up to
    MBC32 : 1

    The question, how can I structure the application such that when the user calls a Set/Get methods the Write/Read methods gets invoked?

    Maybe a different approach would be prudent. I'm open to alternatives.

    Thanks

  2. #2
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Reading/Writing to H/W registers

    1) Under MOST operating systems you can NOT directly write to hardware registers.

    2) If you can infact write to them, then Placement New can be your friend.
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  3. #3
    Join Date
    Dec 2005
    Posts
    382

    Re: Reading/Writing to H/W registers

    Quote Originally Posted by TheCPUWizard View Post
    1) Under MOST operating systems you can NOT directly write to hardware registers.
    Agreed, except my application is executing on a TI DSP, which has a litany of peripheral registers - SPI, CAN etc. etc. + my own memory map - to deal with.

    Quote Originally Posted by TheCPUWizard View Post
    2) If you can infact write to them, then Placement New can be your friend.
    In which case, I could use it within the set and get methods?

  4. #4
    Join Date
    Nov 2003
    Posts
    1,902

    Re: Reading/Writing to H/W registers

    Typically in C, you would use macros to construct the proper pointer casting of the fixed memory address for reading a writing the register. In C++ you can use inline template functions instead of macros. For example:
    Code:
    #include <iostream>
    using namespace std;
    
    template <typename register_t, typename ptrdiff_t>
    inline
    volatile register_t* reg_ptr(ptrdiff_t address)
    {
        return reinterpret_cast<register_t*>(address);
    }//reg_ptr
    
    template <typename register_t, typename ptrdiff_t>
    inline
    register_t reg_read(ptrdiff_t address)
    {
        return *reg_ptr<register_t>(address);
    }//reg_read
    
    template <typename register_t, typename ptrdiff_t>
    inline
    void reg_write(register_t value, ptrdiff_t address)
    {
        *reg_ptr<register_t>(address) = value;
    }//reg_write
    
    int main()
    {
        // use memory off the heap for testing
        int *p = new int;
        int addr = reinterpret_cast<int>(p);
    
        // write to "register" then read it back
        reg_write(5, addr);
        cout << reg_read<int>(addr) << endl;
    
        // or, create a reference variable representing the "register" 
        volatile int &reg_ref = *reg_ptr<int>(addr);
        reg_ref = 0;
        cout << reg_read<int>(addr) << endl;
    
        delete p;
        return 0;
    }//main
    gg

  5. #5
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Reading/Writing to H/W registers

    You CAN to the casting, but then it gets lost with other casts. Pleacemet new overcomes this...
    Code:
    struct RegBlock
    {
       BYTE RegA;
       Byte RegB;
    }
    
    void *regBase; // Initialized to base address of this registerr group...
    
    RegBlock *p = new(regBase) RegBlock();
    
    p->RegA = 123;
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  6. #6
    Join Date
    Dec 2005
    Posts
    382

    Re: Reading/Writing to H/W registers

    Codeplug & CPUWizard thanks alot. Sure helps alot when I see code

    Truly appreciate it. If I could apply a rating I would. Not sure why this 'low level' (though I admit I'm not a fan of) stuff had me stuck on trying to determine what's the right thing to do

    I might be back for a critique of my approach when I put something together based on ideas presented.
    Last edited by mop65715; December 29th, 2008 at 12:42 PM.

  7. #7
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Reading/Writing to H/W registers

    Quote Originally Posted by mop65715 View Post
    Truly appreciate it.
    You can...just click on the little "scales" icon to the right of the replies...

    Also dont forget to mark threads as resolved...
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  8. #8
    Join Date
    Nov 2003
    Posts
    1,902

    Re: Reading/Writing to H/W registers

    I don't see how anything is "lost" using either method. Placement new achieves the same results as a cast.

    When mapping a structure of contiguous registers onto memory, you must take care to ensure the compiler generates the proper byte-packing and alignment. You should also generate volatile reads and writes when accessing the registers.

    Thinking about it more, this seems like the most straight forward way of accessing a single register or a block of registers (in my opinion):
    Code:
    typedef unsigned long uint32; // 32bit type on "this" platform
    
    volatile uint32 &REG1 = *reinterpret_cast<uint32*>(/*0x9*/new uint32);
    
    struct RegBlock1 // ensure proper packing/alignment
    {
        uint32 REG1;
        uint32 REG2;
    };//RegBlock
    
    volatile RegBlock1 &REG_BLOCK1 = *reinterpret_cast<RegBlock1*>(/*0x9*/new RegBlock1);
    If you have a lot of (unrelated) registers/blocks to define, you could organize them into separate namespaces for additional readability.

    You can also check your compiler documentation to see if it supports bit-field access to individual registers. For example: http://focus.ti.com/lit/an/spraa85a/spraa85a.pdf

    gg

  9. #9
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Reading/Writing to H/W registers

    Quote Originally Posted by Codeplug View Post
    I don't see how anything is "lost" using either method. Placement new achieves the same results as a cast.
    Let me e-mail you code that has the following characterisicws.

    1) 100,000 line of source code
    2) 2,000 reinterpret_casts in the code base.
    3) 5 structures that represent "fixed address" items (e.g. registers)
    4) 75 places in the code where these structures ARE mapped to the physical location.
    5) a couple of hunder of these same structures that are in normal ram (ie shadows)

    Your task is to find the 75 locations in the code. You have 30 minutes.

    With your approach it would be virtually impossible.

    With placement new. You can just put a private override of the placement new operator in the 5 structures, re-compile and hacve the answer in about a minute (assuming a really fast compiler!)

    That is what gets "lost".
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  10. #10
    Join Date
    Nov 2003
    Posts
    1,902

    Re: Reading/Writing to H/W registers

    Those 75 places would be qualified with volatile, and the "shadows" wouldn't.

    gg

  11. #11
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Reading/Writing to H/W registers

    Quote Originally Posted by Codeplug View Post
    Those 75 places would be qualified with volatile, and the "shadows" wouldn't.
    gg
    Most likely not...the general accepted pattern is to make the members volatile, as shown in the code snipped below. Requiring the "user" of the structure to remember to declare each instance volatile violates the principle
    Quote Originally Posted by Scott Meyers
    Make classes easy to use properly and difficult to use incorrectly
    Code:
    struct RegisterSet{ enum eCommands { CommandAddress  = 1,
                                       CommandDisable  = 2,
                                       CommandIdle     = 3,
                                       CommandNone     = 0,
                                       CommandNop      = 7,
                                       CommandReceive  = 4,
                                       CommandTransmit = 5 };
                      enum eStates { StateDisabled        = 0,
                                     StateIdle            = 1,
                                     StateMaster          = 2,
                                     StateSlave           = 3,
                                     StateSlaveTerminated = 4,
                                     StateTransition      = 5 };
    
                      unsigned                                      : 6;
                      bool      volatile const TransmitDataFull     : 1;
                      bool      volatile const ReceiveDataAvailable : 1;
                      bool      volatile const Interrupt            : 1;
                      bool      volatile const Acknowledged         : 1;
                      eStates   volatile const State                : 3;
                      eCommands volatile       Command              : 3;
                    };
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  12. #12
    Join Date
    Nov 2003
    Posts
    1,902

    Re: Reading/Writing to H/W registers

    >> the general accepted pattern
    That pattern suggests that the structure is not meant to be used in ram. Otherwise the "shadow" copies would be unnecessarily qualified as volatile.

    gg

  13. #13
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Reading/Writing to H/W registers

    Quote Originally Posted by Codeplug View Post
    >> the general accepted pattern
    That pattern suggests that the structure is not meant to be used in ram. Otherwise the "shadow" copies would be unnecessarily qualified as volatile.

    gg
    volatile only has a potential for negative impact if there was the opportunity for the compiler to optimze multiple reference (ie by using a register).

    In 30+ years of professional development, including many real-time (embedded system) programs where I am concered with sub 100uS timing loops), I have NEVER encountered a single situation where this has occured.

    It is much better to write robust code that minimizes the risk of errors. Unless it can be PROVEN (for a pspecific circumstance that there is no viable alternative the safest code is always the best code.
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  14. #14
    Join Date
    Nov 2003
    Posts
    1,902

    Re: Reading/Writing to H/W registers

    There only ever needs to be one instance of "RegisterSet" per hardware instance (eg. their may be multiple UARTs). Making that one instance volatile qualified isn't any more or less "robust" than using explicit qualification with multiple instances (created with placement new). Since the one instance is already volatile - there's no way for the "user" to make a mistake - they just use the already defined instance. The only advantage that could be claimed in using one method or the other, is that shadows wouldn't be unnecessarily volatile qualified - which ties the optimizers hands in more ways than just cpu-register allocation. Still, I don't see one as being more/less robust than the other.

    Having a single instance means no need for placement new. Searching the source for non-shadowed references is as simple as searching for "REG_BLOCK1" (using my previous example). Still, I don't see anything being "lost" choosing this approach over the other.

    If you wanted to support shadowed copies of "RegBlock1", then you would need to add copy and assignment operators:
    Code:
    #include <iostream>
    using namespace std;
    
    //------------------------------------------------------------------------------
    
    typedef unsigned long uint32; // 32bit type on "this" platform
    
    struct RegBlock1 // ensure proper packing/alignment
    {
        uint32 REG1;
        uint32 REG2;
    
        RegBlock1() {}
        RegBlock1(volatile const RegBlock1 &rhs) {*this = rhs;}
        RegBlock1& operator=(volatile const RegBlock1 &rhs)
        {
            REG1 = rhs.REG1;
            REG2 = rhs.REG2;
            return *this;
        }//assignment operator
    };//RegBlock1
    
    extern volatile RegBlock1 &REG_BLOCK1; // for header
    
    #define REG_BLOCK1_ADDR /*0x9*/ (new RegBlock1) // use heap for testing
    
    volatile RegBlock1 &REG_BLOCK1 = *reinterpret_cast<RegBlock1*>(REG_BLOCK1_ADDR);
    
    //------------------------------------------------------------------------------
    
    int main()
    {
        // write to "REG1" then read it back
        REG_BLOCK1.REG1 = 4;
        cout << REG_BLOCK1.REG1 << endl;
    
        // create a non-volatile shadow copy of block 1
        RegBlock1 rb1_copy = REG_BLOCK1;
    
        return 0;
    }//main
    This gives you another method for finding all shadow copies in the source: just comment out the copy/assignment operators and compile.

    gg

  15. #15
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Reading/Writing to H/W registers

    Quote Originally Posted by Codeplug View Post
    There only ever needs to be one instance of "RegisterSet" per hardware instance (eg. their may be multiple UARTs). Making that one instance volatile qualified isn't any more or less "robust" than using explicit qualification with multiple instances (created with placement new). Since the one instance is already volatile - there's no way for the "user" to make a mistake - they just use the already defined instance.
    This is self conflicting. If there are multiple dynamic instances (for example the Photon Dispersion Energy controller I wrote earlier this year had between 16 and 256 sensors depending on configuration), and it was a different developer than the original author of the structure who instantiated the instances putting them into a collection.

    "Steve" was a user of the classes that "Robert" designed, and he NEVER had to use or think about the word volatile. "Peter" used the instantiated instances (exposed via STL collections) and never had to know about placement new. Complete seperation of concerns.

    I am NOT disagreeing with your methodology in terms of it working. There is no argument there. And my approach is definately biased by the fact that I run a small development company, where a single "oops" can mean the difference between success and company failure (which has not happened in the 25 years in business)
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured