如何将 AVR GCC 风格的 C 内联汇编转换为 Rust 内联汇编?

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

我想将一些最初用 C++ 编写的 Arduino 代码翻译成 Rust,但是这行内联汇编给我带来了麻烦。

    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");

我最好的尝试是:

    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");

我离编译还差得很远。我尝试编译时显示的错误是:

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");
   | |_______________________________________^

我正在使用 Cargo 和 rustc 1.38.0。

您的错误的直接含义是没有名为 timer0toffsettsync 的寄存器。根本原因是 Rust 中的 "{}" 语法表示约束的寄存器名称,而不是符号名称。换句话说,它对应于GCC中的""东西,而不是[]东西。我看不到使用符号名称的方法,所以只需改用数字名称即可。此外,它使用 $ 而不是 % 来替换约束。试试这个:

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

    asm!(
"     lds r16, [=10=]
\t     subi r16, 
\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");

(注意:未经测试,因为我目前没有安装 AVR-Rust)