Odp: C vs. ASM na przykładzie PIC18F

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.

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.

Sam procesor juz pomieszany. Robiłem co mogłem. Ja to nawet zrobiłem to 7-bitowo.

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ł.

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.

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.

Reply to
Sylwester Łazar
Loading thread data ...

Dzięki. Mam mieszane uczucia. Napracowałeś się, przekompilowałeś i mamy fajne dane. Teraz tak. Ten PIC, który wybrałeś dla pkt.1 to 16F, a nie 18F. Różnica jest taka, że on ma 14bitów długość rozkazu, więc tam w bajtach nie mozna porównywać. Słusznie napisałeś, że po kompilacji ma 149 _słów_. Mój w ASM ma 71 słów na 18F. na 16F miałby o 10 słów więcej, gdyż 16F nie ma rozkazów LFSR,MOVFF i NEGF. Czyli 81 słów vs. 149 słów, czyli współczynnik C/ASM=1,8.

Całkiem nieźle, jeśli chodzi o nadmiarowość kodu. Jednak jak powiedziałem - nie mierzyłem czasu, więc nie są te badania obiektywne, co do czasu wykonywania. Ja podałem ok. 6x wolniejszy, ale to tylko szacunek. Podaj może ilość rozkazów w głównej pętli sortującej, lub umieść kod to policzymy. S.

Reply to
Sylwester Łazar

Tutaj muszę sprostować. Oczywiście 182 bajty. Nie instrukcje. No i dodatkowo okazało się, że jest jeszcze więcej, bo coś około 218 bajtów W każdym razie, w poniższej pętli jest zawartych 94 instrukcji ASM 18F, co odpowiada 20 instrukcjom w kodzie pisanym bezpośrednio w ASM.

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 }

Przepraszam, za pomyłkę. S.

Reply to
Sylwester Łazar

Sylwester Łazar wrote:

Podaj proszę ile ma Twoja funkcja zlicz() w ASM napisana, ponieważ podałem wynik kompilacji z i bez niej. Kompilator pewnie dorzuca jakiś extra kod jako startup.obj.

Ja jedynie mogę wklaić wynik kompilacji z opcją -S: global ?a_zlicz global _ADRDIOD global _ADRDOUT global _LICZV global _VDIOD global _VDOUT global _k global _main signat _main,88 FNCALL _main,_zlicz global _n global _zlicz signat _zlicz,88 FNSIZE _zlicz,2,0 global clear_bank0 global start global used_btemp0 processor 16F876A psect __Z08170RS_,global psect text0,local,class=CODE,delta=2 psect text1,local,class=CODE,delta=2 psect strings,global,class=STRING,delta=2 psect const1,local,class=CONST,delta=2 psect const2,local,class=CONST,delta=2 psect rbss_0,global,class=BANK0,space=1 psect temp,global,ovrld,class=BANK0,space=1 file "C:\users\jacek\Temp\_8.AAB"

psect __Z08170RS_

psect text0 _main ;main5.c: 16: VDIOD[0]=1; bcf 3,5 bcf 3,6 ;carry unused clrf _VDIOD incf _VDIOD ;main5.c: 17: VDIOD[1]=2; movlw 2 movwf _VDIOD+1 ;main5.c: 18: VDIOD[2]=6; movlw 6 movwf _VDIOD+2 ;main5.c: 19: VDIOD[3]=4; movlw 4 movwf _VDIOD+3 ;main5.c: 20: VDIOD[4]=3; movlw 3 movwf _VDIOD+4 ;main5.c: 21: ADRDIOD[0][0]=1; clrf _ADRDIOD incf _ADRDIOD ;main5.c: 22: ADRDIOD[0][1]=0; clrf _ADRDIOD+1 ;main5.c: 23: ADRDIOD[1][0]=1; clrf _ADRDIOD+2 incf _ADRDIOD+2 ;main5.c: 24: ADRDIOD[1][1]=1; clrf _ADRDIOD+3 incf _ADRDIOD+3 ;main5.c: 25: ADRDIOD[2][0]=1; clrf _ADRDIOD+4 incf _ADRDIOD+4 ;main5.c: 26: ADRDIOD[2][1]=2; movlw 2 movwf _ADRDIOD+5 ;main5.c: 27: ADRDIOD[3][0]=2; movwf _ADRDIOD+6 ;main5.c: 28: ADRDIOD[3][1]=0; clrf _ADRDIOD+7 ;main5.c: 29: ADRDIOD[4][0]=2; movwf _ADRDIOD+8 ;main5.c: 30: ADRDIOD[4][1]=1; clrf _ADRDIOD+9 incf _ADRDIOD+9 ;main5.c: 32: zlicz(); fcall _zlicz ;main5.c: 35: } ljmp start

psect text1 _zlicz ; _j assigned to ?a_zlicz+0 _zlicz$j set ?a_zlicz ; _i assigned to ?a_zlicz+1 _zlicz$i set ?a_zlicz+1 ;main5.c: 38: char i; clrf 3 ;select bank 0 clrf ?a_zlicz+1 goto l6 l3 movf ?a_zlicz+1,w addlw _LICZV movwf 4 bcf 3,7 clrf 0 incf ?a_zlicz+1 l6 movlw 7 subwf ?a_zlicz+1,w btfss 3,0 goto l3 ;main5.c: 42: for(i=0;i<n;++i) ++LICZV[VDIOD[i]]; clrf ?a_zlicz+1 l10 movlw 5 subwf ?a_zlicz+1,w btfsc 3,0 goto l8 movf ?a_zlicz+1,w addlw _VDIOD movwf 4 bcf 3,7 movf 0,w addlw _LICZV movwf 4 incf 0 incf ?a_zlicz+1 goto l10 l8 ;main5.c: 43: for(i=1;i<k;++i) LICZV[i]+=LICZV[i-1]; clrf ?a_zlicz+1 L1 incf ?a_zlicz+1 movlw 7 subwf ?a_zlicz+1,w btfsc 3,0 goto l12 decf ?a_zlicz+1,w addlw _LICZV movwf 4 bcf 3,7 movf 0,w movwf btemp movf ?a_zlicz+1,w addlw _LICZV movwf 4 movf btemp,w addwf 0 goto L1 l12 ;main5.c: 44: for(i = n-1 ; i >= 0 ; --i) movlw 4 movwf ?a_zlicz+1 l15 ;main5.c: 45: { ;main5.c: 46: j=--LICZV[VDIOD[i]]; movf ?a_zlicz+1,w addlw _VDIOD movwf 4 bcf 3,7 movf 0,w addlw _LICZV movwf 4 decf 0 movf 0,w movwf ?a_zlicz ;main5.c: 47: VDOUT[j] = VDIOD[i]; movf ?a_zlicz+1,w addlw _VDIOD movwf 4 movf 0,w movwf btemp movf ?a_zlicz,w addlw _VDOUT movwf 4 movf btemp,w movwf 0 ;main5.c: 48: ADRDOUT[j][0]=ADRDIOD[i][0]; movf ?a_zlicz+1,w addwf ?a_zlicz+1,w addlw _ADRDIOD movwf 4 movf 0,w movwf btemp movf ?a_zlicz,w addwf ?a_zlicz,w addlw _ADRDOUT movwf 4 movf btemp,w movwf 0 ;main5.c: 49: ADRDOUT[j][1]=ADRDIOD[i][1]; bsf 3,0 rlf ?a_zlicz+1,w addlw _ADRDIOD movwf 4 movf 0,w movwf btemp bsf 3,0 rlf ?a_zlicz,w addlw _ADRDOUT movwf 4 movf btemp,w movwf 0 ;main5.c: 50: } decf ?a_zlicz+1 goto l15

psect const1 addwf 2 _k retlw 7

psect const2 addwf 2 _n retlw 5

psect rbss_0 _LICZV ds 5 _VDIOD ds 5 _VDOUT ds 5 _ADRDIOD ds 10 _ADRDOUT ds 10

psect temp btemp ds 1

Reply to
jacek pozniak

U mnie w programi pisanym w ASM liczba instrukcji wynosi: 57 Instrukcje w głównej pętli sortującej: 20 Są 4 pętle, ale chodzi o tę ostatnią. Wydaje mi się ona najtrudniejsza dla kompilatora. Ale w innych, jak w tej pierwszej - samo zerowanie też mój kompilator C18 robi głupoty.

A teraz postaram się znaleźć i policzyć instrukcje w głównej pętli sortującej, w tym co ogłosiłeś po kompilacji.

S.

Reply to
Sylwester Łazar

W tym kompilatorze Hi-Tech 8.05PL2 główna pętla wykonuje się w 46 instrukcjach. procesor pic16f876A W tym kompilatorze MPLAB C18 v3.12 (demo) 94 instrukcji. PIC18F2320 S.

Reply to
Sylwester Łazar

Ciekawe czy to demo ma wyłączoną optymalizację czy też 'ten typ tak ma'.

jp

Reply to
jacek pozniak

Oczywiście sama główna pętla. Ta ostatnia, która sortuje. S.

Reply to
Sylwester Łazar

Ma włączoną. "MPLAB C18 v3.12 (demo) Copyright 1999-2005 Microchip Technology Inc. Days remaining until demo becomes feature limited: 56 WARNING: The procedural abstraction optimization will not be supported when the demo becomes feature limited." Czyli za 56 dni abstrakcyjna optymalizacja zostanie wyłączona. Cokolwiek to znaczy. Może zacznie działać lepiej :-)

Widać, że ten C18 jest gorszy od HI-Techa. Jednak, to że Microchip ma kiepski kompilator zauważył już dawno Zbych. Ja tylko pokazałem jak to wygląda.

Problem jest taki, że średnio też jestem zadowolony z tego kodu HI-Techa.

Nie wiem na co są pisane naprawde dobre kompilatory. Teraz zmienić procesor to nie jest duży problem. Problemem jest dobry kompilator i obawiam się, że tendencja jest taka, aby sprzedać marny produkt, a wmawia się ludziom, że czyni cuda. S.

Reply to
Sylwester Łazar

W przeszłości programowałem 51; najpierw asm potem C, miałem jakiś spiracony klucz sprzętowy na LPT do kompilatora Keil, pod DOS. A że znałem asm na 51 to porównywałem wynik kompilacji. I powiem jedno: byłem pod wielkim wrażeniem generowanego kodu, przede wszystkim jego zwartości. Obecnie chyba jedyna rozsądna droga to ewoluowanie w kierunku gcc i pochodnych nad rozwojem których pracuje z reguły więcej osób niż nad rozwiązaniami korporacyjnymi.

jp

Reply to
jacek pozniak

Ja jednak mam inne doświadczenia. To znaczy nie analizowałem kodu po tłumaczeniu. Jednak na 8051 zabrakło mi pamięci 64kB programu, przy tworzeniu oprogramowania na centralkę telefoniczną. Musiałem się mocno gimnastykować, poprawiając kod w C, aby w ogóle się zmieścić. Wyciągnąłem wtedy wniosek, że kompilator robi straszną nadbudowę. Jednak mogło być też i tak, że kod był mało optymalny. Wtedy nauczyłem się wyciskać z C dosłownie kilobajty. Doszedłem do tego, że istnieje już granica, której się nie przeskoczy. Od tego momentu wybieram, czy piszę w C, czy w asm. Jako, że człowiek jadł już z wielu piecy chleb... najczęściej wybieram ASM, gdyż nie lubię, jak na LCD widać jak obraz wczytuje się niczym w ZX Spectrum podczas wczytywania z taśmy:-)

Nie sądzę, że jedyna. Tam gdzie kupa ludzi, tam też i kupa ... błędów.

2) Wydaje mi się, że lepiej wypróbować kontakt z HI-Techem. Widać, że są tam ludzie, którzy wiedzą o co chodzi. Może im podpowiadać, czego będziemy oczekiwać. Może zechcą rozijać się w kierunku prawdziwej optymalizacji. 3) Samemu stworzyć kompilator. Jest to trudniejsze, ale jeśli się chce, to czemu nie. Skoro tworzy się swoje uC z własną listą rozkazów? 4) Jak już, to stworzyć swój procesor z instrukcjami C, które działają poprawnie. Zresztą MCHIP w 18F już dołożył kilka drobnostek do FSRów, jak FSRx++, FSRx--,++FSRx, FSRx+w. Ale to drobnostki, ograniczone i 8-bitowe. Zresztą adresowanie z przesunięciem już dawno miał INTEL.

Problem w tym, że trzeba mieć doświadczenie, a Hi-Tech (i inne też) mają wieloletnie. Dlatego opcja 2 wydaje się sensowna, jeśli zaskoczy. Ale trzeba rozmawiać z konkretnymi programistami, a nie przez "sekretarkę". Może zacząć od tego, że "Kocham Was i szanuję, chcę z Wami być, ale nie mam co od Was kupić" :-) S.

Reply to
Sylwester Łazar

Użytkownik Sylwester Łazar napisał:

A jakie to funkcje ta centralka miała? Niegdyś wystrugałem prostą centralkę na 89C52, 1 linia zew, 4 wew, LCD znakowy do monitorowania stanu, własny generator dzwonienia i dekoder DTMF. O ile pamiętam kod miał jakieś 3kB, oczywiście pisany w asm.

Reply to
AlexY

Ale robiłeś w Keilu? Bo był jeszcze IAR, który faktycznie produkował kod, delikatnie mówiąc, niezbyt optymalny.

I większa wymiana informacji, co pozwala na ich obejście, zastosowanie innego rozwiązania.

Nie sądzę, ponieważ HiTech jest chyba obecnie częścia Microchipa (vide brak kompilatorów dla innych platform) ze wszystkimi konsekwencjami, tzw. kultury korporacyjnej.

Managment w wielkiej korporacji, za cel nadrzędny stawia sobie utrzymanie się na stołkach, więc nie sądzę, żeby produkt był lepszy- raczej dodaje się więcej czynnika marketingowego (w strukturze 4*P (product,price,place,promotion).

jp

Reply to
jacek pozniak

Faktycznie IAR.

Ale chyba, skoro przejęli HiTecha, to może chcą mieć lepszy kompilator dla swoich chipów, abyśmy je kupowali. Nigdy nie wiadomo.

Na dwoje babka wróżyła. S.

Reply to
Sylwester Łazar

Na pokładzie to samo, tylko 3 linie wewnętrzne. Funkcji jednak bardzo dużo, jak budzenie, zamawianie rozmów, blokowanie kierunków, , zliczanie czasu, taryfikację, itp. To było 18 lat temu... O właśnie, widzę, że moja żona nawet tam dodała swoje procedury :-)

char getTariff(char *wcStr1) { /*funkcja napisana przez xxx*/ char str2[6] = "xxxxx\0"; int j, k, p, max; for (j=0; j<5; ++j) { str2[j] =48+ *( wcStr1+j); } max = 0; for (k=0; k<nmax; k++) { j = 0; while (str2[j] == tab[k].num[j]){ j++; } if (j > max) { max = j; p = k; } } if ((tab[p].num[max] == 'x') || (max==6)) return (tab[p].tar); else return NOTARIFF; }

S.

Reply to
Sylwester Łazar

W dniu 05.04.2014 o 18:12 Sylwester Łazar snipped-for-privacy@alpro.pl pisze:

Ok, poniżej.

tak

65

Kod:

sort.elf: file format elf32-avr

Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000166 00000000 00000000 00000094 2**1 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .data 00000002 00800060 00000166 000001fa 2**0 CONTENTS, ALLOC, LOAD, DATA 2 .bss 00000023 00800062 00800062 000001fc 2**0 ALLOC 3 .debug_aranges 00000020 00000000 00000000 000001fc 2**0 CONTENTS, READONLY, DEBUGGING 4 .debug_pubnames 00000067 00000000 00000000 0000021c 2**0 CONTENTS, READONLY, DEBUGGING 5 .debug_info 00000116 00000000 00000000 00000283 2**0 CONTENTS, READONLY, DEBUGGING 6 .debug_abbrev 000000ab 00000000 00000000 00000399 2**0 CONTENTS, READONLY, DEBUGGING 7 .debug_line 00000145 00000000 00000000 00000444 2**0 CONTENTS, READONLY, DEBUGGING 8 .debug_frame 00000030 00000000 00000000 0000058c 2**2 CONTENTS, READONLY, DEBUGGING 9 .debug_str 0000005e 00000000 00000000 000005bc 2**0 CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>: 0: 0c 94 2a 00 jmp 0x54 ; 0x54 <__ctors_end> 4: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 8: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>

c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>

10: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 14: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 18: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 1c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 20: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 24: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 28: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 2c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 30: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 34: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 38: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 3c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 40: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 44: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 48: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 4c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt> 50: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>

00000054 <__ctors_end>: 54: 11 24 eor r1, r1 56: 1f be out 0x3f, r1 ; 63 58: cf e5 ldi r28, 0x5F ; 95 5a: d8 e0 ldi r29, 0x08 ; 8 5c: de bf out 0x3e, r29 ; 62 5e: cd bf out 0x3d, r28 ; 61

00000060 <__do_copy_data>: 60: 10 e0 ldi r17, 0x00 ; 0 62: a0 e6 ldi r26, 0x60 ; 96 64: b0 e0 ldi r27, 0x00 ; 0 66: e6 e6 ldi r30, 0x66 ; 102 68: f1 e0 ldi r31, 0x01 ; 1 6a: 02 c0 rjmp .+4 ; 0x70 <.do_copy_data_start>

0000006c <.do_copy_data_loop>: 6c: 05 90 lpm r0, Z+ 6e: 0d 92 st X+, r0

00000070 <.do_copy_data_start>: 70: a2 36 cpi r26, 0x62 ; 98 72: b1 07 cpc r27, r17 74: d9 f7 brne .-10 ; 0x6c <.do_copy_data_loop>

00000076 <__do_clear_bss>: 76: 10 e0 ldi r17, 0x00 ; 0 78: a2 e6 ldi r26, 0x62 ; 98 7a: b0 e0 ldi r27, 0x00 ; 0 7c: 01 c0 rjmp .+2 ; 0x80 <.do_clear_bss_start>

0000007e <.do_clear_bss_loop>: 7e: 1d 92 st X+, r1

00000080 <.do_clear_bss_start>: 80: a5 38 cpi r26, 0x85 ; 133 82: b1 07 cpc r27, r17 84: e1 f7 brne .-8 ; 0x7e <.do_clear_bss_loop>

86: 0e 94 8b 00 call 0x116 ; 0x116 <main> 8a: 0c 94 b1 00 jmp 0x162 ; 0x162 <_exit>

0000008e <__bad_interrupt>: 8e: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>

00000092 <zlicz>: ADRDIOD[4][0]=2; ADRDIOD[4][1]=1; zlicz(); }

void zlicz(){ 92: e0 e8 ldi r30, 0x80 ; 128 94: f0 e0 ldi r31, 0x00 ; 0

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

for(i = 0 ; i < k ; ++i) LICZV[i] = 0; // zerowanie tablicy 96: 11 92 st Z+, r1 void zlicz(){

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

for(i = 0 ; i < k ; ++i) 98: 80 e0 ldi r24, 0x00 ; 0 9a: e7 38 cpi r30, 0x87 ; 135 9c: f8 07 cpc r31, r24 9e: d9 f7 brne .-10 ; 0x96 <zlicz+0x4>

a0: a2 e6 ldi r26, 0x62 ; 98 a2: b0 e0 ldi r27, 0x00 ; 0 LICZV[i] = 0; // zerowanie tablicy

for(i = 0 ; i < n ; ++i) ++LICZV[VDIOD[i]]; // po tych operacjach LICZV[i] będzie zawierała a4: ed 91 ld r30, X+ a6: f0 e0 ldi r31, 0x00 ; 0 a8: e0 58 subi r30, 0x80 ; 128 aa: ff 4f sbci r31, 0xFF ; 255 ac: 80 81 ld r24, Z ae: 8f 5f subi r24, 0xFF ; 255 b0: 80 83 st Z, r24 char j; // zmienna pomocnicza

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

for(i = 0 ; i < n ; ++i) b2: 80 e0 ldi r24, 0x00 ; 0 b4: a7 36 cpi r26, 0x67 ; 103 b6: b8 07 cpc r27, r24 b8: a9 f7 brne .-22 ; 0xa4 <zlicz+0x12>

ba: e0 e8 ldi r30, 0x80 ; 128 bc: f0 e0 ldi r31, 0x00 ; 0 ++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 be: 81 81 ldd r24, Z+1 ; 0x01 c0: 90 81 ld r25, Z c2: 89 0f add r24, r25 c4: 81 83 std Z+1, r24 ; 0x01 c6: 31 96 adiw r30, 0x01 ; 1 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) c8: a0 e0 ldi r26, 0x00 ; 0 ca: e6 38 cpi r30, 0x86 ; 134 cc: fa 07 cpc r31, r26 ce: b9 f7 brne .-18 ; 0xbe <zlicz+0x2c>

d0: 34 e0 ldi r19, 0x04 ; 4 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 d2: 83 2f mov r24, r19 d4: 90 e0 ldi r25, 0x00 ; 0 d6: fc 01 movw r30, r24 d8: ee 59 subi r30, 0x9E ; 158 da: ff 4f sbci r31, 0xFF ; 255 dc: 20 81 ld r18, Z de: a2 2f mov r26, r18 e0: b0 e0 ldi r27, 0x00 ; 0 e2: a0 58 subi r26, 0x80 ; 128 e4: bf 4f sbci r27, 0xFF ; 255 e6: ec 91 ld r30, X e8: e1 50 subi r30, 0x01 ; 1 ea: ec 93 st X, r30 VDOUT[j] = VDIOD[i]; //wstawienie elementu na odpowiednią pozycję ec: f0 e0 ldi r31, 0x00 ; 0 ee: df 01 movw r26, r30 f0: a5 58 subi r26, 0x85 ; 133 f2: bf 4f sbci r27, 0xFF ; 255 f4: 2c 93 st X, r18 ADRDOUT[j][0] = ADRDIOD[i][0]; // sortowanie adresów f6: ee 0f add r30, r30 f8: ff 1f adc r31, r31 fa: e9 59 subi r30, 0x99 ; 153 fc: ff 4f sbci r31, 0xFF ; 255 fe: 88 0f add r24, r24 100: 99 1f adc r25, r25 102: 8f 58 subi r24, 0x8F ; 143 104: 9f 4f sbci r25, 0xFF ; 255 106: dc 01 movw r26, r24 108: 2c 91 ld r18, X 10a: 20 83 st Z, r18 ADRDOUT[j][1] = ADRDIOD[i][1]; // sortowanie adresów 10c: 11 96 adiw r26, 0x01 ; 1 10e: 8c 91 ld r24, X 110: 81 83 std Z+1, r24 ; 0x01 ++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) 112: 31 50 subi r19, 0x01 ; 1 114: de cf rjmp .-68 ; 0xd2 <zlicz+0x40>

00000116 <main>: 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; 116: 91 e0 ldi r25, 0x01 ; 1 118: 90 93 62 00 sts 0x0062, r25 VDIOD[1]=2; 11c: 22 e0 ldi r18, 0x02 ; 2 11e: 20 93 63 00 sts 0x0063, r18 VDIOD[2]=6; 122: 86 e0 ldi r24, 0x06 ; 6 124: 80 93 64 00 sts 0x0064, r24 VDIOD[3]=4; 128: 84 e0 ldi r24, 0x04 ; 4 12a: 80 93 65 00 sts 0x0065, r24 VDIOD[4]=3; 12e: 83 e0 ldi r24, 0x03 ; 3 130: 80 93 66 00 sts 0x0066, r24 ADRDIOD[0][0]=1; 134: 90 93 71 00 sts 0x0071, r25 ADRDIOD[0][1]=0; 138: 10 92 72 00 sts 0x0072, r1 ADRDIOD[1][0]=1; 13c: 90 93 73 00 sts 0x0073, r25 ADRDIOD[1][1]=1; 140: 90 93 74 00 sts 0x0074, r25 ADRDIOD[2][0]=1; 144: 90 93 75 00 sts 0x0075, r25 ADRDIOD[2][1]=2; 148: 20 93 76 00 sts 0x0076, r18 ADRDIOD[3][0]=2; 14c: 20 93 77 00 sts 0x0077, r18 ADRDIOD[3][1]=0; 150: 10 92 78 00 sts 0x0078, r1 ADRDIOD[4][0]=2; 154: 20 93 79 00 sts 0x0079, r18 ADRDIOD[4][1]=1; 158: 90 93 7a 00 sts 0x007A, r25 zlicz(); 15c: 0e 94 49 00 call 0x92 ; 0x92 <zlicz>

} 160: 08 95 ret

00000162 <_exit>: 162: f8 94 cli

00000164 <__stop_program>: 164: ff cf rjmp .-2 ; 0x164 <__stop_program>

Reply to
janusz_k

Dzięki. Dobra robota. Podoba mi się ten ATMEGA32 (jak na 8-bitowca) Ma fajne instrukcje:

1) MOVW Rd, Rr Copy Register Word Rd+1:Rd ← Rr+1:Rr w jednym cyklu! 3x jej używają w naszym programie testowym. Nie dziwię się. Tego brakuje w PIC. 2) LDI Rd, K Load Immediate Rd ← K 14x jej używają Też w jednym cyklu do dowolnego rejestru. Tez brakuje w PICu. Wszystko przez WREG trzeba przenosić. 3)CPI Rd,K Compare Register with Immediate Rd − K 3x użyta Też w jednym cyklu. Też brakuje w PICu. 4) CPC Rd,Rr Compare with Carry Rd − Rr − C 3x użyta. Też występuje w jednym cyklu. Zdaje się, że tak fajnie można porównać w 4 instrukcjach 2bajtową liczbę. ldi r26, 0x00 ; 0 cpi r30, 0x86 ; 134 cpc r31, r26 brne .-18 ; 0xbe <zlicz+0x2c>

Szkoda tylko, że nie ma takiego porównania cpc ze stałą i tutaj musiał załadować najpierw do r26 zero. W PIC18 jest CPFSEQ, która ze skokiem wykonuje się w 3 cyklach, ale też trzeba załadować do w stałą i też tylko jeden bajt, a nie słowo. Ach te ośmiobitowce :-(

5)MOV Rd, Rr Move Between Registers Rd ← Rr 5x występuje Też w jednej instrukcji i też fajne. PIC18 ma MOVFF, ale trwa 2 cykle, czyli identycznie, jak w PIC16 MOVF R1,w MOVWF R2 tyle, że nie używa w.

---------------------------------- Podsumowując:

1) Kod wygląda dość ciekawie, ale coś mi się zdaje, że można to jeszcze skrócić przynajmniej do 45 instrukcji z takim zestawem rozkazów. 2) rozkazy korzystające z indeksów trwają zawsze 2 cykle np. LD Rd, Z Load Indirect Rd ← (Z) 3) pętla główna sortowania zajmuje aż 34 rozkazy. 8 rozkazów 2 cyklowych 26 rozkazów 1 cyklowych czyli 26+2*8=26+16=42 cykle

4) Ja mam w ASM na PIC18F 20 instrukcji w pętli. I tak:

6 wykonujących się w 2 cyklach 14 wykonujących się w 1 cyklu. Co daje mimo bardziej ubogiej listy rozkazów 14+2*6=14+12=26cykli

W cyklach wychodzi C/ASM= 42/26=1,62 Całkiem nieźle jak na razie. Nawet nie dwukrotna nadbudowa.

5) ATMEGA32 może pracować, jak dobrze wyczytałem @16MHz z czasem jednego cyklu: Tcy=1/16=62,5ns. Daje to obieg pętli: 42*62,5=2,625us Dla PICa 18F2320 @40MHz Tcy=1/40*4=100ns Daje to obieg pętli: 26*100= 2,6us

I to jest ciekawa sprawa. ================================================== ATMEGA32 z kompilatorem C (nie wiem jaka wersja?) Avr studio4 Wykonuje tą samą funkcję, którą napisałem w ASM na PIC18 mniej więcej w tym samym czasie! Sukces polega zapewne na tym, że ATMEGA32 wydaje się dość zgrabnym maleństwem, a kompilator korzysta z listy rozkazów dość logicznie. Oba procki mają tylko 3 rejestry indeksowe. Jeden więcej byłby w tym przypadku pomocny. ATMEGA32 jakieś 12-15 zł PIC18F2320 jakieś 20 -28 zł Polecam ATMEGA32 w takim razie, zarówno do pracy w ASM jak i w C. Choć zaznaczam, że na ATMEGA32 kawałka kodu jeszcze nie napisałem w ASM :-) Jednak, 8-bitowce to marne są, więc jeśli już lepiej to takiego 32MX220F032B-50ISP za 8 zł. ================================================== Uwaga: Co prawda jeszcze nie mówiłem, że ten mój kod w ASM vs. C ma automatyczne odliczanie najmniejszej wartości KMIN, w celu zmniejszenia rozmiaru tablicy zliczającej. Ale to myślę, że jakieś 5-15% szybkości może zabrać w ASM.

Bardzo dziękuję Janusz. Podaj proszę jeszcze typ kompilatora, wersję i może jakiegoś linka do tego AVRSTUDIO i kompilatora (demo?) Może się komuś przyda. S.

Reply to
Sylwester Łazar

W dniu 2014-04-05 23:19, Sylwester Łazar pisze:

Ja bym go nie polecał bo ten procek znika z rynku. Jeśli już to jakiś zamiennik np Atmega328. A tak w ogóle po co kupować 8 bitowy procek z

1kB RAM za 12-15 zł gdy można kupić 32 bitowy z 8kB RAM za 7 zł?
formatting link
Reply to
Mario

formatting link
--

Z tych dwóch. Poniżej napisałem o 32 bitowym 32MX2xx. O.K. Wygląda, że 8-bitowce się kończą. Ale zawsze mogą służyć za PORT EXPANDER. Jeśli będzie w cenie takiej co CD4094, to można kupić takiego 8-bitowca i jeszcze sobie, do płytki piny dostosować :-)

S.

Reply to
Sylwester Łazar

Jeszcze jakby kogoś interesowało, to podaję link do algorytmu w asm:

formatting link

Reply to
Sylwester Łazar

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.