avr-gcc inline assembler viselt dolgai

Sziasztok!

Adott AVR8 alatt egy egyszeru problema: ossze kellene szorozni egy 32bites es egy 8bites szamot. Ha csinalok erre egy ilyesmit, hogy


static inline uint32_t mul32x8(uint32_t a,uint8_t b)
{
 return(a*b);
}

akkor ez nagyon lassu lesz. Tobbek kozott azert mert 32x32bites szorzasra alakitja es egy avr-libc konyvtarban implementalt (valami __mul32... jellegu nevvel megaldott) fuggvenyt hiv. Es ez ugye egy RISC architektura alatt (plane 8 biten) koltseges. Marmint mind az a luxus hogy 8bit helyett 32bittel dolgozunk, mind a fuggvenyhivas.

Nosza, irjuk meg asm-ben. Halistennek a linuxos avr-gcc fejleszteseben is tevekenyen ott van az Atmel, a referenciadoksi is nagyon jo, igy szepen el lehet indulni. Ossze is sikerult dobni egy ilyet:


static inline uint32_t mul32x8(uint32_t a,uint8_t b)
{
 uint32_t       prod;

 __asm__ 
  (
        "       mul     %A[a], %[b]     \n\t"
        "       mov     %A[p], r0       \n\t"
        "       mov     %B[p], r1       \n\t"
        "       eor     %C[p], %C[p]    \n\t"
        "       eor     %D[p], %D[p]    \n\t"
        "       mul     %B[a], %[b]     \n\t"
        "       add     %B[p], r0       \n\t"
        "       adc     %C[p], r1       \n\t"
        "       mul     %C[a], %[b]     \n\t"
        "       add     %C[p], r0       \n\t"
        "       adc     %D[p], r1       \n\t"
        "       mul     %D[a], %[b]     \n\t"
        "       add     %D[p], r0       \n\t"

        : [p] "=&d" (prod)
        : [a] "d" (a), [b] "d" (b) 
        :  "r0", "r1", "cc"
  );

 return(prod);
}

Offline debugger szerint is megy, jo kodot is general (avr-objdump -d), elesben is majdnem mukodik, csak neha nem. Akkor viszont valahogy ugy kifagyasztja az MCU-t hogy WDR-ig se sikerul eljutnia :] Akkor nem mukodik (neha), ha ket egymas koveto" szorzas van, kis egyeb aritmetikaval (pl osszeadas). Igy felmerul a lehetoseg, hogy optimalizacio (-O3) soran valamit a parameter-regiszterekkel (lasd [p], [a], [b]) igencsak osszekavar itten.

Szoval a lenyegi kerdes: van-e valakinek tapasztalata hogy gcc inline asm mellett az output es/vagy input parametereknel az egyes regisztereket hogyan erdemes es/vagy ajanlott beallitani? Esetleg pont AVR8 alatt? A "d" itten kvazi hasrautes szeru" volt, de ha pl =&d helyett csak =d-t adok meg outputkent akkor az -O3-as kod mar debugger szinten nem lesz jo. A clobber szekcioban meg az r0, r1 es a flags-on kivul mast csakcsak nem kell megadni (a mul explicite csak az r0,r1-et bantja, a tobbi meg csak a parametereit es a cc-t). De valszeg a kiakada's azert van mert itten rosszul adok meg valamit... Lehet hogy "d" helyett "a" kene? A referencia szepen osszefoglalja az opciokat (r, d, a, l, ...) de hogy ebben az esetben mi a banat baja lehet azt nem tudom...

thx, A

Hozzászólások

Úgy rémlik, hogy az r1 a __zero_reg__, a libc sok helyen feltételezi, hogy 0 van benne, emiatt, ha megváltoztattuk, akkor illendő törölni a használat végén.

Koszi, igen, lehet hogy ez lesz az! Lasd pl itten.

Ettol fuggetlenul kerdes, hogy a clobber erre nem ad-e valami automatikus megodast. Merthogy annak pont az a celja hogy explicit jelezzuk hogy milyen regisztereket piszkaltunk meg az asm kodban. Illetve ezzel fenntartho (lenne) a ko'd "hordozhatosaga is" (maramennyiben asm eseten erdemes ilyesmirol beszelni...:]).