For some reason I want to mix a bit of assembly with C++ (not C).
To allow the code to be compilable using the standard Arduino IDE, I don't want to use direct assembly source.
I don't want to use a wrapper C file either.
My problem is as follows:
I have a class with a single instance (implementing some kind of driver) that looks like this:
class cDriver {
public:
char ISR_param;
// ...
};
cDriver Driver;
If I want to access the ISR_param
of this single instance from within an ISR, I can do something like:
ISR (TIMER2_COMPA_Vect) {
do_something_with (Driver.ISR_param);
}
This works like a charm: the address of Driver.ISR_param
beign a constant, the compiler simply generates an lds r24, &Driver.ISR_param
instruction to load the proper byte as a parameter for do_something_with
.
Now when I try to replicate the same mechanism with inline assembler, things get a lot more complicated.
The address of Driver.ISR_param
is only known to the C++ compiler as an mangled label, and I can't find a way to pass it to the inline assembler to generate the equivalent lds r24, <&Driver.ISR_param>
.
trying to remane the variable
The renaming of variables for assembly like so:
char global_var asm("my_var");
and an attempt to use it like so:
asm ("lds r24, my_var\n");
will compile, but produce a linker error (my_var
is undefined).
Looking at the object symbol table, the only label for global_var
is a C++-like mangled name.
However hard I tried this renaming trick, I could not bring the compiler to generate a my_var
label.
trying to use asm constraints
A constraint like
asm (lds r24, %0\n" : : "I"(&global_var));
will simply not compile. I scoured the possible parameter types and could not find a way to let the assembler know about this bloody address.
a terribly awkward workaround
The only way I found to make the compiler generate this dreaded lds r24,...
instruction is to perform an actual function call.
So you can do something like:
__attribute__((always_inline)) give_me_my_friggin_variable(char data)
{
asm volatile ("cmp %0,%0\n"::"r"(data));
}
ISR (TIMER2_COMPA_Vect, ISR_NAKED) {
<some prologue to save SREG and all needed registers>
//...
give_me_my_friggin_variable(Driver.ISR_param);
// continue assembly code with r24 properly initialized
}
That will generate:
lds r24, <the proper address> // added by the compiler...
cmp r24,r24 // ...because of the register constraint here
Well, that sort of works, but at the cost of generating a totally useless instruction.
so my question is...
Is there a simpler way to let the assembler know about addresses of C++ static variables?