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 :-)
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.
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 }
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"
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.
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.
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.
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.
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.
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.
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).
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; }
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
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.
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ć :-)
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.