eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.misc.elektronikaC vs. ASM na przykładzie PIC18FC vs. ASM na przykładzie PIC18F
  • Path: news-archive.icm.edu.pl!agh.edu.pl!news.agh.edu.pl!news.cyf-kr.edu.pl!news.nask
    .pl!news.nask.org.pl!news.internetia.pl!not-for-mail
    From: Sylwester Łazar <i...@a...pl>
    Newsgroups: pl.misc.elektronika
    Subject: C vs. ASM na przykładzie PIC18F
    Date: Sat, 5 Apr 2014 05:20:27 +0200
    Organization: Netia S.A.
    Lines: 221
    Message-ID: <lhntl8$u3a$1@mx1.internetia.pl>
    NNTP-Posting-Host: 77-253-141-36.adsl.inetia.pl
    Mime-Version: 1.0
    Content-Type: text/plain; charset="iso-8859-2"
    Content-Transfer-Encoding: 8bit
    X-Trace: mx1.internetia.pl 1396668904 30826 77.253.141.36 (5 Apr 2014 03:35:04 GMT)
    X-Complaints-To: a...@i...pl
    NNTP-Posting-Date: Sat, 5 Apr 2014 03:35:04 +0000 (UTC)
    X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2615.200
    X-Tech-Contact: u...@i...pl
    X-Newsreader: Microsoft Outlook Express 5.00.2615.200
    X-Priority: 3
    X-Server-Info: http://www.internetia.pl/
    X-MSMail-Priority: Normal
    Xref: news-archive.icm.edu.pl pl.misc.elektronika:662303
    [ ukryj nagłówki ]

    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


Podziel się

Poleć ten post znajomemu poleć

Wydrukuj ten post drukuj


Następne wpisy z tego wątku

Najnowsze wątki z tej grupy


Najnowsze wątki

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: