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

AVR-GCC i wolne rejestry, szybkie przerwanie od timera.

Aro_ 26 Gru 2007 10:22 1770 8
  • #1 26 Gru 2007 10:22
    Aro_
    Poziom 15  

    Witam,
    Musze zrobic szybkie przerwanie od timera w atmega162. W związku z tym nie moge sobie pozwolic na korzystanie z pamięci SRAM i stosu, więc zostają tylko rejestry, wystarczą 3, w tym dwa wskaźnikowe np. X. No więc w właściwym programie te rejesrty nie mogą byc użyte, ani modyfikowane. Czy da się to zrobic w AVG-GCC? Przepisywanie dużego fragmentu kodu na asembler mi nie odpowiada. Może jest jakiś rejestr, którego kompilator wogóle nie używa? R1 niestety odpada ze względu na procedury mnożenia.

    0 8
  • #2 26 Gru 2007 12:22
    trol.six
    Poziom 31  

    Pisząc w C to nie masz gwarancji co na końcu zrobi kompilator.

    Możesz przypisać zmienne do rejestru:

    Code:
    register unsigned char zmienna asm("r2");


    Ale to co sie potem stanie zależy od kompilatora. Mi w wersji 3.4 robił troche badziewia, ze względu na optymalizacje, i nie możność stosowania tej zmiennej jako volatile, Ponoć generowany kod miał sie poprawić w wersji 4.2

    Ale jak braknie kompilatorowi rejestrów, to i tak twoja zmienna wyląduje w SRAM

    A co do ewentualnych stosów, to nie wiem jak zmienić ewentualną procedure odkładania zmiennych na stos przy przerwaniu. Bo czasem rzeczywiście jest to niepotrzebne. A to dodatkowe kilka taktów.

    0
  • #3 26 Gru 2007 21:23
    Aro_
    Poziom 15  

    Jeśli chodzi o samo przerwanie to wywoływane jest oczywiście z atrybutem naked, i całe będzie w asemblerze. Natomiast napisanie kilku KB kodu jako wstawka asemblerowa kompatybilna do reszty programu wyprowadziłoby mnie z równowagi. Wystarczy jak piszę większy algorytm w asemblerze (jako wstawka w C) to i tak wywala sporo błędów, nad którymi mecze się potem całymi dniami.
    Co do przypisywania zmiennym rejestrów to raczej nie przyniesie oczekiwanego efektu, ponieważ kompilator i tak będzie korzystac z pomocniczych rejestrów. Może jednak jest jakis trik pozwalający kompilatorowi ograniczyc ich liczbę. Przecież gdzieś jest zapisane że AVR posiada 32 rejestry. Chyba to nie jest na sztywno w kodzie kompilatora, skoro tym samym kompilatorem można tworzyc dla różnych platform? Nie znam sie na tym zbytnio.
    Jedyną wadą byłoby wtedy ograniczenie ich liczby dla całego programu, ale te 3 rejestry mniej to chyba jakoś ujdzie.

    0
  • #4 27 Gru 2007 12:02
    szelus
    Specjalista - Mikrokontrolery

    Aro_ napisał:

    Co do przypisywania zmiennym rejestrów to raczej nie przyniesie oczekiwanego efektu, ponieważ kompilator i tak będzie korzystac z pomocniczych rejestrów.


    Hmm, nie wiem co masz na myśli? Stosowałem skutecznie technikę wkazaną przez trol.six do zoptymalizowania kodu na tiny2313 (pod gcc 3.4.5), zajmując jeden z rejestrów indeksowych (bodaj Y - r28, r29) jako globalny wskaźnik na strukturę ze zmiennych globalnych. Działało jak najbardziej poprawnie. Kilka uwag:

    1. Taka deklaracja (globalnej zmiennej rejestrowej) musi być widoczna we wszystkich kompilowanych plikach, w tym w bibliotekach. :!: Jeżeli używasz np. avr-libc to musisz ją odpowiednio zmodyfikować i przekompilować.

    2. Może być przydatna opcja -fomit-frame-pointer (podana jawnie).

    3. Zajmowanie rejestru indeksowego na globalny wskaźnik wygląda trochę dziwnie w kodzie, ale działa poprawnie (rezerwuje parę rejestrów):
    Code:

    register struct costam * pCostam asm("r28");

    0
  • #5 27 Gru 2007 12:56
    Aro_
    Poziom 15  

    :)Przepraszam, troche inaczej zrozumiałem to przypisywanie. Masz rację, to się sprawdzi, zresztą zobaczę dopiero jak to wygląda w praktyce.
    A to znaczy, że jak użyję jakieś bibliotecznej funkcji to nie weźmie pod uwagę register unsigned char zmienna asm("r2"); ? Czyli jak avr-libc trzeba zmodyfikowac?
    To tak na boku, bo i tak będę używał tylko avr/io i avr/pgmspace w tym fragmencie kodu.

    0
  • #6 27 Gru 2007 13:19
    szelus
    Specjalista - Mikrokontrolery

    Aro_ napisał:

    A to znaczy, że jak użyję jakieś bibliotecznej funkcji to nie weźmie pod uwagę register unsigned char zmienna asm("r2"); ? Czyli jak avr-libc trzeba zmodyfikowac?
    To tak na boku, bo i tak będę używał tylko avr/io i avr/pgmspace w tym fragmencie kodu.


    Nie chodzi o fragment, chodzi o całość! Choć nieprecyzyjnie się wyraziłem.

    Zobacz, jeżeli w czasie kompilacji biblioteki (lub innego fragmentu programu w oddzielnym pliku) kompilator nie zostanie poinformowany o zarezerwowaniu rejestru, to będzie miał pełne prawo użyć go np. jako rejestru pomocniczego przy obliczaniu wyrażeń. Jeżeli ten globalny rejestr jest jednym z rejestrów, które funkcja ma obowiązek przechować, to teoretycznie nie ma problemu, bo kompilator go przechowa (np. na stosie) na czas jego użycia. O ile pamiętam, kompilator zgłasza co najmniej ostrzeżenie w przypadku próby użycia na globalną zmienną rejestrową rejestru z grupy nie przechowywanej przez funkcje (np. r0, r24 - o ile pamiętam, nie udało mi się nigdzie znaleźć dokładnej listy dla AVR).

    Ale w Twoim przypadku jest inaczej. Chcesz użyć tego rejestru w przerwaniu bez przechowywania jego zawartości, czyli chciałbyś zabronić kompilatorowi używania tego rejestru wogóle. Jedynym, znanym mi sposobem uzyskania tego efektu, przynajmniej dla gcc 3.4, jest zadeklarowanie globalnej zmiennej rejestrowej w każdym pliku .c, w tym w bibliotekach. Oczywiście, najlepiej przez umieszczenie deklaracji w headerze.

    0
  • #7 27 Gru 2007 18:36
    Aro_
    Poziom 15  

    ehh, zapomniałem napisac, że przerwanie będzie aktywne tylko podczas wykonywania tego właśnie fragmentu kodu, a więc reszta programu będzie mogła do woli korzystac ze wszystkich rejestrów. Wtedy wystaczy zadeklarowac chyba tylko zmienną jako static dostępną tylko w tej funkcji? (chociaż jeszcze nie wiem czy uda mi sie zrobic z tego funkcję).

    0
  • #8 28 Gru 2007 11:09
    szelus
    Specjalista - Mikrokontrolery

    Aro_ napisał:
    ehh, zapomniałem napisac, że przerwanie będzie aktywne tylko podczas wykonywania tego właśnie fragmentu kodu, a więc reszta programu będzie mogła do woli korzystac ze wszystkich rejestrów.

    W takim wypadku oczywiście wystarczy rezerwacja tylko w tym fragmencie.

    Aro_ napisał:

    Wtedy wystaczy zadeklarowac chyba tylko zmienną jako static dostępną tylko w tej funkcji?


    Chyba nie. Z rozdziału "Specifying Registers for Local Variables":
    Cytat:

    Defining such a register variable does not reserve the register; it remains available for other uses in places where flow control determines the variable's value is not live.

    Sądząc z opisu jest to chyba mało przydatna opcja gcc.

    Ale możesz chyba cały ten fragment umieścić w oddzielnym pliku źródłowym i dodać deklarację tylko tam.

    0
  • #9 28 Gru 2007 14:25
    Aro_
    Poziom 15  

    Przy zadeklarowaniu jako globalna wartośc kompilator posłusznie jej nie stosuje, jednak zadeklarowanie w funkcji nie przynosi żadnego efektu, tak jakby tej zmiennej wogóle nie było. Więc rozwiązanie jest jedno, umiescic ten fragment w osobnym pliku, no ewentualnie zrezygnowac z rejestru w całym programie.
    Dzięki Wam za pomoc!

    Dodano po 1 [godziny] 19 [minuty]:

    Ehh, jednak nie do końca, po skompilowaniu nadal są jeszcze w niektórych miejscach używane te rejestry.
    Czy to wina funkcji bibioltecznych? zadeklarowałem we wszystkich plikach źródłowych zminenna globalna na R23, i kompilator używa go niestety podczas dzielenia. Rejestrów 28 i r29 zadeklarowanych jako wskaźnik globalny używa tylko na starcie, a potem już ich nie rusza.

    0