简体   繁体   中英

How do I translate AVR GCC-style C inline assembly to Rust inline assembly?

I want to translate some Arduino code written originally in C++ to Rust but this line of inline assembly is giving me trouble.

    asm volatile(
      "     lds r16, %[timer0]    \n\t" //
      #if defined(__AVR_ATmega2560__)
      "     add r16, %[toffset]   \n\t" //
      #endif
      "     subi r16, %[tsync]    \n\t" //
      "     andi r16, 7           \n\t" //
      "     call TL               \n\t" //
      "TL:                        \n\t" //
      #if defined(__AVR_ATmega2560__)
      "     pop r17               \n\t" //ATMEGA2560 has a 22bit PC!
      #endif
      "     pop r31               \n\t" //
      "     pop r30               \n\t" //
      "     adiw r30, (LW-TL-5)   \n\t" //
      "     add r30, r16          \n\t" //
      //"   adc r31, __zero_reg__ \n\t" //
      "     ijmp                  \n\t" //
      "LW:                        \n\t" //
      "     nop                   \n\t" //
      "     nop                   \n\t" //
      "     nop                   \n\t" //
      "     nop                   \n\t" //
      "     nop                   \n\t" //
      "     nop                   \n\t" //
      "     nop                   \n\t" //
      //"   nop                   \n\t" //
      "LBEND:                     \n\t" //
    :
    : [timer0] "i" (&TCNT0),
      [toffset] "i" ((uint8_t)DEJITTER_OFFSET),
      [tsync] "i" ((uint8_t)DEJITTER_SYNC)
    : "r30", "r31", "r16", "r17");

my best attempt is this:

    const TCNT0: *mut u8 = 70 as *mut u8;
    const DEJITTER_OFFSET: u8 = 1;
    const DEJITTER_SYNC: i8 = -2;

    asm!(
"     lds r16, %[timer0]
\t     subi r16, %[tsync]
\t     andi r16, 7
\t     call TL
\tTL:
\t     pop r31
\t     pop r30
\t     adiw r30, (LW-TL-5)
\t     add r30, r16
\t     ijmp
\tLW:
\t     nop
\t     nop
\t     nop
\t     nop
\t     nop
\t     nop
\t     nop
\tLBEND:
\t"
    :
    : "{timer0}"(&TCNT0),
      "{toffset}"(DEJITTER_OFFSET),
      "{tsync}"(DEJITTER_SYNC)
    : "r30", "r31", "r16": "volatile");

I'm still far from being able to compile. The error shown when I try to compile is:

error: couldn't allocate input reg for constraint '{timer0}'
  --> /home/kirbylife/Proyectos/rvgax/src/lib.rs:53:9
   |
53 | /         asm!(
54 | | r"     lds r16, ${timer0}
55 | |      subi r16, ${tsync}
56 | |      andi r16, 7
...  |
77 | |       "{tsync}"(DEJITTER_SYNC)
78 | |     : "r30", "r31", "r16": "volatile");
   | |_______________________________________^

I'm using Cargo and rustc 1.38.0.

The immediate meaning of your error is that there's not registers called timer0 , toffset , and tsync . The root cause is that "{}" syntax in Rust denotes register names for constraints, not symbolic names. In other words, it corresponds to the "" stuff in GCC, not the [] stuff. I don't see a way to use symbolic names, so just switch to numerical ones instead. Also, it uses $ instead of % for substituting from constraints. Try this instead:

    const TCNT0: *mut u8 = 70 as *mut u8;
    const DEJITTER_OFFSET: u8 = 1;
    const DEJITTER_SYNC: i8 = -2;

    asm!(
"     lds r16, $0
\t     subi r16, $2
\t     andi r16, 7
\t     call TL
\tTL:
\t     pop r31
\t     pop r30
\t     adiw r30, (LW-TL-5)
\t     add r30, r16
\t     ijmp
\tLW:
\t     nop
\t     nop
\t     nop
\t     nop
\t     nop
\t     nop
\t     nop
\tLBEND:
\t"
    :
    : "i"(&TCNT0),
      "i"(DEJITTER_OFFSET),
      "i"(DEJITTER_SYNC)
    : "r30", "r31", "r16": "volatile");

(note: untested, since I don't currently have AVR-Rust installed)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM