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)