Zrozumieć asemblera dla AVRów

Właśnie siedzę i uczę sie asemblera na AVRy. Wszystko narazie idzie ładnie, wspomagam sie kilogramami dokumentacji, ale czegoś w niej nie rozumiem. Dokłądniej to chodzi o intrukcje skoków. Np. taka instrukcja RJMP. Jako argument podajemy jej adres pod jaki ma skoczyć. Wszystko ładnie pięknie. Ale dlaczego w AVR Instruction Set oraz w manualu do ATiny26 (na nim będę ćwiczył, narazie symulacja w AVR Studio) w sekcji Operations dla instrukcji RJMP jest napisane: PC <- PC + k + 1 Ja rozumiem to tak że do aktualnego stanu PC dodawany jest argument k oraz 1, i wartosć tego jest nowym licznikiem rozkazów. A tymczasem działa to tak ze licznik rozkazów zastępowany jest zinkrementowanym argumentem k. Gdybym miał opisać jak w rzeczywistosci działa instrukcja RJMP to napisałbym: PC <- k + 1 Gdzie tkwi błąd w moim rozumowaniu? I przy okazji zapytam się, czy jest jakiś sposób na ominięcie iluś rozkazów korzystajac z porównań i skoków, czy też muszę grupę rozkazów zetykietować i pomijać w programie skok do tej etykiety? Z góry dziękuje za pomoc :)

Reply to
Mateusz Majchrzycki
Loading thread data ...

działa to tak, jak jest opisane w manualu. A to, że w assemblerze piszesz RJMP <etykieta> to akurat nieważne. Kompilator czyta adres twojej etykiety i pozycji, gdzie akurat jest i koduje w instrukcji różnicę między aktualna pozycją i etykietą.

nie za bardzo rozumiem o co ci chodzi. Co chcesz robić?

Waldek

Reply to
Waldemar Krzok

Zapewne pisząc program nie wpisujesz kodów bajtowych poszczególnych instrukcji. Używasz słów które są przeznaczone dla kompilatora. W przypadku RJMP kompilator na podstawie np. etykiet oblicza jaki ma być argument tej instrukcji i wpisuje odpowiednią wartość do pliku wynikowego. W AVR Studio wyświetl okienko View->Disassembler to zobaczysz co faktycznie stworzył kompilator

Nie wiem czy AVR Studio jest odpowiednia dyrektywa oznaczająca aktualną wartość PC. Załóżmy dla przykładu, że tak i jest to znak $. Czyli RJMP $+3 lub ewentualnie RJMP $+6 (w AVRach instrukcje zajmują 2 bajty) będzie oznaczało ominięcie trzech instrukcji.

Paweł

Reply to
invalid unparseable

Pewnego dnia Waldemar Krzok snipped-for-privacy@t-online.de nastukał(a):

No dobrze, ale proszę mi w takiej sytuacji powiedzieć dokąd skoczy program przy takich instrukcjach gdy z portu a odczyta 0b11111110. Według moich zamirzeń miał przeskoczyć 4 instrukcje (brne 4 => PC <- PC

  • 4 + 1), czyli przejsc do następnego porównania: ============kod=========== .def ior=r16 .cseg ldi ior,ramend out sp,ior ldi ior,0b00111110 out ddrb,ior ldi ior,0b00000100 out portb,ior ldi ior,0b11111111 out porta,ior sbi portb,portb5

loop: in ior,pina sbrs ior,0 rjmp routesetup rjmp loop

routesetup: neg ior cpi ior,1 brne 4 andi r20,0b00111111 ori r20,0b01000000 andi r21,0b00001111 ori r21,0b10100000 cpi ior,2 brne 4 andi r22,0b00111111 ori r22,0b01000000 andi r23,0b00001111 ori r23,0b10100000 rjmp loop ======koniec==kodu======== A w moim końcowym pytaniu chodziło o to jak ominąć te 4 instrukcje po brne 4 jeżeli ior będzie różne od 1.

Reply to
Mateusz Majchrzycki

no właśnie po to sa etykiety, byś nie musiał liczyć. BRNE 4 przeskakuje 4 bajty, a nie 4 instrukcje. W tym przypadku lądujesz w połowie tego, co chcesz. Aby działało jak chcesz, musisz napisać BRNE 8. Tylko szukanie błędów po tym, jak program ma trochę więcej niz 20 linijek może doprowadzić jezuitę do kurwienia na czym świat stoi. Daj te etykiety, nawet jakby ich

100 sztuk było, to i tak łatwiej szukać. Ja przywykłem dawać funkcjom nazwy w stylu f01_cotafunkcjarobi, a etykietom potem f01_001 itd, jak te etykiety tylko do realizacji instrukcji switch służą.

Waldek

Reply to
Waldemar Krzok

Kompilator to zinterpretuje jako skok pod adres 4.

Paweł

Reply to
invalid unparseable

Pewnego dnia Paweł snipped-for-privacy@neostrada.pl nastukał(a):

No dobrze. Ale to i tak nie tłumaczy dlaczego pisząc np. brne 10 program skoczy do 10 instrukcji od początku programu, a nie przeskoczy

10 instrukcji. Cały czas rozchodzi mi się o ten zapis w Instruction Set: PC <- PC + k + 1 gdzie k to argument instrukcji brne. Według mnie, przy powyższym zapisie, instrukcja brne 10 powinna zostać wykonana jako PC <- PC+10+1, a nie jako PC<-10+1. To mnie własnie cały czas dręczy

Poszukałem i jest. Nomen omen ta dyrektywa nazywa sie PC :) Czyli mój zapis wygląda teraz brne PC+10. Ale mimo wszystko nie tłumaczy to wyżej opisanego sposobu myślenia mojego i twórców avr-asm :/

Reply to
Mateusz Majchrzycki

Pewnego dnia Paweł snipped-for-privacy@neostrada.pl nastukał(a):

No i doszliśmy do tego co mnie dręczy. Przeskoczy 4 czy skoczy pod 4? Według zapisów z Instruction Set powinien przeskoczyć 4, ale według tego co mi serwuje AVR Studio to skoczy pod 4. Kto ma racje i dlaczego?

Reply to
Mateusz Majchrzycki

Instrukcja jaką wykonuje procesor to 2 bajty. np. C0 07 oznacza wykonanie PC<-PC+7+1

Kompilator natomiast zakłada, że po RJMP będzie się znajdował fizyczny adres. Taka składnia języka jest znacznie wygodniejsza.

Paweł

Reply to
invalid unparseable

Popelniasz blad w rozumowaniu - zapis brne 10 powie kopilatorowi, ze chcesz skoczyc do instrukcji o adresie absolutnym rownym 10 i on to przetlumaczy na brne xx, gdzie xx to roznica pomiedzy 10 i PC. Latwo sie o tym przekonasz kompilujac taki kod, a nastepie ogladajac go w disassemblerze, nie bedzie brne 10 tylko brne np. 138. A przy okazji wartosc k w skokach wzglednych jest zapisywana w kodzie uzupelnien, czyli wartosci powyzej 128 sa traktowane jako ujemne, np. brne $FE to skok o jedna instrukcje wczesniej. Zobacz cos takiego: START: BRNE 10

i START: NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP BRNE 10

Zobaczysz jaki kod ci wygeneruje assembler - za kazdym razem argument BRNE bedzie inny mimo, ze ty ciagle wpisales 10. Co wiecej mozesz stwierdzic, ze raz argumentem bedzie 10, a raz -10, w zaleznosci jak jest polozona instrukcja BRNE wzgledem komorki pamieci o adresie 10. Z kolei jedynka ktora jest dodawana wynika z faktu, ze w chwili wykonywania skoku licznik instrukcji (PC) wskazuje juz na nastepna instrukcje za BRNE. Wbrew pozorom takie zachowanie kompilatora jest logiczne, bo zwykle wykonujesz BRNE etykieta - gdzie kompilator zamiast etykieta podstawia po prostu jej adres, dlatego tez zapis BRNE 10 musi byc traktowany jako skok do komorki o adresie 10, a nie skok o 10 slow do przodu.

Z kolei odpowiadajac na twoje drugie pytanie dotyczace pomijania blokow instrukcji - niestety tylko realizujac na poczatku bloku skok warunkowy. W szczegolnym przypadku kiedy to jest wylacznie jedna instrukcja, ktora chcesz warunkowo wykonac mozesz wykoszystac SBIC, SBIS, SBRC, SBRS. Pozdrawiam, T.M.F.

Reply to
T.M.F.

Dnia 2004-12-05 21:25, Użytkownik Mateusz Majchrzycki napisał: [...]

Blad z tego co czuje polega na tym ze RJMP to skrot od Relative Jump... Oznacza to "skok względny". Wzgledny - w stosunku do aktualnego licznika instrukcji! PC - Program Counter. Czyli skaczesz o [parametr] do przodu. Nie wzgledem poczatku tylko wzgledem aktualnego polozenia w kodzie. Dlatego masz PC+K... proste? :)

Reply to
mavs[NOSPAM

Pewnego dnia Paweł snipped-for-privacy@neostrada.pl nastukał(a):

Czyli zapisy w Instruction Set wprowadzają w błąd? No bo jeżeli kompilator zapis brne 10 interpretuje jako: PC<-10 to w takiej sytuacji zapis z manuala: brne k PC<-PC+k+1 wprowadza w błąd :/ A może ja dziwnie rozumuję :/ Zobaczymy jak to jutro będzie wyglądało.

Reply to
Mateusz Majchrzycki

Dziwnie rozumujesz. Jak piszesz brne 10, to kompilator sprawdza pod jakim adresem jest rozkaz brne, wylicza roznice i umieszcza w kodzie rozkazu.

Wpisz brne 10 kilka razy pod rzad i zobacz jaki kod sie wygeneruje.

A dodatkowo - jesli wpiszesz brne <etykieta> to kompilator moze roznice wyliczyc. Jesli brne 10 - to zazwyczaj dopiero linker bedzie wiedzial pod jakim adresem umiesci ten rozkaz.

J.

Reply to
J.F.

Użytkownik "Mateusz Majchrzycki" snipped-for-privacy@spam.spam napisał w wiadomości news:Xns95B6D8638D204XNSMateoM@192.168.0.1...

Reply to
Marek A.

PC jest rejestrem 16-to bitowym(PCH i PCL). Zapis PC<=PC+k+1 oznacza ,że do aktualnej wartości PC zostanie dodane przesunięcie k. Z tego względu, że rejestr PC jest dwubajtowy i musi być zapisany w dwóch sąsiednich komórkach pamięci, " +1 " oznacza następną sąsiednią komórkę pamięci a nie liczbę 1 która ma być dodana do przesunięcia k .

Reply to
Marek A.

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.