For low-level programming, sometimes it's necessary to say, at a given memory location, this is where my address is. For this post, the example is the PIR1
register in the PIC16F886 and related microcontrollers. It's always found at address 0x000C.
I've taken this approach:
#define pir1 (*(uint8_t*)0xc)
now I can assign to the variable with something like pir1 |= 0x40
(okay, I'd use a #defined constant instead of magic numbers but you get my drift). This compiles just fine on GCC, with no warnings even when I use -Wextra -Wall
. To check my assumptions, GCC spits out the following x86_64:
movl $12, %eax
movb $64, (%rax)
Exactly what I wanted (okay, I'm now sure why it's eax
one moment and rax
another, that's probably yet another stupid x86 quirk, but irrelevant since I want PIC14 code anyway)
Now, to target the PIC14, I'm actually using the SDCC compiler. I am invoking it like this
sdcc --std-c99 -mpic14 -p16f886 --use-non-free source.c
The above code starting with #define
gives the following warning:
source.c:412: warning 88: cast of LITERAL value to 'generic' pointer
from type 'const-int literal'
to type 'unsigned-char generic* fixed'
I've tried doing this instead:
__code __at (0xc) uint8_t PIR1;
but that results in an error message
error 33: Attempt to assign value to a constant variable (=)
when I try to make an assignment.
So my question is if I'm missing an idiomatic way to do this in C? Why is SDCC warning me? Is there's some particular SDCC specific funk I'm ignoring here?