Search code examples
c++assemblygccavrinline-assembly

asm error "inconsistent operand constraints in an 'asm'"


I'm trying to use this code for attiny10. Here, I try to use _delay_loop_2 but it does not work sometime.

#include <avr/io.h>
#include <util/delay.h>

#define LED_PIN         PB0
#define DELAY_MAX       512
#define DELAY_MIN       1


int
main(void)
{
        uint16_t delay = DELAY_MIN;
        uint8_t dir = 0;

        /* setup */
        DDRB = 0b00000001; // set LED pin as OUTPUT
        PORTB = 0b00000001; // set LED pin to HIGH

        /* loop */
        while (1) {

                PORTB &= ~(_BV(LED_PIN)); // LED off
                _delay_loop_2(delay);

                PORTB |= _BV(LED_PIN); // LED on
                _delay_loop_2(DELAY_MAX - delay);

                if (dir) { // fade-in
                        if (++delay >= (DELAY_MAX - 1)) dir = 0;
                } else { // fade-out
                        if (--delay <= DELAY_MIN) dir = 1;
                }

        }
}

But sometimes I get the error.

Processing attiny10 (platform: atmelavr; board: attiny10)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/atmelavr/attiny10.html
PLATFORM: Atmel AVR (4.0.0) > ATtiny10
HARDWARE: ATTINY10 1MHz, 32B RAM, 1KB Flash
PACKAGES: 
 - toolchain-atmelavr @ 1.50400.190710 (5.4.0)
LDF: Library Dependency Finder -> 
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 0 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Compiling .pio/build/attiny10/src/main.o
Linking .pio/build/attiny10/firmware.elf
src/main.cpp: In function 'main':
/Users/user/.platformio/packages/[email protected]/avr/include/util/delay_basic.h:110:3: error: inconsistent operand constraints in an 'asm'
  );
   ^
/Users/user/.platformio/packages/[email protected]/avr/include/util/delay_basic.h:110:3: error: inconsistent operand constraints in an 'asm'
  );
   ^
lto-wrapper: fatal error: avr-g++ returned 1 exit status
compilation terminated.
/Users/user/.platformio/packages/[email protected]/bin/../lib/gcc/avr/5.4.0/../../../../avr/bin/ld: error: lto-wrapper failed
collect2: error: ld returned 1 exit status
*** [.pio/build/attiny10/firmware.elf] Error 1

My investigation showed the problem is here.


void
_delay_loop_1(uint8_t __count)
{
    __asm__ volatile (
        "1: dec %0" "\n\t"
        "brne 1b"
        : "=r" (__count)
        : "0" (__count)
    );
}

void
_delay_loop_2(uint16_t __count)
{
    __asm__ volatile (
        "1: sbiw %0,1" "\n\t"
        "brne 1b"
        : "=w" (__count)
        : "0" (__count)
    );
}

But if I change _delay_loop_2 on _delay_loop_1. There is no error anymore. Why does it happen? I use virtual studio and PlatformIO.


Solution

  • There is this bug reported against AVR-LibC: Extend _delay_loop_2 so it works with AVR_TINY.

    Well, it's a pull request actually, so you see the solution to the bug. After applying the patch to include/util/delay_basic.h, _delay_loop_2 will read:

    void
    _delay_loop_2 (uint16_t __count)
    {
    #if defined (__AVR_TINY__)
        __asm__ volatile (
            "1: subi %A0,1" "\n\t"
            "   sbci %B0,0" "\n\t"
            "brne 1b"
            : "+d" (__count)
        );
    #else
        __asm__ volatile (
            "1: sbiw %0,1" "\n\t"
            "brne 1b"
            : "+w" (__count)
        );
    #endif /* AVR_TINY */
    }
    

    The problem was that register class w is empty on reduced Cores, thus just fall back to 2-instruction subtraction with register class d.

    However

    Better don't use stuff like _delay_loop_2 which is internal helper.

    If you want to delay a specific number of cycles specified at compile-time, better use __builtin_avr_delay_cycles, see https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/AVR-Built-in-Functions.html