Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

assembler - prosty program na zaliczenie

20 Wrz 2012 00:53 3240 10
  • Poziom 8  
    Witam szanownych użytkowników :)

    Na zaliczenie mam do napisania program. Jego treść przedstawiam poniżej.

    Szesnascie kolejnych liczb osmiobitowych (wyniki pomiarow) umieszczono na stosie. Napisac procedure (wywolywana z programu glownego), zdejmujaca te dane ze stosu, obliczajaca ich wartosc srednia, umieszczajaca te wartosc w komorce nr 30h i powracajaca do programu glownego.

    Aby to uzyskać, jak mniemam, muszę:
    1. Napisać kilka linijek programu ogólnego (początek, koniec, a w środku wspomniana procedura)
    2. Wywołanie procedury.
    3. Przeniesienie zawartości akumulatora do jakiejś komórki pamięci.
    4. Wyzerowanie akumulatora

    Początek pętli
    5. Zdjęcie ze stosu pierwszej liczby i dodanie jej do wartości akumulatora/.
    6. Odczytanie i dodanie kolejnych liczb ze stosu.
    Koniec pętli

    7. Wynik z akumulatora podzielić przez liczbę powtórzeń pętli.
    8. Wynik dzielenia (zawartość akumulatora?) przenieść do komórki 30h.
    9. Wyzerować akumulator.
    10. Przenieść do akumulatora jego wartość pierwotną (zapisaną w komórce pamięci - pkt 3)
    11. Wrócić do programu głównego.

    Problem polega na tym, że nie bardzo wiem jak się dalej za to zabrać.
    Brakuje mi wiedzy na temat stosowania komend itp. (być może niektóre pkt są zbędne - np. przeniesienie jakiejś wartości do akumulatora może nie wymaga wcześniejszego zerowania akumulatora). Może trzeba jeszcze coś dodać? Jak to zrobić, aby obliczenia uwzględniały znak poszczególnych wartości zdejmowanych ze stosu (pomiary mogą mieć wartość dodatnią lub ujemną).?
    Czy wywołanie podprogramu zapisuje się w jakiś sposób na stosie? Jeśli tak, to ile "wartości" trzeba zdjąć aby dokopać się do "wyników pomiarów, które podlegają dalszej obróbce"?

    Proszę o pomoc.
  • Poziom 27  
    Po pierwsze to zależy na jakim procku to masz napisać, komendy trzeba sobie przejrzeć jakie są dostępne i na tej podstawie coś próbować zrobić. Nie wiadomo, jakie instrukcje są wykonywane więc ciężko ułożyć jakiś scenariusz.

    Wywołanie podprogramu zapisuje się na stosie, a to ile dokładnie zajmuje ten narzut (przynajmniej adres powrotu z podporgramu i najważniejsze rejestry uC) to też zależy od procka.

    Jeśli założyć, że masz jakieś dane na stosie, które zostały umieszczone tam przez jakiś podprogram i chcesz je w procedurze zdjąć, to:

    ogólnie to wygląda tak, że taka procedura odczytująca to powinna gdzieś mieć zapisany Stack Pointer od którego zacznie zdejmować dane ze stosu, pierwsze pójdzie ostatnio zapisana zmienna i tak do tej, która została zapisana najwcześniej, potem zostają zdjęte wartości rejestrów i kontekst powrotu z podprogramu.
  • Poziom 40  
    Musisz jeszcze pamiętać że akumulator jak i rejestry prawdopodobnie są ośmiobitowe a co za tym idzie nie możesz sobie tak bezmyślnie dodawać szesnastu liczb i trzymać ich sumy w akumulatorze bo się tam ta suma nie zmieści. Wynik musisz zapisywać na dwóch bajtach i dopiero dodawać kolejną bajtową liczbę. Zazwyczaj w asemblerze, ale to zależy od konkretnego procesora, nie ma operacji dzielenia w dodatku liczby 16-bitowej. Nie będzie więc tak łatwo. Tak jak wspomniał kolega wyżej na stosie będziesz miał co najmniej adres powrotu z procedury i musisz go zanim zaczniesz operować na twoich liczbach zdjąć ze stosu i zapisać w jakiejś komórce pamięci a na końcu procedury znów wrzucić adres powrotu na stos.
  • Poziom 8  
    Dziękuję za wstępne zainteresowanie tematem.

    Rozumiem więc, że algorytm trzeba uzupełnić o następujące punkty:
    2A. Przeniesienie zawartości stosu związanej z wywołaną procedurą do znanej mi komórki pamięci.
    10A. Przeniesienie zawartości ww. komórki na stos.

    Program jako taki ma być napisany w środowisku AT89LP Developer Studio. Dostępnych jest tam z tego co widzę kilkanaście (naliczyłem 17) typów mikrosterowników. Załóżmy, że wspomniany program ma działać na AT89LP51 (pierwszy na liście).

    Posiadam literaturę:
    Mikrokontrolery jednoukładowe rodziny MCS-51 (A.Rydzewski)
    Wprowadzenie do techniki mikroprocesorowej (J.Jakubiec)
    Sterowniki mikroprocesorowe w górnictwie (A.Fręchowicz, A.Heyduk)

    Rozumiem, że teraz najtrudniejszy etap. Wyszukać odpowiednie komendy realizujące opisany algorytm. I tak np rozkaz LCALL adr16 spowoduje skok do podprogramu, który będzie zapisany we wskazanej komórce pamięci?
  • Poziom 27  
    Tak i tam jest wyjaśnione jak to działa, tylko, że się walnęli w np. doc3710 bo podają :
    08H and 09H will contain 26H and 01H, co jest nieprawdą, bo zawierają 23H i 01H.
  • Poziom 8  
    Oto co wymyśliłem :)

    ORG 0
    AJMP 50H
    ORG 50H

    LCALL OBLSR ; wywołanie podprogramu obliczania średniej
    OBLSR: POP R7 ; zdjęcie ze stosu bardziej znaczącego bajtu adresu powrotu do programu głównego i zapisanie w rejestrze R7
    POP R6 ; zdjęcie ze stosu mniej znaczącego bajtu adresu powrotu do programu głównego i zapisanie w rejestrze R6
    MOV R5, A ; przeniesienie aktualnej zawartości akumulatora do rejestru R5
    CLR A ; wyzerowanie akumulatora
    POP A ; zdjęcie ze stosu i zapisanie w akumulatorze pierwszej danej do obliczenia wartości średniej
    MOV R4, #15 ; licznik pętli umiejscowiony w rejestrze R4
    PETLA: CLR R3 ; wyzerowanie rejestru R3
    POP R3 ; zdjęcie ze stosu i zapisanie w rejestrze R3 kolejnych danych do obliczenia średniej
    ADD A, R3 ; dodanie do akumulatora zawartości R3
    DJNZ R4, PETLA ; powrót w pętli (15-krotny)
    MOV B, #16 ; ustawienie w rejestrze B wartości odpowiadającej ilości sumowanych liczb
    DIV AB ; obliczenie wartości średniej
    MOV 30H, A ; przeniesienie do komórki pamięci o adresie 30H zawartości akumulatora (liczba całkowita - w rejestrze B jest reszta z dzielenia?)
    CLR A ; wyzerowanie akumulatora
    MOV A, R5 ; przeniesienie do akumulatora jego pierwotnej zawartości zapisanej w rejestrze R5
    PUSH R6 ; przeniesienie na stos mniej znaczącego bajtu adresu powrotu do programu głównego
    PUSH R7 ;przeniesienie na stos bardziej znaczącego bajtu adresu powrotu do programu głównego
    RET ; koniec podprogramu = powrót do programu głównego

    END ; koniec programu

    Teraz kilka pytań...
    1. Jak to skompilować w tym AT89LP Developer Studio? (na zajęciach robiliśmy to tak, że był podgląd komórek pamięci i poszczególnych rejestrów -> nie pamiętam jak to zrobić aby widzieć jak działa program).
    2. Dodawanie liczb może spowodować przekroczenie zakresu [0-255]. Załóżmy że będę sprawdzał wartość CY. Jeśli przy dodawaniu zostanie przekroczony zakres, CY=1. Co dalej mam z tym zrobić? Wykonać dzielenie przez liczbę sumowanych liczb, a wynik przenieść do jakiejś komórki pamięci? Później znowu sumować i jeśli CY = 1 znosu wydzielić i przenieść do innej komówrki pamięci... a następnie, aby otrzymać wartość średnią zsumować otrzymane pośrednio wartości średnie i z nich wyciągać srednią? Co z częścią ułamkową przechowywaną w rejestrze B?
    3. Co jeśli liczby będą miały różny znak? Rozbijać program na dodawanie i odejmowanie od akumulatora (jeśli liczba będzie ujemna)?
  • Poziom 27  
    Weź to w jakiś asm syntax daj.
  • Poziom 8  
    Kod: asm
    Zaloguj się, aby zobaczyć kod


    Cytat:
    ---- Building project: zadanie_25.ncp ----
    Building file... : C:\Documents and Settings\Piter\Pulpit\u_kontrolery\u_kontrolery\zadanie_25\zadanie_25.asm
    C51ASM: advanced C51 macro assembler Version 1.0 (01 Sept. 2009)
    Copyright (C) 2009 Atmel Corp.


    Pass 1 completed with no warnings and no errors

    Pass 2 completed with no warnings and no errors

    Segment usage:
    Code : 36 bytes
    Data : 0 bytes
    Idata : 0 bytes
    Edata : 0 bytes
    Fdata : 0 bytes
    Xdata : 0 bytes
    Bit : 0 bits

    Register banks used: ---

    Warnings: 0
    Errors: 0


    ---------------------- Done ----------------------
    Successfully built project: zadanie_25.ncp


    Zmieniłem nazwy rejestrów na konkretne komórki pamięci - wg książek odpowiadające tym właśnie rejestrom.
    Wygląda na to, że składnia jest poprawna.

    Jak mogę teraz sprawdzić działanie programu??? (na zajęciach robiliśmy to jakoś w okienku DOSowym - wpisywało się co ma zawierać konkretna komórka pamięci. Jak bym wiedział gdzie jest STOS i wiedział jak wejść w tego DOSa, to mógłbym coś podejrzeć)

    Gdzie jest STOS? Jak mogę sobie go umieścić w miejscu w którym ja chcę?
  • Poziom 17  
    W rodzinie '51 standardowo stos ma początek w rejestrze o adresie 07H
    (i zajmuje kolejne o wyższym adresie)
    można to sobie zmienić przez wpisanie nowego adresu do SP
    przykład:
    MOV SP,#30H ;przenosi początek stosu od adresu 30H

    Co do dzielenia to mała podpowiedź
    Ponieważ liczba ma być dzielona przez 16 to najlepszym sposobem
    jest przesuwanie bitowe w prawo (każde przesunięcie to dzielenie przez dwa)
    Jeżeli odrzucisz cztery najmniej znaczące bity, to otrzymasz wynik dzielenia przez 16.
  • Poziom 8  
    Kod: asm
    Zaloguj się, aby zobaczyć kod


    Cytat:
    ---- Building project: zadanie_25.ncp ----
    Building file... : C:\Documents and Settings\Piter\Pulpit\u_kontrolery\u_kontrolery\zadanie_25\zadanie_25.asm
    C51ASM: advanced C51 macro assembler Version 1.0 (01 Sept. 2009)
    Copyright (C) 2009 Atmel Corp.


    Pass 1 completed with no warnings and no errors

    Pass 2 completed with no warnings and 2 errors

    Segment usage:
    Code : 104 bytes
    Data : 0 bytes
    Idata : 0 bytes
    Edata : 0 bytes
    Fdata : 0 bytes
    Xdata : 0 bytes
    Bit : 0 bits

    Register banks used: ---

    Warnings: 0
    Errors: 2

    ERROR #2 C:\Documents and Settings\Piter\Pulpit\u_kontrolery\u_kontrolery\zadanie_25\zadanie_25.asm(7): Undefined symbol.
    ERROR #13 C:\Documents and Settings\Piter\Pulpit\u_kontrolery\u_kontrolery\zadanie_25\zadanie_25.asm(7): Expression is undefined.

    ---------------------- Done ----------------------
    There were build errors. Unable to build project: zadanie_25.ncp


    Niestety ale komenda ustawiająca początek STOSu w 40H powoduje błąd.
    Aby coś na ten stos było "odłożone" dodałem początek programu wprowadzający tam kolejno 16 liczb (2x od 1 do 8 - teoretycznie to z nich powinna być teraz liczona średnia).
    Gdzie odnaleźć informację odnośnie poprawnych adresów poszczególnych rejestrów itp (przy ustalaniu korzystałem z podanych wcześniej książek - wg nich w komórce 07H jest rejestr R7 banku rejestrów nr 0.

    Czyli podzielenie powinno być wykonane w taki sposób:
    CLR C
    RRC A (powtórzone 4 razy, bo jedno przesunięcie to dzielenie przez 2)?

    Jak sprawdzić co aktualnie znajduje się w poszczególnych komórkach pamięci??? (na zajęciach robiliśmy jakieś przejście pod DOSa - ale niestety nie pamiętam jak się to robiło)...

    Proszę o pomoc... zostało mi niewiele czasu aby to zaliczyć... z góry dzięki.
  • Poziom 17  
    Witam
    Jeżeli masz książkę Andrzeja Rydzewskiego
    to na stronie 82 zobacz stan początkowy rejestrów.

    Na stronie 138 jest opis rozkazu PUSH
    to może coś się wyjaśni

    W skrócie, jeżeli nie przestawisz początku stosu
    to pierwszy bajt odłożony na stos znajdzie sie pod adresem 08H
    (jest to adres rejestru R0 z banku rejestrów nr1 )
    standardowo używany jest bank nr0 więc często stos nie wymaga przenoszenia.


    Rozkaz modyfikacji wskaźnika stosu musi działać
    MOV SP,#40H ;ustawienie początku (wierzchołka) stosu

    Jeżeli ładujesz dane na stos za pośrednictwen akumulatora
    to trzeba uzyć rozkazu:
    PUSH ACC
    lub:
    PUSH 0E0H ;(bo taki ma adres rejestr zwany akumulatorem)

    czyli:
    MOV A,#2
    PUSH ACC ;umieszcza liczbę 2 na stosie

    MOV A,#4
    PUSH ACC ;umieszcza liczbę 4 na stosie


    można różnie (tu przy pomocy rejestru B)
    MOV B,#8
    PUSH B ;umieszcza liczbę 8 na stosie



    Polecam do zabawy jakiś programowy symulator 8051
    jest tego sporo w sieci również w wykonaniu naszych rodaków

    Znalazłem procedurkę w moich starociach,
    trochę ją przystosowałem do twoich potrzeb.
    Może coś pomoże


    Kod: asm
    Zaloguj się, aby zobaczyć kod