Jun 26, 2018

[C++] Design the Write-only variables

reference:
https://mklimenko.github.io/english/2018/06/19/write-only-variables/

There are basically three types of registers:
  • Read-write
  • Read-only
  • Write-only
Read-write:
volatile auto &read_write = *reinterpret_cast<std::uint32_t*>(register_address);
Read-only:
const volatile auto &read_only = *reinterpret_cast<std::uint32_t*>(register_address);
Code:
https://godbolt.org/g/1ro2FN
constexpr std::size_t register_address = 123456;
const volatile auto &read_only = *reinterpret_cast<std::uint32_t*>(register_address);


void foo() {
    auto dst = read_only;
}
/// Disassembly:
foo():
  mov eax, DWORD PTR ds:123456
  ret

Wrap it:
https://godbolt.org/g/nbDYdo
class Register {
private:
    static volatile inline std::uint32_t &ref = *reinterpret_cast<std::uint32_t*>(register_address);
public:
    static std::uint32_t Get(){
        return ref;
    }

    static void Set(std::uint32_t val){
        ref = val;
    }
};


Final code:
https://godbolt.org/g/gQR1wd
#include <cstdint>
#include <type_traits>


template <std::size_t address> 
class Register {
    private:
    static volatile inline std::uint32_t &ref = *reinterpret_cast<std::uint32_t*>(address);

    public:
    Register& operator=(std::uint32_t val){
        ref = val;
        return *this;
    }

    template <typename T>
    operator T() const{
        static_assert(std::is_same_v<T, std::uint32_t>, "You should assign this register to the std::uint32_t value"); 
        return T();
    }

    operator std::uint32_t() const {
        return ref;
    }
};

Register<1234567> reg;

void RegGet() {
    auto dst = reg;
}

void RegSet(std::uint32_t val) {
    reg = val;
}


write-only:
template <std::size_t address> 
class Register {
private:
    static volatile inline std::uint32_t &ref = *reinterpret_cast<std::uint32_t*>(address);
public:
    static void Set(std::uint32_t val){
        ref = val;
    }

    Register& operator=(std::uint32_t val){
        ref = val;
        return *this;
    }
};


read-only:
template <std::size_t address> 
class Register {
private:
    static volatile inline std::uint32_t &ref = *reinterpret_cast<std::uint32_t*>(address);
public:
    static std::uint32_t Get(){
        return ref;
    }

    template <typename T>
    operator T() const{
        static_assert(std::is_same_v<T, std::uint32_t>, "You should assign this register to the std::uint32_t value"); 
        return T();
    }

    operator std::uint32_t() const {
        return ref;
    }

};

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.