Memory Master Example

In most cases the user will take advantage of the pyrogue.RemoteVariable, pyrogue.Device, pyrogue.RemoteCommand and pyrogue.MemoryBlock classes to interact with memory buses. In rare cases it may be necessary to write custom memory Master modules in Python or C++.

Python and C++ subclasses of the Master class can be used interchangeably, allowing c++ Slave subclasses to service memory transactions from python masters and python Slave subclasses to receive service memory transactions initiated by c++ masters.

See Master for more detail on the Master class.

Below is an example class which will initiate a read followed by a write.

import pyrogue
import rogue.interfaces.memory

# Create a subclass of a memory Master
# This master will initiate a read from a passed address and
# increment that value at that address by a passed value
class MyMemMaster(rogue.interfaces.memory.Master):

    # Init method must call the parent class init
    def __init__(self):
        super().__init__()

    # Start a sequence with passed address and increment value
    def incAtAddress(self, address, value):

        # Create byte array for data
        ba = bytearray(4)

        # Clear any existing errors
        self._clearError()

        # Start read transaction from address into bytearray
        # size = 4, byte array offset = 0
        id = self._reqTransaction(address, ba, 4, 0, rogue.interfaces.memory.Read)

        # Wait for transaction to complete
        _waitTransaction(id)

        # Check transaction result
        if self._getError() != "":
            print("got error")
            return False

        # Increment value in byte array by passed value
        oldValue = int.from_bytes(ba, 'little', signed=False)
        oldvalue += value
        ba = oldValue.to_bytes(4, 'little', signed=False)

        # Start write transaction to address from bytearray
        # size = 4, byte array offset = 0
        id = self._reqTransaction(address, ba, 4, 0, rogue.interfaces.memory.Write)

        # Wait for transaction to complete
        self._waitTransaction(id)

        # Check transaction result
        self.if _getError() != "":
            print("got error")
            return False
        else:
            return True

The equivalent code in C++ is show below:

#include <rogue/interfaces/memory/Constants.h>
#include <rogue/interfaces/memory/Master.h>

// Create a subclass of a memory Master
// This master will initiate a read from a passed address and
// increment that value at that address by a passed value
class MyMemMaster : public rogue::interfaces::memory::Master {
   public:

      // Create a static class creator to return our custom class
      // wrapped with a shared pointer
      static std::shared_ptr<MyMemMaster> create() {
         static std::shared_ptr<MyMemMaster> ret =
            std::make_shared<MyMemMaster>();
         return(ret);
      }

      // Standard class creator which is called by create
      MyMemMaster() : rogue::interfaces::memory::Master() {}

      // Start a sequence with passed address and increment value
      bool incAtAddress(uint64_t address, uint32_t value) {
         uint32_t rValue;
         uint32_t id;

         // Clear any existing errors
         this->clearError();

         // Start read transaction, size=4
         id = this->reqTransaction(address, 4, &rValue, rogue::interfaces::memory::Read);

         // Wait for transaction to complete
         this->waitTransaction(id)

         // Check transaction result
         if ( this->getError() != "" ) {
             printf("got error\n");
             return false;
         }

         // Increment value by passed value
         rValue += value;

         // Start write transaction, size = 4
         id = this->reqTransaction(address, 4, &rValue, rogue::interfaces::memory::Write);

         // Wait for transaction to complete
         this->waitTransaction(id)

         // Check transaction result
         if ( this->getError() != "" ) {
             printf("got error\n");
             return false;
         } else return true;

      }
};

// Shared pointer alias
typedef std::shared_ptr<MyMemMaster> MyMemMasterPtr;

Of course neither of the above classes ensure that the memory does not get modified by another process between the read and write. The pyrogue device management tree manages this at a higher level.