eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.misc.elektronika › C vs. ASM na przykładzie PIC18F
Ilość wypowiedzi w tym wątku: 58

  • 1. Data: 2014-04-05 05:20:27
    Temat: C vs. ASM na przykładzie PIC18F
    Od: Sylwester Łazar <i...@a...pl>

    Tak jak opisałem wcześniej, przygotowałem procedurę, która sortuje mi
    kilka napięć metodą zliczania:
    http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php

    Jako, że ostatnio toczą się dyskusje o kompilatorach C,
    pozwoliłem sobie zrobić prosty test.

    Napisałem procedurę w ASM i w C.
    Oczywiście obie działają poprawnie.
    1) Objętość kodu ma się następująco (dla otymalizacji Debug):
    470 bajty kodu w C
    128 bajty kodu w ASM
    3,67x więcej w C
    Poniżej wklejam oba kody.
    Kodu w C po kompilacji z oczywistych względów nie wklejam.
    2) Testów czasowych _nie robiłem_, ale główna pętla przepisywania rekordów
    ma w asm: 20 instrukcji,
    a w C po przekompilowaniu: 121 instrukcji.
    Wygląda na to, że w C program działa jakieś 6x wolniej.
    3) Ciekawe jest, że prosta procedura, która kasuje wstępnie tablicę typu
    char,
    ma w pętli 10 rozkazów na samo kasowanie
    i 16 rozkazów na obsługę pętli.
    No i jest taka perełka:
    MOVLW 0
    ADDWFC 0xfea, F, ACCESS
    Najpierw do w wpisuje 0, a potem dodaje do rejestru 0xFEA, czyli do
    starszego bajtu FSR0H.
    Operacja kompletnie bezsensowna.
    4) Kompilator to MPLAB C18 v3.12 (demo)
    5) Po włączeniu optymalizacji "Enable on" kod zmniejszył się do 342 bajtów
    i w ten sposób współczynnik ilości bajtów C vs. ASM wyniósł: 2,67.
    Główna pętla zwiększyła się ze 121instrukcji na 182!
    Przypominam: w asm 20 instrukcji.
    Możliwe, że ma to swoje umotywowanie czasowe, ale trudno mi sobie je
    wytłumaczyć,
    skoro da się to ze spokojem przeprowadzić w 20 instrukcjach, a niech będzie,
    że i w 40,
    jeśli jakiś student by się pokusił o nieoptymalne napisanie kodu.
    Ale 182 to już gruba przesada.

    Wnioski:
    1) Wydaje mi się, że takie wyniki to porażka, jeśli chodzi o możliwości
    kompilatora C.
    2) Ja w swoim kodzie nie używałem żadnych sztuczek.
    Wszystkie ewentualne optymalizację, mógłby wykonać kompilator -
    mechanicznie.
    3) Być może są jakieś inne kompilatory, które potrafią wydusić z siebie coś
    więcej.
    4) Ten przykład sortował 5 liczb.
    Nie jestem w stanie sobie wyobrazić sprawnego sortowania 5000 liczb,
    pobieranych np. z pendrive'a,
    za pomocą kodu napisanego w C.
    5) Podglądnąłem też wcześniej kod po kompilacji dla 32-bitowego
    mikrokontrolera MX32. Też byłem załamany,
    ale nie analizowałem wtedy tak dokładnie, co tam za cuda się dzieją.

    --
    -- .
    pozdrawiam
    Sylwester Łazar
    http://www.alpro.pl Systemy elektroniczne.
    http://www.rimu.pl -oprogramowanie do edycji schematów
    i projektowania PCB.

    Kod w C:
    void zlicz(void);
    const char k = 7; // elementami tablicy VDIOD są liczby całkowite z
    przedziału 0..6
    const char n = 5;
    char VDIOD[5]; // tablica zawierająca elementy do posortowania
    char VDOUT[5]; // tablica zawierająca elementy posortowane
    char ADRDIOD[5][2];//tablica adresów diod
    char ADRDOUT[5][2];//tablica adresów diod po posegregowaniu
    char LICZV[5]; // zawiera liczbę elementów o danej wartości

    void main (void){
    VDIOD[0]=1;
    VDIOD[1]=2;
    VDIOD[2]=6;
    VDIOD[3]=4;
    VDIOD[4]=3;
    ADRDIOD[0][0]=1;
    ADRDIOD[0][1]=0;
    ADRDIOD[1][0]=1;
    ADRDIOD[1][1]=1;
    ADRDIOD[2][0]=1;
    ADRDIOD[2][1]=2;
    ADRDIOD[3][0]=2;
    ADRDIOD[3][1]=0;
    ADRDIOD[4][0]=2;
    ADRDIOD[4][1]=1;
    zlicz();
    }

    void zlicz(){

    char i; // zmienna pomocnicza
    char j; // zmienna pomocnicza

    for(i = 0 ; i < k ; ++i)
    LICZV[i] = 0; // zerowanie tablicy

    for(i = 0 ; i < n ; ++i)
    ++LICZV[VDIOD[i]]; // po tych operacjach LICZV[i] będzie
    zawierała
    // liczbę wystąpień elementów o kluczu i
    for(i = 1 ; i < k ; ++i)
    LICZV[i] += LICZV[i-1]; // teraz LICZV[i] zawiera pozycje w
    posortowanej
    // tablicy ostatniego elementu o kluczu i
    for(i = n-1 ; i >= 0 ; --i)
    {
    j=--LICZV[VDIOD[i]]; // aktualizacja LICZV
    VDOUT[j] = VDIOD[i]; //wstawienie elementu na odpowiednią pozycję
    ADRDOUT[j][0] = ADRDIOD[i][0]; // sortowanie adresów
    ADRDOUT[j][1] = ADRDIOD[i][1]; // sortowanie adresów
    }
    }

    Kod w asm:
    ;***************************************************
    ************************
    ;PROJEKT: TDIODA
    ;DATA: 2014-04-04
    ;PROCESOR: PIC18F2320
    ;PROCEDURA:ZLICZ
    ;PLIK:ZLICZ201446.SDA
    ;DANE WE: TABLICA NAPIĘĆ DIODY
    ;KMIN-wartość minimalna napięcia
    ;KMAX-wartość maksymalna napięcia
    ;N-liczba diod
    ;
    ;DVOLT- tablica napięć diod (1 bajt)
    ;LICZV - tablica ilości takich samych próbek napięć
    ;ADRDIOD - ADRES <PAR PORT;PIN> (2 bajty)
    ;
    ;DANE WY: posortowane obie tablica:
    ;DWOLT2
    ;ADRDIOD2
    ;OPIS:
    ;Procedura sortuje diody w kolejności rosnącego
    ;napięcia.
    ;METODA: ZLICZAJĄCA
    ;Uwagi:
    ;1) Dla dłuższych danych należy zastosować mikrokontroler 16 lub 32 lub 64
    bitowy.
    ;2) TABLICE wyników muszą następować bezpośrednio po tablicy
    nieposortowanej.
    ;np. ADRDIOD2 musi być po ADRDIOD
    ;3) pozycje tablicy numerujemy od 1
    ;4) Sortowane elementy mogą mieć maksymalnie 128 pozycji (dwubajtowe dane).
    ;Tutaj N to liczba diod.
    ;Muszą się zaczynać na adresie pamięci xx00. (ALIGNED)
    ;Trochę to bez sensu, gdyż dla N=128 pozycji to sortowanie szybkie byłoby
    szybsze.
    ; Jednak po przeniesieniu na większy uC liczba N może ulec zmianie.
    ;***************************************************
    ************************
    ;ZLICZ.
    ZLICZ
    MOVF KMIN,w ;zacznij zerować tablicę liczników od KMIN
    SUBWF KMAX,w ;oblicz rozpiętość napięć
    MOVWF COUNTER ;zapisz rozpiętość na stosie
    INCF WREG ;liczba bajtów do sumowania wystąpień o 1 większa
    MOVWF CNT ;zapisz do CNT
    LFSR 1,LICZV ;zapisz do wskaźnika początek tablicy zliczającej
    ZCLR
    CLRF POSTINC1 ;LICZV[CNT++]:=0
    DECFSZ CNT ;Czy cała tablica wyzerowana?
    BRA ZCLR ;NIE
    LFSR 1,VDIOD ;początek tablicy napięć diod
    LFSR 2,LICZV ;początek tablicy liczników wartości
    movlf NR,CNT ;ustal liczbę działań równą liczbie diod
    ZLICZN
    MOVF KMIN,w ;od każdej wartości odejmiemy KMIN
    SUBWF POSTINC1,w ;odczytaj klucz z tablicy VDIOD++[]
    INCF PLUSW2,F ;zwiększ o 1 licznik dla tego napięcia
    DECFSZ CNT ;Czy wszystkie napięcia zliczone?
    BRA ZLICZN ;NIE
    LFSR 1,LICZV ;początek tablicy liczb wartości napięć
    LFSR 2,LICZV+1 ;następna pozycja
    ZSUMUJ
    MOVF POSTINC1,w ;odczytaj poprzednią sumę
    ADDWF POSTINC2,F ;dodaj do bieżącej
    DECFSZ COUNTER ;Czy wszystkie wartości posumowane?
    BRA ZSUMUJ ;NIE
    LFSR 0,NR+VDIOD-1;koniec tablicy napięć diod
    LFSR 1,LICZV ;POCZĄTEK tablicy liczników wartości
    LFSR 2,ADRDIOD ;adres początku tablicy adresów diod
    movlf 2*NR,CNT ;ustal liczbę działań (po 2 bajty adresu) liczbie diod*2
    NEGF KMIN ;zaneguj KMIN, aby w pętli móc dodawać zamiast odejmować
    ZSORTUJ
    MOVF POSTDEC0,w ;odczytaj wartość napięcia i cofnij wskaźnik
    MOVWF VOLTAGE ;zapamiętaj bieżącą wartość napięcia
    ADDWF KMIN,w ;zrób klucz: dodaj zanegowaną wartość minimalna
    DECF PLUSW1,F ;zmniejsz ostatnią POZYCJĘ dla tego napięcia w LICZV[VOLTAGE]
    MOVF PLUSW1,w ;odczytaj nową pozycję dla tej wartości
    MULLW 2 ;zapamiętaj numer nowej pozycji*2 w rejestrze wyniku mnożenia
    ;----------------------
    ADDLW -NR ;przesuń wskaźnik do tablicy wyników VDOUT[]- musi być
    koniecznie przed ADRDIOD[]
    MOVFF VOLTAGE,PLUSW2;zapisz wartość napięcia
    VDOUT[ADRDIOD-NR+LICZV[klucz]:=VOLTAGE
    ;----------------------
    DECF CNT,F ;zmniejsz pozycję z tablicy ADRESÓW
    MOVF CNT,w ;przepisz do w
    ;-------------TUTAJ KOPIOWANIE CAŁEGO REKORDU - ODCZYT:
    MOVFF PLUSW2,BIT ;odczytaj ADRES BITU
    DECF WREG,F ;zmniejsz wskaźnik
    MOVFF PLUSW2,PORT ;odczytaj ADRES PORTU
    ;-------------TUTAJ KOPIOWANIE CAŁEGO REKORDU - ZAPIS:
    MOVF PRODL,w ;odzyskaj numer nowej pozycji
    ADDLW 2*NR ;dodanie offsetu, aby uzyskać adres tablicy wynikowej ADRDOUT
    MOVFF PORT,PLUSW2 ;zapisz ADRES BITU na nowej pozycji
    INCF WREG,F ;zmniejsz wskaźnik
    MOVFF BIT,PLUSW2 ;zapisz ADRES PORTU na nowej pozycji
    DECFSZ CNT ;Czy wszystkie wartości posortowane?
    BRA ZSORTUJ ;NIE
    NEGF KMIN ;przywróć poprawna wartość dla porządku
    RETURN



  • 2. Data: 2014-04-05 06:40:26
    Temat: Re: C vs. ASM na przykładzie PIC18F
    Od: John Smith <d...@b...pl>

    On 05-04-2014 05:20, Sylwester Łazar wrote:
    > Tak jak opisałem wcześniej, przygotowałem procedurę, która sortuje mi
    > kilka napięć metodą zliczania:
    > http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php
    >
    > Jako, że ostatnio toczą się dyskusje o kompilatorach C,
    > pozwoliłem sobie zrobić prosty test.
    >
    > Napisałem procedurę w ASM i w C.
    > Oczywiście obie działają poprawnie.
    [ciach]

    Ja bym się aż tak bardzo nie ekscytował uzyskanymi wynikami.
    CPU procesora PIC18F2320 jest 16 bitowe a Ty napisałeś program
    z pomieszaniem adresowania 8 i 16 bitowego. Nic dziwnego, że
    kompilator dodał instrukcje konwersji typów. Bądż uprzejmy
    przepisać ten program na liczby i adresowanie 16 bitowe
    i dopiero wtedy porównać uzyskane rezultaty.
    Oczywiście optymalizacja w C powinna być dla "release" a nie "debug".

    Współcześnie sprzedawane kompilatory są często generowane przez
    metakompilatory, gdyż koszta zabiłyby producenta oprogramowania.
    K.


  • 3. Data: 2014-04-05 10:02:24
    Temat: Odp: C vs. ASM na przykładzie PIC18F
    Od: Sylwester Łazar <i...@a...pl>

    > > Napisałem procedurę w ASM i w C.
    > > Oczywiście obie działają poprawnie.
    > [ciach]
    >
    > Ja bym się aż tak bardzo nie ekscytował uzyskanymi wynikami.
    Spokojnie. Wcale się nie ekscytuje. Przecież znałem z góry wynik.
    Nie spodziewałem się tylko, że mechanika, jak na "głupie" układanie kody,
    osiągnie nawet takie wyniki. Za naszego życia maszyna nie będzie lepsza od
    człowieka.


    > CPU procesora PIC18F2320 jest 16 bitowe
    No tak w połowie, bym rzekł.
    Jeśli mówisz o adresowaniu, no to rejestry FSRxH:L mają tylko 12-bitów,
    więc do 4096 może i procedura się nie zmieni zbyt wiele po kompilacji.
    O 100, może więcej instrukcji?
    Spójrz na rysunek adresowania pośredniego:
    ww1.microchip.com/downloads/en/DeviceDoc/39605b.pdf
    strona 58AR (Acrobat Reader)/56DS.

    Jak zapewne zauważyłeś, podałem w rozważaniach liczbę 5000.
    Dla 5000 to naprawdę może kompilator przygotuje coś 16 bitowego.
    Wtedy obawiam się, będzie dopiero tragedia.
    A szyna danych jest z kolei 8-bitowa.
    Jednak jeśli czytać ją z tablicy ROM to wtedy jest dopiero 16-bitowy procek.
    Trudno tak rzec jaki on właściwie jest.

    Na stronie 55(AC)/55DS Microchip podaje świetny przykład kasowania pamięci.
    Dlaczego sam go nie stosuje?
    Przecież można by go lepiej adaptować, nawet na kasowanie 16-bitowe.
    Example 5-5
    LFSR FSR0 ,0x100 ;
    NEXT
    CLRF POSTINC0 ; Clear INDF register then inc pointer
    BTFSS FSR0H, 1 ; All done with Bank1?
    GOTO NEXT ; NO, clear next
    CONTINUE ; YES,

    Oczywiście jest tutaj sprawdzany tylko przeniesienie z bitu 8 na 7 FSR,
    ale przecież kompilator mógłby sobie poukładać w pamięci tak zmienne, aby
    ostatnia kończyła się
    na adresie modulo 256.
    Przynajmniej do dwóch pętli w tym maleństwie dałoby się tak zrobić.
    Ale ja też tak nie zrobiłem u siebie, a wyszło mi to krótsze.

    > a Ty napisałeś program
    > z pomieszaniem adresowania 8 i 16 bitowego.
    Sam procesor juz pomieszany. Robiłem co mogłem.
    Ja to nawet zrobiłem to 7-bitowo.

    > Nic dziwnego, że
    > kompilator dodał instrukcje konwersji typów. Bądż uprzejmy
    > przepisać ten program na liczby i adresowanie 16 bitowe
    > i dopiero wtedy porównać uzyskane rezultaty.
    Taki szkielet. Nie widzę problemu (poza RAMem), aby go rozbudować.
    Ale to będzie walka mojej głowy z głupim metakompilatorem.
    Wynik obawiam się będzie jeszcze bardziej przerażający.
    Myślę, że Ty z łatwością byś sobie też poradził.

    > Oczywiście optymalizacja w C powinna być dla "release" a nie "debug".
    Była ALL w drugim etapie.
    Nie bawiłem się selektywnym klikaniem na checkboxy,
    bo w totolotka nie gram :-)
    Jednak nie sądzę, że przy jakiejś kombinacji da się coś uzyskać sensownego.
    > Współcześnie sprzedawane kompilatory są często generowane przez
    > metakompilatory, gdyż koszta zabiłyby producenta oprogramowania.
    > K.
    A tak zabijają nas kosztami:-)
    Myślę, że wiesz, że musiałem spędzić wielokrotnie więcej godzin nad ASM.
    W tym C to bajka - tylko kilka linijek :-)

    S.


  • 4. Data: 2014-04-05 10:10:45
    Temat: Re: C vs. ASM na przykładzie PIC18F
    Od: Marek <f...@f...com>

    On Sat, 5 Apr 2014 05:20:27 +0200, Sylwester Łazar<i...@a...pl>
    wrote:
    > 1) Objętość kodu ma się następująco (dla otymalizacji Debug):

    Zakładanie, że mniejsza objętość kodu to szybszy kod często jest
    mylne, gcc na pic32 dla optymalizacji na szybkosc generuje 3x większy
    kod niż dla optymalizacji na rozmiar.
    Oczywiście pic16 wiekszosc rozkazów robi w tym samym czasie
    zegarowym, więc teoretycznie na tej arch mniejszy z reguły będzie
    szybszy.


    > 2) Testów czasowych _nie robiłem_, ale główna pętla przepisywania
    rekordów
    > Wygląda na to, że w C program działa jakieś 6x wolniej.

    No i co z tego? To nie jest żaden argument. W programowaniu istotne
    jest ile dana implementacja kosztuje i ile czasu będzie tworzona.
    Nikt nie będzie inwestował w nieprzenośny asm jak taniej GOOTOWY już
    kod skompilować na szybszy procek.

    --
    Marek


  • 5. Data: 2014-04-05 10:15:34
    Temat: Re: C vs. ASM na przykładzie PIC18F
    Od: Marek <f...@f...com>

    On Sat, 5 Apr 2014 05:20:27 +0200, Sylwester Łazar<i...@a...pl>
    wrote:
    > 5) Po włączeniu optymalizacji "Enable on" kod zmniejszył się do 342
    bajtów

    Wyłączyłeś optymalizację _czego_? Czytając to co napisałeś ma się
    wrażenie, że kompletnie nie znasz narzędzia i nie wiesz jak je
    prawidłowo użyć.

    --
    Marek


  • 6. Data: 2014-04-05 10:25:09
    Temat: Re: C vs. ASM na przykładzie PIC18F
    Od: Marek <f...@f...com>

    On Sat, 5 Apr 2014 05:20:27 +0200, Sylwester Łazar<i...@a...pl>
    wrote:
    > Nie jestem w stanie sobie wyobrazić sprawnego sortowania 5000 liczb,
    > pobieranych np. z pendrive'a,

    Natomiast ja bardzo chętnie chciałbym takie zadanie zobaczyć napisane
    przez Ciebie w asm, o które proszę już od pół roku, założenia do
    kodu:
    - obsługa pendrive usb
    - obsługa vfat
    - sortowanie 5000 liczb ze wskazanego pliku
    - sensowny czas wykonania (krótki timetomarket) - powiedzmy tydzień

    Na marginesie, do czego sensownego może się akurat przydać sortowanie
    w 8bitowym mcu 5000 liczb... pachnie mi to znowu jak nieekonomiczne
    użycie mcu do realizacji danego zadania.

    --
    Marek


  • 7. Data: 2014-04-05 10:32:02
    Temat: Re: C vs. ASM na przykładzie PIC18F
    Od: Marek <f...@f...com>

    On Sat, 05 Apr 2014 06:40:26 +0200, John Smith <d...@b...pl>
    wrote:
    > CPU procesora PIC18F2320 jest 16 bitowe a Ty napisałeś program

    Ten proc jest 8 bit, co miałeś na myśli pisząc cpu 16 bit? 18f nie
    jest w stanie jako argument rozkazu przyjac bezpośrednio 16 bitowy
    adres docelowy lub źródłowy,.

    --
    Marek


  • 8. Data: 2014-04-05 11:01:20
    Temat: Odp: C vs. ASM na przykładzie PIC18F
    Od: Sylwester Łazar <i...@a...pl>

    > > 5) Po włączeniu optymalizacji "Enable on" kod zmniejszył się do 342
    > bajtów
    >
    > Wyłączyłeś optymalizację _czego_? Czytając to co napisałeś ma się
    > wrażenie, że kompletnie nie znasz narzędzia i nie wiesz jak je
    > prawidłowo użyć.
    >
    > --
    > Marek
    Na razie odpowiem na ten post, bo musze sprostować.
    Jednak zastanów się, czy chcesz na poważnie dyskutować, czy wpadłeś w furię.
    Wysłałeś 4 agresywne posty. Do końca dnia jeszcze możesz takich wysłać
    sporo,
    więc nie wiem czy warto...

    Co do optymalizacji.
    Zapewniam Cię, że umiem i rozumiem zaznaczać checkboxy z różnymi opcjami
    narzędzi do kompilacji kodu.
    Pomyliłem się i napisałem "Enable On", a powinno być "Enable all".
    Przepraszam.
    W każdym razie włączyłem poprawnie wszystkie opcje optymalizacji.
    I jak napisałem - nie grałem w totolotka.
    S.


  • 9. Data: 2014-04-05 11:04:59
    Temat: Re: Odp: C vs. ASM na przykładzie PIC18F
    Od: Marek <f...@f...com>

    On Sat, 5 Apr 2014 11:01:20 +0200, Sylwester Łazar<i...@a...pl>
    wrote:
    > Jednak zastanów się, czy chcesz na poważnie dyskutować, czy wpadłeś
    w furię.

    Ja jestem oceanem spokoju, bądź łaskaw porzucić osobiste uprzedzenia
    i komentować merytorycznie i na temat wątku :)

    --
    Marek


  • 10. Data: 2014-04-05 11:10:32
    Temat: Re: C vs. ASM na przykładzie PIC18F
    Od: jacek pozniak <j...@f...pl>

    Sylwester Łazar wrote:

    > Tak jak opisałem wcześniej, przygotowałem procedurę, która sortuje mi
    > kilka napięć metodą zliczania:
    > http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php
    >
    > Jako, że ostatnio toczą się dyskusje o kompilatorach C,
    > pozwoliłem sobie zrobić prosty test.
    >
    > Napisałem procedurę w ASM i w C.
    > Oczywiście obie działają poprawnie.
    > 1) Objętość kodu ma się następująco (dla otymalizacji Debug):
    > 470 bajty kodu w C
    > 128 bajty kodu w ASM
    > ...
    To ja podam wyniki kompilacji Twojego kodu:

    1. Kompilator HiTech 8.05PL2 -O -Zg, procesor pic16f876A:
    149 words(słów, nie bajtów) ROM, 38 bytes RAM
    bez funkcji zlicz(), odpowiednio 54 słów ROM, 35 RAM

    2. Kompilator HiTech 9.63PL2 --opt=ALL , procesor pic18f252:
    284 bytes ROM, 37 RAM
    bez funkcji zlicz(),75 bytes ROM, 15 bytes RAM

    3. Kompilator XC8, ver 1.3 --opt=ALL (60-dniowa) procesor pic18f252: nie
    wiem do końca, ćzy jest właczone MODE PRO niby w ciągu 60 dni powinno być
    właczone ale coś kod zbyt duży wychodzi):
    606 bytes ROM, 43 RAM
    bez funkcji zlicz() 160 ROM, 35 RAM

    4. AVR-GCC na atmega32 -O2 (nie znam jeszcze dokładnie avr-gcc i jego opcji)
    376 ROM, 37 RAM
    bez funkcji zlicz() 222 ROM, 37 RAM

    Wśród PICów jaki widać zwycięzcą jest 8.05 na PIC16.

    jp

strony : [ 1 ] . 2 ... 6


Szukaj w grupach

Szukaj w grupach

Eksperci egospodarka.pl

1 1 1

Wpisz nazwę miasta, dla którego chcesz znaleźć jednostkę ZUS.

Wzory dokumentów

Bezpłatne wzory dokumentów i formularzy.
Wyszukaj i pobierz za darmo: