[#1] Asembler for dumies - czyli pytania poczatkujacego
Jako ze wczesniej znalem tylko asm Z80 i 8051, to obecnie chcialbym sie blizej przyjrzec aseblerowi 68k. Poczytalem troche literatury na ten temat i troszeczeke mi sie rozjasnilo jednak kilka niejasnosci pozostalo. Dlatego otwieram watek na temat porad z tym zwiazanych. Odrazu uprzedzam ze posty typu "a po co ci to" , "tego juz nikt nie uzywa" itp mozecie sobie odpuscic.

Ja swoja nauke zaczalem troszeczke od innej strony: swoje obecne produkcje przegladam przez deasemblacje i przygladanie sie "jak to kompilator zrobil"

Moja uwage przykul jeden fragment, w C on wyglada tak:

for(; x1 < x2; x1++)
{
*wskaznik++ = zmienna;
}

kompilator przeksztalcil to na cos takiego:

skok:
MOVE.L D1, D0
MOVE.B DO, (A5)+
ADDQ #1, D7
CMP.L D6, D7
BLT.B skok

Ja zdaje sobie sprawe ze z kompilatorem nie ma sie zbytnio co klucic "bo wie lepiej", jednak czy teoretycznie skok nie powinien sie odbyc do linii drugiej? Sprobowalem to sprawdzic na swoj sposob i przekierowalem recznie skok (majstrujac w hexie) do tej linijki jednak nie przynioslo to spodziewanego rezultatu. Wygladalo to tak jakby rejestr D0 zostal wyzerowany.
Dlatego moje pytanie brzmi: czy instrukacja MOVE.B Dn, (An)+ kasuje rejestr Dn?
[#2] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #1

Nie, nie kasuje. Instrukcja ta przesyła bajt z rejestru Dn pod adres z rejestru An i zwiększa ten adres o jeden.
[#3] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #1

Dlatego moje pytanie brzmi: czy instrukacja MOVE.B Dn, (An)+ kasuje rejestr Dn?


Nie. Modyfikuje rejestr An oraz zawartość pamięci pod adresem wskazywanym przez An.

Moim zdaniem zaszedł jeden z dwóch wariantów:
- po prostu D1 służy w tym przypadku do przechowania zmiennej "zmienna", zaś D0 to roboczy rejestr służący do kopiowania bądź,
- zachodzi rzutowanie z typu long do char i tak kompilator radzi sobie z taką sytuacją.

Mam pytanie: jakiego to kompilatora C używasz? Bo kod jest bardzo ładny.
[#4] Re: Asembler for dumies - czyli pytania poczatkujacego

@Hexmage960, post #3

#2, #3

Moze zle zadalem pytanie, co robi ta instrukcja to wiem, tyle ze nie wiedzialem co sie dzieje z rejestrem D0.

Faktycznie "wsakaznik" jest zdefiowany jako UBYTE, a "zmienna" jako int, wiec rzutowanie jakies zachodzi. Jednak "zmienna" nigdy nie bedzie wieksza niz 255.

A co do kompilatora to uzywam Sas C.

Ostatnia aktualizacja: 05.05.2014 19:12:24 przez Phibrizzo
[#5] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #4

Dn po tej operacji zostaje takie jak przed transferem. Jeśli było 5 to będzie 5.
[#6] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #1

Moze dla pelnej jasnosci przedstawie to co pokazalo po deasemblacji:

0616 2001 MOVE.L D1,D0
0618 1AC0 MOVE.B D0,(A5)+
061A 5287 ADDQ.L #1,D7
061C BE86 CMP.L D6,D7
061E 6DF6 BLT.B 0616

Z ciekawosci wlasnie zamienilem ostatnia wartosc na $6DF8.
[#7] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #1

Czy mógłbyś zamieścić kompilowalny fragment, najlepiej jako funkcję. Dzięki, ułatwi to identyfikacje, gdzie jest problem, bo dobrze przekierowałeś ręcznie skok i powinno działać dobrze to co zrobiłeś. Dobrze by było byś opisał co ta funkcja ma robić, własnymi słowami.
[#8] Re: Asembler for dumies - czyli pytania poczatkujacego

@Hexmage960, post #3

Chyba troche przesadziles, ze to jest ladny kod, co najwyzej przecietny.
Ta petla, ktora ma cztery instrukcje jako skompilowana w C, moze miec tylko
dwie instrukcje w wersji ASM, czyli strata parudziesciu procent mocy procesora
na bardzo prostej procedurze.

A wracajac do tematu, to sprawdz czy jak zamienisz
move.b D0,(A5)+
na
move.b D1,(A5)+ ($1AC1)
to zadziala lepiej. Byc moze ta petla jest wykonywana przez skok
do offsetu $061C albo $061A, a nie leci po kolei, bo kompilatory
tak juz czesto maja, ze proste rzeczy komplikuja (stad chyba zreszta
ich nazwa).
[#9] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #1

D0 zawiera D1, tylko liczy sie pierwsze 8bitow (MOVE.B) - nalezy zauwazyc. Dziwna petla, pierwsza linia zbedna, ale kompilatory tak juz maja, zreszta calosc mozna zapisac jeszcze optymalniej.
[#10] Re: Asembler for dumies - czyli pytania poczatkujacego

@Don_Adan, post #8

Po prostu widziałem gorszy. Kompilator niestety nie zrobi za człowieka optymalizacji, może co najwyżej próbować To jak gra w szachy, komputer nie ma tego czegoś...
[#11] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #1

W przypadku tak zbudowanej pętli zdaje się że kompilator zrobił dobrze.
A jakby dało się przekształcić to w coś takiego:
x = ilosc_petli;
do {
*wskaznik++ = wartosc;
x--;
} while(x != 0);

to powinno być lepiej/szybciej. W zależności od wartości parametrów dla tej pętli można pokusić się o dalszą optymalizację.

Nie warto zwalać winy na kompilator, za to warto optymalizować algorytmy.
[#12] Re: Asembler for dumies - czyli pytania poczatkujacego

@tygrys, post #11

Ale chyba nie o to chodzi w tym wątku jak zmusic kompilator do generowania lepszego kodu;)
[#13] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #4

Mógłbyś polecić jakieś środowisko dla sasc.
[#14] Re: Asembler for dumies - czyli pytania poczatkujacego

@asman, post #7

Chcialbym tu odpowiedzciec na posty kolegow Asmana i Don Adana, bo zaczyna sie robic ciekawie :)

Na poczatek funkcja o ktora prosil Asman (forum obcina spacje wiec moze byc troche nieczytelnie)

void RysujLiniePozioma(int x1, int x2, int y, int kolor)
{
unsigned char *ptr;

if(y < 0) return;

ptr = Tab_Mapa + y * 320;

x1 >>= 8;
x2 >>= 8;

if(x1 < x2)
{
x2++;

if(x1 < 0) x1 = 0;
if(x2 > 319) x2 = 319;

ptr += x1;

for(; x1<x2; x1++)
{
*ptr++ = kolor;
}

return;
}
x1++;

if(x2 < 0) x2 = 0;
if(x1 > 319) x1 = 319;

ptr += x2;

for(; x2<x1; x2++)
{
*ptr++ = kolor;
}
}

Opis: funkcja ma na zadanie wyrysowac linie pozioma od puntu x1 do x2, na wysokosci y, o kolorze "kolor". Wpis nastepuje do kolejnych komorek tablicy UBYTE Tab_Mapa.

Deasemblacja (tutaj dopiero bedzie balagan)

; 319: void RysujLiniePozioma(int x1, int x2, int y, int kolor)
| 05CC 48E7 0304 MOVEM.L D6-D7/A5,-(A7)
| 05D0 222F 001C MOVE.L 001C(A7),D1
| 05D4 202F 0018 MOVE.L 0018(A7),D0
| 05D8 2C2F 0014 MOVE.L 0014(A7),D6
| 05DC 2E2F 0010 MOVE.L 0010(A7),D7
; 320: {
; 321: unsigned char *ptr;
; 322:
; 323: if(y < 0) return;
| 05E0 4A80 TST.L D0
| 05E2 6B62 BMI.B 0646
; 324:
; 325: ptr = Tab_Mapa + y * 320;
| 05E4 4C3C 0800 0000 0140 MULS.L #00000140,D0
| 05EC 4BF9 0000 8A74-02 LEA 02.00008A74,A5
| 05F2 DBC0 ADDA.L D0,A5
; 326:
; 327: x1 >>= 8;
| 05F4 E087 ASR.L #8,D7
; 328: x2 >>= 8;
| 05F6 E086 ASR.L #8,D6
; 329:
; 330: if(x1 < x2)
| 05F8 BE86 CMP.L D6,D7
| 05FA 6C26 BGE.B 0622
; 331: {
; 332: x2++;
| 05FC 5286 ADDQ.L #1,D6
; 333:
; 334: if(x1 < 0) x1 = 0;
| 05FE 4A87 TST.L D7
| 0600 6A02 BPL.B 0604
| 0602 7E00 MOVEQ #00,D7
; 335: if(x2 > 319) x2 = 319;
| 0604 0C86 0000 013F CMPI.L #0000013F,D6
| 060A 6F06 BLE.B 0612
| 060C 2C3C 0000 013F MOVE.L #0000013F,D6
; 336:
; 337: ptr += x1;
| 0612 DBC7 ADDA.L D7,A5
; 338:
; 339: for(; x1<x2; x1++)
| 0614 6006 BRA.B 061C
; 340: {
; 341: *ptr++ = kolor;
| 0616 2001 MOVE.L D1,D0
| 0618 1AC0 MOVE.B D0,(A5)+
| 061A 5287 ADDQ.L #1,D7
| 061C BE86 CMP.L D6,D7
| 061E 6DF6 BLT.B 0616
; 342: }
; 343:
; 344: return;
| 0620 6024 BRA.B 0646
; 345: }
; 346:
; 347: x1++;
| 0622 5287 ADDQ.L #1,D7
; 348:
; 349: if(x2 < 0) x2 = 0;
| 0624 4A86 TST.L D6
| 0626 6A02 BPL.B 062A
| 0628 7C00 MOVEQ #00,D6
; 350: if(x1 > 319) x1 = 319;
| 062A 0C87 0000 013F CMPI.L #0000013F,D7
| 0630 6F06 BLE.B 0638
| 0632 2E3C 0000 013F MOVE.L #0000013F,D7
; 351:
; 352: ptr += x2;
| 0638 DBC6 ADDA.L D6,A5
; 353:
; 354: for(; x2<x1; x2++)
| 063A 6006 BRA.B 0642
; 355: {
; 356: *ptr++ = kolor;
| 063C 2001 MOVE.L D1,D0
| 063E 1AC0 MOVE.B D0,(A5)+
| 0640 5286 ADDQ.L #1,D6
| 0642 BC87 CMP.L D7,D6
| 0644 6DF6 BLT.B 063C
; 357: }
; 358: }
| 0646 4CDF 20C0 MOVEM.L (A7)+,D6-D7/A5
| 064A 4E75 RTS

A teraz najciekawsze. Zamienilem intrukcje tak jak polecil Don Adan i program dzialal dalej tak jak nalezy. Z ciekawosci zmienilem ten skok $6DF6 na $6DF8 i po tej zmianie (uwaga) program dalej dzialal poprawnie (!!!) tyle ze jak mi wyszlo z pomiarow o wiele szycbiej, co chyba nie jest zaskoczeniem.

Wiec pytanie dalej otwarte: co z tym nieszczesnym rejestrem D0?

Ostatnia aktualizacja: 06.05.2014 14:55:45 przez Phibrizzo
[#15] Re: Asembler for dumies - czyli pytania poczatkujacego

@cholok, post #13

Osobiscie kozystam z tego co jest w Sasie jako standard.
[#16] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #14

Jeszcze jedno pytanie jakie są minimalne i maksymalne wartości parametrów (wszystkich ) w tej funkcji ). Dzięki

Edit: Znaczy się czy może zdarzyć się ze wywołasz tą funkcję na przyklad

RysujLiniePozioma( -500, -800000, -123, 456) czy wiesz że zawsze będą poprawne wartośći ?


Ostatnia aktualizacja: 06.05.2014 15:32:50 przez asman
[#17] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #14

Ano nic z tym D0 zlego sie nie dzieje. Wszystko jest OK.
Po prostu ta rutynka w wersji SAS C wyglada tak:

BRA.B init
loop
MOVE.L D1,D0
MOVE.B D0,(A5)+
ADDQ.L #1,D6
init
CMP.L D7,D6
BLT.B loop

A nie tak jak ja dales na poczatku:

loop
MOVE.L D1,D0
MOVE.B D0,(A5)+
ADDQ.L #1,D6
CMP.L D7,D6
BLT.B loop

Pisalem o tym poprzednio, ze kompilatory lubia uzywac skokow do startu,
dlatego jest ten "bra.b 0642" jako init procedury.

A co do szybkosci to przecietny koder zrobilby to w formie:

loop
move.b D1,(A5)+
dbf Dx,loop

albo jesli dla wiecej niz $10000 razy to:

loop
move.b D1,(A5)+
subq.l #1,Dx
bne.b loop

Byc moze jak poprawisz ta procedure w C to otrzymasz podobny kod.
[#18] Re: Asembler for dumies - czyli pytania poczatkujacego

@asman, post #16

Jesli chodzi o x1 oraz x2 to niejestem w stanie oszaczowac, moze sie to zmieniac w szerokim zakresie. dlatego sa te warunki kontrolne. Jesli chodzi o y to wartosc nigdy nie przekroczy 255 w plusue, jednak moze byc ujemnma. W tej sytuacji funkcja konczy prace. Zmienna kolor zawiera sie w zakresie od 0-255.
[#19] Re: Asembler for dumies - czyli pytania poczatkujacego

@Don_Adan, post #17

Dzieki za wyjasnienie, teraz to widze, Ech, wiele sie jeszcze musze nauczyc. Jak widac jeszcze daleka droga przede mna.

Ostatnia aktualizacja: 06.05.2014 15:52:31 przez Phibrizzo
[#20] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #18

To właśnie możesz dokładnie policzyć. Jeśli założymy że ta funkcja jest wywoływana przez 10 sekund (w jakimś demie na przykład), to mamy 10*50 wywołań ( o ile wywołujesz raz na ramkę ofcoz). I jeśli chcemy tylko dowieidzieć się o x1 i x2, to wystarczy nam bufor który pomieści 10*50 * rozmiar x1 w bajtach * rozmiar x2 w bajtach. Dodając odpowiedni kawałek kodu, który zapisze x1 i x2 do bufora a później wystarczy ten bufor zapisać do pliku i można sobie poanalizować. Na podstawie tego możesz przyspieszyć jeszcze bardziej swoją funkcję. Tak jak wspomniał Don, w tym przypadku przecietny koder używa dbfa. Dodatkowo sprawdzając czy masz parzystą bądź nie ilość kolorów do ustawienia możesz pętlę zmniejszyć 2 razy. Zapisując kolor w odpowiedni sposób jako UWORD ( kolor + kolor << 8, bo kolor należe do przedzialu0;255) ) i wtedy zamiast move.b możesz użyć move.w . Wszystko zależy jak długie linie rysujesz. Im dłuższe linie to można pokusić się o move.l. Tego wszystkiego dowiesz się analizuąc wspomniany wyżej bufor. Najpierw popracowałbym nad funkcją w C, jest powtórzenie do wywalenia, wystarczy zamienić miejscami x1 i x2. Druga sprawa że parametry schodzą ze stosu czyli najpierw gdzieś wcześniej zostały umieszczone na stosie, to jest o 4 instrukcje move.l za dużo, może warto zrobić void i użyć zmiennych statycznych. Zamiast int kolor, szybciej będzie UBYTE kolor. Na przykład wtedy wiadomo (dobry kompilator powinien to wiedzieć) że można użyć dbf jako pętli (pomijam że to właśnie dobry kompilator powinien zamienić pętlę na dbf, przecież specyfikacja języka c nie narzuca uporządkowania pamięci, i to że ktoś ma tablice dwuelementową nie oznacza, że kolejny element musi być w pamięci za elementem pierwszym, to tylko nasze przyzwyczajenie), bo każda zmienna tego typu nie przekracza $10000. Mnożenie przez 320 jest cyklożerne na 68000, na 68060 już nie, zależy na jakim procku ma to działać, to można odpowiednie kroki przedsięwziąc by temu zaradzić. Kosztem pamięci możesz tablicę poszerzyć do 512. Widzę, że kompilator tablicę pobiera za pomocą lea. Wszystko fajnie ale dlaczego nie przez lea adres(pc), ale to może być drugorzędna sprawa bo asembler (na przykład barfly) zmieni to na lepszy kod.

Wyszło trochę chaotycznie, więc w razie problemów ze zrozumieniem, warto zadawać dodatkowe pytania.

Ostatnia aktualizacja: 06.05.2014 17:31:13 przez asman
[#21] Re: Asembler for dumies - czyli pytania poczatkujacego

@asman, post #20

Dziekuje wszystkim za rady. Teraz widze ze bede musial bardziej przylozyc sie do tego tematu, zwlaszcza przy analizowaniu kodu. Tak wiec zasiadam do lektury o 68k.
[#22] Re: Asembler for dumies - czyli pytania poczatkujacego

@Phibrizzo, post #21

Ciekawe rzeczy wychodzą jak korzystasz z wielu różnych kompilatorów, można się dowiedzieć w jak różny sposób pewne rzeczy są rozwiązane. Weźmy taki kod

g_nTimerSignal = 1L << port->mp_SigBit;


Sas robi to tak:

MOVEQ.L #$0,D0 ;7000
MOVE.L __MERGED+$2(A4),A0 ;206c 0002 (port)
MOVE.B $f(A0),D0 ;1028 000f (mp_SigBit)
MOVEQ.L #$0,D1 ;7200
BSET D0,D1 ;01c1
MOVE.L D1,__MERGEDBSS(A4) ;2941 0000


A tak robi to vbcc

move.l l2(a4),a0 ;port
moveq #0,d0
move.b (15,a0),d0 ;mp_SigBit
moveq #1,d2
lsl.l d0,d2
move.l d2,d0
move.l d0,_g_nTimerSignal(a4)

A w asemblerze dużo więcej nie pofikasz, przynajmniej ja tyle nafikałem i wyszło coś w stylu Sas

;a2 - port
moveq #0,d0
move.b 15(a2),d0 ;mp_SigBit --> d0
moveq #0,d1
bset d0,d1
move.l d1,signal(a4)
[#23] Re: Asembler for dumies - czyli pytania poczatkujacego

@Don_Adan, post #17

A co do szybkosci to przecietny koder zrobilby to w formie:

loop
move.b D1,(A5)+
dbf Dx,loop


Można jeszcze przyspieszyć (warunek - ilość wykonań pętli podzielna przez 4) :

inicjalizacja:
move.b D1,D0
asl.w #8,D0
move.b D1,D0
swap D0
move.b D1,D0
asl.w #8,D0
move.b D1,D0

pętla:
move.l D0,(A5)+
dbf Dx,petla

@Asman

Myślę, że kod w C można zawsze zoptymalizować, choćby nie wiadomo jak udało mu się automatycznie zoptymalizować. Po prostu kompilator C z reguły generuje bardzo szablonowy kod i nie uwzględnia pewnych niuansów programowania w asemblerze, które zna człowiek.

Programista C zawsze ma pewien narzut, bo o ile jedną procedurę można napisać na różne sposoby, przecież w C liczy się czytelność. Dlatego zawsze wstawki asemblerowe są pomocne.

Np. forma

for( x = 0; x < 100; x++ ) *wskaznik++ = zmienna;

Jest bardziej czytelna od

x = 0;
while( x++ < 100 ) *wskaznik++ = zmienna;

Pętla for jest stworzone do takiego maszerowania. Ważne jest by procedury w C były czytelne, jeśli zależy nam na prędkości, wstawki asemblerowe przychodzą nam z pomocą.

Ostatnia aktualizacja: 07.05.2014 01:56:15 przez Hexmage960
[#24] Re: Asembler for dumies - czyli pytania poczatkujacego

@asman, post #22

Mozna jeszcze wywalic moveq #0,D0 z tego kodu.
Jak kiedys napisal mi pewien hardcorowy koder do operacji na bitach sa uzywane
tylko bity od 0 do 5, reszta (od 6 do 31) jest nieuzywana i moze byc
wykorzystana do czegos innego np. bajt (bit 7) jako flaga plus/minus,
ale takie rzeczy to zwykle sie robi jak zaczyna brakowac rejestrow,
a nie chce sie uzywac pamieci, zeby kod byl jeszcze szybszy.
W kazdym razie jeden rejestr danych mozna wykorzystac jako trzy
(tst.b, tst.w i tst.l) szybkie flagi oraz do operacji na bitach.
[#25] Re: Asembler for dumies - czyli pytania poczatkujacego

@Hexmage960, post #23

Zgadza sie tylko, ze musisz byc pewien, ze zapisujesz pod adres
parzysty, albo ten kod sie wylozy na 68000.
[#26] Re: Asembler for dumies - czyli pytania poczatkujacego

@Don_Adan, post #24

Faktycznie można wywalić, dzięki.
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem