Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[GCC] przekazanie definicji do asemblera.

14 Gru 2008 21:37 1876 9
  • Poziom 18  
    mam złożone wyliczenia preprocesora dokonywane w trakcie kompilacji. wyznaczają one miejsca w pamięci i bloki programu które mają być dołączone.
    Problem się pojawia w chwili gdy obliczam wartości inicjujące program.
    potrzebuję przekazać je do funkcji pisanych czysto w assemblerze (jako wstawka) i nie mam jak tego zrobić. Sam nie rozwiązałem problemu ani nie udało mi się znaleźć w necie rozwiązania.

    ogólnie w GCC definicja:
    #define definicja_stalej 45

    ma pozwolić na wykonanie w asemblerze czegoś w tym rodzaju:

    ldi reg, definicja_stalej

    Czy ma ktoś jakieś rozwiązanie

    Przeniosłem z "Programowanie ogólne"
    Poprawiłem temat - wnioskuję, że chodzi o AVR.
    [Dr.Vee]
  • Pomocny post
    VIP Zasłużony dla elektroda
    Skoro to wstawka, to nie możesz tak:
    Code:
    #define BARDZO_WAZNA_WARTOSC 42
    

    asm volatile
           ( "ldi r16, %0" "\n\t"
           : /* wartosc zwracana */
           : "M" (BARDZO_WAZNA_WARTOSC)
           : "r16" /* rejestry zamazywane */
           );

    Ewentualnie prościej:
    Code:
    uint8_t stala = BARDZO_WAZNA_WARTOSC;
    
    asm volatile
           ( "jakas instrukcja %0" "\n\t"
           : /* wartosc zwracana */
           : "r" (stala)
           : /* rejestry zamazywane */
           );

    Wtedy kompilator wybiera rejestr za Ciebie.

    Poczytaj sobie więcej tutaj: http://www.nongnu.org/avr-libc/user-manual/inline_asm.html

    Pozdrawiam,
    Dr.Vee
  • Poziom 12  
    Dr.Vee a jak zrobić ustawianie jakiegoś bitu(np.7) na POTRB?
    Takie coś mi nie działa:
    Code:

    asm volatile("sbi %0, 0x07" : "I" (_SFR_IO_ADDR(PORTB)):);

    kompilator wywala błędy:
    error: lvalue required in asm statement
    error: output operand constraint lacks '='
    error: output operand constraint lacks '='
    error: invalid lvalue in asm output 0

    W manualu http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_startup piszą, że niby taki zapis jest ok.
  • VIP Zasłużony dla elektroda
    Czytaj ze zrozumieniem. Opuściłeś sekcję rejestrów wyjściowych, która tutaj powinna być pusta:
    Code:
    asm volatile("sbi %0, 0x07" : : "I" (_SFR_IO_ADDR(PORTB)));
    Zresztą po co komu taka wstawka? Przy optymalizacji -Os lub -O2 avr-gcc generuje dokładnie taką samą instrukcję dla kodu
    Code:
    PORTB |= 0x07;

    Pozdrawiam,
    Dr.Vee
  • Poziom 18  
    Dr.Vee napisał:
    Skoro to wstawka, to nie możesz tak:
    Code:
    #define BARDZO_WAZNA_WARTOSC 42
    

    asm volatile
           ( "ldi r16, %0" "\n\t"
           : /* wartosc zwracana */
           : "M" (BARDZO_WAZNA_WARTOSC)
           : "r16" /* rejestry zamazywane */
           );

    Ewentualnie prościej:
    Code:
    uint8_t stala = BARDZO_WAZNA_WARTOSC;
    
    asm volatile
           ( "jakas instrukcja %0" "\n\t"
           : /* wartosc zwracana */
           : "r" (stala)
           : /* rejestry zamazywane */
           );

    Wtedy kompilator wybiera rejestr za Ciebie.

    Poczytaj sobie więcej tutaj: http://www.nongnu.org/avr-libc/user-manual/inline_asm.html

    Pozdrawiam,
    Dr.Vee


    To jest rozwiązaniem ale chodzi mi o zapewnienie widoczności w asm gdyż wyliczam bardzo dużo takich wartości. jeśli tak to będę robił to bardzo nieczytelne zrobi się przekazywanie gdyż lista będzie wynosiła w moim przypadku liczba portów w kontrolerze * 6 definicji dla każdego portu co daje przy ATMega128 zawrotnie długą listę parametrów :/. Liczyłem na formę "Uwidocznienia" niż na formę "Przekazania". Już myślałem nawet na upchnięciu tego do pliku *.S
  • VIP Zasłużony dla elektroda
    Masz jeszcze kilka rozwiązań. Skoro to całe funkcje, to możesz je przenieść do osobnego pliku z rozszerzeniem .S - plik asemblera, który przed asemblacją zostanie przetworzony przez preprocesor - możesz tam normalnie używać #define, #include itd. Oczywiście musisz się stosować do konwencji przekazywania parametrów/zachowywania rejestrów.

    Jeśli chodzi o wstawki, to możesz zdefiniować sobie makra, które w miarę bezboleśnie przekażą definicje stałych. Np. korzystając z nazywanych parametrów w asemblerze (link do dokumentacji ten sam co wcześniej):
    Code:
    #define asm_param_foo [foo] "I" (DEFINICJA_PARAMETRU_FOO)
    
    #define asm_param_bar [bar] "I" (DEFINICJA_PARAMETRU_BAR)
    #define asm_parametry asm_param_foo, asm_param_bar

    /* wstawka */
    asm volatile
           ( "jakas instrukcja %[foo]" "\n\t"
             "jakas instrukcja %[bar]" "\n\t"
           : /* wartosc zwracana */
           : [inny_parametr] "r" (costam),
             asm_parametry
           : /* rejestry zamazywane */
           );

    Nie testowane, ale coś podobnego powinno się dać skonstruować :)

    Pozdrawiam,
    Dr.Vee
  • Poziom 18  
    Dr.Vee napisał:
    Czytaj ze zrozumieniem. Opuściłeś sekcję rejestrów wyjściowych, która tutaj powinna być pusta:
    Code:
    asm volatile("sbi %0, 0x07" : : "I" (_SFR_IO_ADDR(PORTB)));
    Zresztą po co komu taka wstawka? Przy optymalizacji -Os lub -O2 avr-gcc generuje dokładnie taką samą instrukcję dla kodu
    Code:
    PORTB |= 0x07;

    Pozdrawiam,
    Dr.Vee

    a może lepiej sobie zdefiniować strukturę bitową typu:
    typedef struct
    {
    uint8_t bbit0 : 1;
    uint8_t bbit1 : 1;
    uint8_t bbit2 : 1;
    uint8_t bbit3 : 1;
    uint8_t bbit4 : 1;
    uint8_t bbit5 : 1;
    uint8_t bbit6 : 1;
    uint8_t bbit7 : 1;
    } SBitfieldByte;
    zdefiniować makro rzutowania w stylu:
    #define BitfieldCast(Sfr,Bitx) (((volatile SBitfield*)&Sfr)->bbit ## Bitx)

    i przerzutować sobie bity w porcie. ??
  • VIP Zasłużony dla elektroda
    Po 1: kolejność bitów w strukturze bitowej zależy od kompilatora - może sobie ustawiać jak chce.
    Po 2: na 99% kompilator nie wygeneruje Ci z tego instrukcji sbi czy cbi, tylko odczyt lds, zmianę i zapis sts (albo jeszcze lepiej, bo przez wskaźnik Z). Szkoda zachodu.

    Edit: sprawdziłem - dostęp przez wskaźnik Z:
    Code:
        BitfieldCast(PORTB,1) = 1;
    
      5a:   e8 b3           in      r30, 0x18       ; 24
      5c:   f0 e0           ldi     r31, 0x00       ; 0
      5e:   80 81           ld      r24, Z
      60:   82 60           ori     r24, 0x02       ; 2
      62:   80 83           st      Z, r24


    Jeśli bardzo chcesz, to lepszym wyjściem będzie zadeklarowanie statycznego obiektu w c++, na którym będziesz mógł wykonywać operacje. Masz dużo większe szanse na wygenerowanie optymalnego kodu niż przy rzutowaniu na strukturę :)

    Pozdrawiam,
    Dr.Vee
  • Poziom 18  
    avrGcc realizuje to poprawnie. optymalizuje dla -O różnego od 0 i tam gdzie może upycha SBI i CBI. już sprawdziłem dlatego dałem moją propozycję. Sam rozpoznaje w której strefie adresów jest zmieniany rejestr i zgodnie z tym optymalizuje.




    A odnośnie jeszcze przekazania stałych wartości. Jeśli definiuję proste stałe na zasadzie etykieta wartość, ew proste typu etykieta (wartosc>>x) to przechodzi.
    niestety przy złożonych wyliczeniach wywala z powodu niekompatybilności typu błąd przy przekazaniu stałej do asm-a. w definicji stosowałem rzutowanie i przy wartości wyszczególnionej jako parametr dla asm też dawałem rzutowanie i kicha. Jak to obejść?
  • VIP Zasłużony dla elektroda
    Pokaż (minimalny) kod - definicje i wstawkę.

    Pozdrawiam,
    Dr.Vee