cembeddedpicsdccmemory-mapped-io

How to put a variable at a specific memory location in SDCC


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 not 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?


Solution

  • Regarding the warning it's probably a bug in the compiler. And as said, you must use (volatile uint8_t*)0xc for memory-mapped access instead

    The standard way for absolute addressing in SDCC is via compiler extensions, but you're doing it wrongly. __code __at (0xc) uint8_t PIR1; puts the variable in the code section which isn't writable. That's why you see the error error 33: Attempt to assign value to a constant variable (=). Remember PIC14 uses Harvard architecture. If the address is in RAM then use

    volatile __data __at (0xc) uint8_t PIR1;
    

    If it's in xdata then use

    volatile __xdata __at (0xc) uint8_t PIR1;
    

    See Absolute Addressing in the documentation

    Demo on Godbolt