2

In my Atmel ASF project, I am trying to build following inline asm code. However I am getting impossible constraint while compilation.

Compiler points to this line __asm__ __volatile__, am I missing anything?

#define OUTPORT PORTD
#define OUTBIT 3      // PD.3   
uint8_t rport ,rbits;
uint8_t *buf = message;
asm volatile(   "in     __tmp_reg__, __SREG__             \n\t" // 1  Save SREG for later
                "cli                                      \n\t" // 1  Clear interrupts
                "in     %[rport], %[port]                 \n\t" // 1  Move PORTB adress to rport

                : //Outputs
                [rport] "=&r" (rport)

                : //Inputs
                [port]    "I" (_SFR_IO_ADDR(OUTPORT))     // Adress to port register, 6-bit positive constant

                : //Clobber list (compiler must restore)

                "r0"                                       // This is __tmp_reg__
);
  1. What is destroying this build?
  2. I wonder if asm syntax is incorrect? I have been following this manual
phuclv
  • 37,963
  • 15
  • 156
  • 475
Artec
  • 23
  • 4
  • That's very hefty inline asm. Make sure you need asm for this and if you really do consider putting it in a separate asm file and not inline. Will save a lot of headache. – Jester Jun 11 '16 at 16:02
  • That's a ridiculously long macro. Why not make it a function and put it in an assembly file? Then it doesn't even need to be volatile. Given all its calls and deliberate delays, how could it possibly hurt? And then you will get reasonable diagnostics. And if this is called more than once, your code will get smaller. – DigitalRoss Jun 11 '16 at 16:03
  • Is _SFR_IO_ADDR(OUTPORT) actually a value between 0 and 63? – Michael Petch Jun 11 '16 at 21:48
  • Upvoted for turning this into an [mcve] instead of a ridiculously large code dump. (For future readers: see the revision history for the original, which probably didn't leave interrupts disabled.) – Peter Cordes Jun 11 '16 at 21:50
  • I only ask my previous question because I wonder if it is outside the range mentioned, and possibly `"M"` would be more appropriate than `"I"`. – Michael Petch Jun 11 '16 at 21:59
  • @MichaelPetch I tried even "M", but it is complaining about the same constraint. – Artec Jun 11 '16 at 22:16
  • @DigitalRoss, Jester only reason for inline is the timing requirements and also having it in assembly file complicate it more. – Artec Jun 11 '16 at 22:18
  • I assume you included – Michael Petch Jun 11 '16 at 22:21
  • What is the actual value of `_SFR_IO_ADDR(OUTPORT)`? – David Wohlferd Jun 12 '16 at 00:09
  • You have used "rport" as a label and as a variable. Try using a different label that doesn't conflict with a variable name. – UncleO Jun 12 '16 at 01:07
  • Works fine here with `avr-gcc -mmcu=attiny2313` (version 4.7.2). – Jester Jun 12 '16 at 18:14
  • @Jester, I am trying to compile it with avr-gcc -mmcu=atxmega128a4u (version 4.9.2) – Artec Jun 12 '16 at 20:42
  • **Inline assembly with arguments must be located in a function.** As your code is not inside a function, it will never work, no matter with which constraints. – emacs drives me nuts Dec 16 '22 at 14:59
  • (Posting as an answer because I'm new and don't have rep to comment yet. But maybe I can provide some insight to anyone else who ends up here.) I wound up here after copy/pasting some asm into a project I'm working on with an ATMega4809 and got the same error. I don't know asm, but Edgar's answer above gave me the clue I needed to solve my problem: I recalled from reading the MCU datasheet that it also provides a set of "virtual ports" VPORTA, VPORTB, etc. and that these provide direct memory access. Changing my code from PORTC to VPORTC resolved the compiler error for me and got it working. – Absurd Squirrel Dec 16 '22 at 03:28

1 Answers1

1

PORTD, on the ATxmega128A4U, is at address 0x0660, as stated in its datasheet, page 62. The port is therefore not accessible to the in instruction. You should use lds instead, with the constraint

[port]  "i" (_SFR_MEM_ADDR(OUTPORT))

Notice the lowercase "i".

Addendum: I just tried compiling the following:

#include <avr/io.h>

void test(void)
{
    uint8_t rport;

    asm volatile(
        "in __tmp_reg__, __SREG__  \n\t"
        "cli                       \n\t"
        "lds %[rport], %[port]     \n\t"
        : [rport] "=&r" (rport)               // output
        : [port]  "i" (_SFR_MEM_ADDR(PORTD))  // input
        : "r0"                                // clobber
    );
}

Using avr-gcc 4.9.2 with the options -mmcu=atxmega128a4u -c I get the correct generated code and no warnings, even with -Wall -Wextra.

The "i" constraints is documented to mean an “immediate integer operand”, whereas "I" means “Constant greater than −1, less than 64”.

Edgar Bonet
  • 3,416
  • 15
  • 18
  • lowercase "i" constraint is not known to the compiler also if i use lds in the code section it complains about operand. – Artec Jun 14 '16 at 06:29
  • @Artec: avr-gcc 4.9.2 does support the "i" constraint. See amended answer. – Edgar Bonet Jun 14 '16 at 08:25
  • Since it's just a normal load, you don't actually need inline asm to load from it. Just a `volatile char* portd = (char*)_SFR_MEM_ADDR(PORTD)`. – Peter Cordes Jun 14 '16 at 08:40
  • @PeterCordes: In plain C I would rather write `char* portd = PORTD;`, which is a more standard idiom when programming with avr-libc (`PORTD` is defined as `(*(volatile uint8_t *)(0x0660))`). This idiom also works with the I/O space, as the compiler optimizes the access into `in` or `out` when possible. – Edgar Bonet Jun 14 '16 at 08:58
  • @EdgarBonet: ah I see; I haven't coded for AVR. I've seen similar SO questions about MMIO on ARM. Anyway, I think you mean `uint8_t portd_value = PORTD;`, since the macro apparently includes a dereference. – Peter Cordes Jun 14 '16 at 09:41
  • @EdgarBonet thanks for clarifying. following instruction is not operating since port is outside the lower 32 I/O registers. Following is causing operand out of range error, even SBS is not supported "sbi %[port] , %[bit] \n\t" // 1 Set pin HIGH – Artec Jun 14 '16 at 22:45