I'm working with some code that targets an unusual embedded system that requires distinct processor instructions to read from its read-only memory.
For variables to be placed in said read-only memory, they must be marked with an attribute that places them in a designated section whose contents will be placed into read-only memory.
It would be useful to be able to programmatically determine which section a variable is stored in so that I can determine, at compile-time, which variables are going to be stored in RAM (and thus can use ordinary pointer dereferencing and reference reading) and which variables are going to be stored in ROM (and thus require specialised access code written in assembly).
Having access to such a feature would allow me to do something like:
template<typename Type>
struct data_pointer
{
Type * pointer;
data_pointer(Type * pointer, bool) :
pointer { pointer } {}
// Non-const data cannot be readonly
Type & operator *()
{
return *pointer;
}
};
template<typename Type>
struct data_pointer<const Type>
{
const Type * pointer;
bool is_readonly;
data_pointer(const Type * pointer, bool is_readonly) :
pointer { pointer },
is_readonly { is_readonly }
{}
// Const data might be in RAM or ROM
const Type operator *()
{
return (is_readonly ? *pointer : readonly_dereference(pointer));
}
};
#define make_data_pointer(object) \
(data_pointer(&object, is_in_readonly_section(object)))
Where:
readonly_dereferenceis the mechanism by which a pointer to a value in the read-only memory area is read.is_in_readonly_section(object)is the hypothetical compile-time predicate that would be necessary to make the mechanism seamless.
Does GCC have anything akin to this hypothetical is_in_readonly_section compile-time predicate, or am I out of luck?
I could manage without it, but not having it means that the end user would be responsible for ensuring that their data_pointers point to the right kind of memory, which is liable to be a far more error-prone scenario than if the compiler could be made to bear the burden.
ReadOnly<int> foo;would define an object with the right attribute, with a conversion operator that executes the appropriate instruction. And now you can distinguish read-only objects because they are really a different C++ type.const rom<Type> var ROM { value };and then read the data either with an explicitvar.read(),rom_read(var), or (possibly dangerous) by overloadingoperator Type(). It's a little better, but still error prone...rom<Type>can only be used for variables with static storage duration, that it must always be used alongsideROM, and thatrom<Type>must never be used as a non-static local variable, non-static member variable, or a parameter, and that onlyrom<Type> &androm<Type> *are safe to use in those circumstances. Potentially a macro could alleviaterom<Type>always requiringROM, but it would look ugly (e.g.ROMDATA(Type, var) { value };). It might also be tricky to initialise e.g. arrays.