Skocz do zawartości
qwee

Asembler '51 pomoc w zrozumieniu

Pomocna odpowiedź

Potrzebuje pomocy w analizie kodu dla 8051 od silicona w asm. Jest to problem natury dydaktycznej. Całe życie pracuje w c i nie znam ani trochę asemblera. Czy mógłby ktoś oświecić mnie w kilku kwestjach składniowych? Mianowicie:

obl_20:

movx	A,	@R0
mov	MAC0AH,	A
mov	MAC0BH,	A
inc	R0
movx	A,	@R0
mov	MAC0AL,	A
mov	MAC0BL,	A	; This line initiates the Multiply operation
inc	R0

djnz	R3,	obl_20


mov	SFRPAGE,	#CONFIG_PAGE
cpl	OBL_pin

ret

Czy dobrze kombinuje, że działa to tak:

1 do A (akumulatora???) przenosimy zawartość rejestru(?) R0 N

2 Następnie z A przepisujemy wartości do dwóch bajtów MAC ( mnożarki z 16 bitowej z dodawaniem )

3 później zwiększamy R0

4. tak samo do kolejnych dwóch bajtów MAC

W efekcie w rejsetrach MAC powinni być:

MAC0AH = A

MAC0AL= A

MAC0BH = A

MAC0BL = A

Gdzie MAC0AH i MAC0AL to jedno 16 bitowe słowo, co powinno dać działanie :

(256*A + 256*A) * (256*A + 256*A) ? A- wartość przepisana z rejestru R0.

6. następnie dekrementuj R3, lub skocz do obl_20 jeśli 0.

Czyli po polsku for(R3=x, R3>0, R3--)?

Nastomiast kompletnie nie czasje co mówi linia

 mov	SFRPAGE,	#CONFIG_PAGE

Czy mogę liczyć na pomoc?

Udostępnij ten post


Link to post
Share on other sites

Oczywiście - na ile jestem w stanie.

Przede wszystkim '51 to tylko nazwa jądra procesora a więc bloku pobierającego, dekodującego i wykonującego instrukcje. Trzeba pamiętać, w czasie pojawienia się tego procesora jednoukładowość była w powijakach. Dopiero co przed chwilą udało się zmieścić w jednej kostce prosty procesor 8-bitowy (jądro 8048) zintegrowany z niewielką pamięcią programu i danych. Intel przy projektowaniu swojej następnej kostki wpadł na genialny pomysł: zróbmy przestrzeń adresową w której będziemy umieszczać rejestry sterujące bloków peryferyjnych. Pierwsze 51 miały dwa timery i UART a mimo to zawojowały rynek na lata. Właśnie dlatego, że można było właściwie dowolnie pakować tam wokół jądra różne układy peryferyjne. Dziś taka idea skalowalności to standard - tak mają i AVR i STMy i chyba każdy procesor jednoukładowy, ale wtedy to był przełom. Dlatego pisząc o 51 powinieneś dokładnie podać nazwę i producenta, bo przecież nie wiemy co za licho mieści się pod nazwą rejestru MAC0AH. Każdy robił to inaczej i nie było (oprócz podstawowych dwóch timerów i UARTa) żadnego standardu.

8051 ma trzy a właściwie to pięć przestrzeni adresowych pamięci, każda adresowana od zera.

1. Pamięć programu - no to jest jasne. Z niej procesor pobiera instrukcje a program może dobrać się np. do tablicy umieszczonej w kodzie za pomocą dwóch specjalnych rozkazów.

2. Wewnętrzna pamięć danych. Do niej mamy dostęp za pomocą tzw. rejestrów indeksowych R0 i R1. Ponieważ są one 8-bitowe, można zaadresować tylko 256 bajtów tej pamięci. Pierwsza 51 miała jej tylko 128 bajtów. Następne miały już pełne 256. Żeby dostać się do tej pamięci trzeba wykonać instrkcję:

MOV A,@R0 ; odczyt z pamięci zaadresowanej zawartością R0 do akumulatora

MOV @R1, A ; to samo ale w drugą stronę i adres w R1

Oczywiście są dostępne wszystkie cztery kombinacje.

3. Obszar rejestrów SFR (Special Function Registers). Może być ich 128, zajmują adresy 128..255 w obszarze wewnętrznej pamięci danych, ale musimy się do nich dostawać innymi instrukcjami, posługującymi się adresowaniem bezpośrednim, np:

MOV A,adres

Jeżeli jako 'adres' użyjemy liczby z zakresu 0..128 dostaniemy się do zwykłego RAMu w obszarze wewnętrznej pamięci danych. Adres w zakresie 128..255 otwiera dostęp do SFRów układów peryferyjnych. Instrukcji dobierających się w ten sposób (przez bezpośrednie podanie adresu komórki) jest dość dużo a ponieważ 8051 jest procesorem CISC, są też zaskakujące np:

MOV adres_dest, adres_src

która przepisuje daną z komórki do komórki bez udziału akumulatora

lub

XCH A,adres

która wymienia zwartość komórki pamięci i akumulatora.

4. Obszar zewnętrznej pamięci danych. Do 8051 można było podłączyć z zewnątrz do 64K RAMU lub czegoś innego (np. dodatkowe zewnętrzne UARTY, rejestry I/O itp). Ta pamięć, mimo że znacznie rozszerzała możliwości biednego 8051 była dość skromnie wyposażona w instrukcje. Procesor miał specjalny rejestr DPTR (Data Pointer) za pomocą którego można było tę pamięć adresować, uprzednio wpisując adres do tego jedynego 16-bitowego rejestru, np:

MOV DPTR,#1234H

MOVX a,@DPTR

oznaczało załadowanie do DPTR adresu 0x1234 i odczyt tej komórki pamięci zewnętrznej do akumulatora. Nie było autoinkrementacji wskaźnika itp. Wyobraźcie sobie jakiej ekwilibrystyki rejestrami wymagało np. przesuniecie bloku danych w pamięci zewnętrznej. Acha, DPTR można było inkrementować w jednym strzale za pomocą instrukcji INC DPTR. Adres do zewnętrznej pamięci danych wysyłany był z procesora poprzez dwa porty, normalnie wykorzystywane jako typowe porty I/O: P0 (młodsze 8 bitów adresu) i P2 (starsze 8 bitów). Podczas użycia instrukcji "MOVX A,@DPTR" cały DPTR był wystawiany na oba porty. Jednak dodano jeszcze cztery instrukcje:

MOVX A,@R0

MOVX A,@R1

i w drugą stronę:

MOVX @R0,A

MOVX @R1,A

które używały adresowania 8-bitowego. Skąd pamięć wiedziała jakie jest starsze 8 bitów adresu? Z wcześniej wysłanej tam zawartości portu P2. Tak więc wiedząc, że dane mamy na jednej z 256 stron pamięci, można było wysłać na P2 jej "numer":

MOV P2,#strona

a potem do woli grzebać w pamięci już bez użycia kłopotliwego DPTRa. Rejestry R0 i R1 były dużo bardziej elastyczne, można je było łatwo przeładowywać, inkrementować, dekrementować i zachowywać w pamięci na później. Oczywiście wszystko w ramach jednej strony pamięci zewnętrznej. Zmiana strony wymagała zmiany zwartości portu P2. Oczywiście używanie pamięci zewnętrznej zabierało aż 2 z trzech standardowych portów I/O procesora. Na szczęście szyna danych była multipleksowana z młodszą połówką adresu i dane były przeciskane przez P0 tuż po wysłaniu adresu do pamięci.

5. Była jeszcze pamięć pojedynczych bitów - też (wtedy) super nowość, ale nie chcę już się rozwlekać.

Myślę, ze teraz jest już dla Ciebie jasne co program robi. Pobiera zawartość komórki zewnętrznej pamięci danych zaadresowaną parą rejestrów P2:R0 (nie wiemy co tam jest - RAM czy może coś innego), ładuje to tak jak się domyśliłeś jako pierwszy argument mnożarki, potem inkrementuje wskaźnik R0 i pobiera następną komórkę z zewn. pamięci danych, mnoży i akumuluje to w dość zaskakujący sposób i powtarza to R3 razy.

Instrukcja "DJNZ R3, adres" przekłada się "po polsku" raczej jako:

do

{

.....

} while (--R3);

i najpierw dekrementuje R3 a potem skacze do "adres" (zamyka pętlę) gdy zawartość R3 jest wciąż > 0.

Instrukcja

MOV SFRPAGE,#CONFIG_PAGE

ładuje stałą CONFIG_PAGE (użycie # oznaczało adresowanie natychmiastowe - stała jest w instrukcji) do rejestru SFR o adresie SFRPAGE. Podejrzewam, że ten Twój 8051 ma tak dużo rejestrów SFR, że nie mieszczą się na jednej 128-bajtowej stronie i trzeba było zrobić rejestr wybierający "zestaw" aktualnie dostępnych peryferiów. Nazwa SFRPAGE właśnie na to wskazuje.

Instrukcja

CPL OBL_pin

po prostu odwraca stan bitu o adresie OBL_pin. To może być bit w wewnętrznej pamięci RAM, ale raczej nazwa wskazuje na jeden z pinów któregoś portu. 128 bitów dostępnych bezpośrednio przez adresowanie bitowe było umieszczonych w tej pamięci jako komórki o adresach 0x20..0x2F oraz jako pierwszych 16 rejestrów SFR. Ponieważ te najcenniejsze adresy dostały m.in. porty I/O, można było jedną instrukcją ustawić, wyzerować lub odwrócić pojedynczy bit.

Ech, to był fajny procesor. Programowanie w jego asemblerze to była przyjemność 🙂

------------------

EDIT: Teraz zajarzyłem, że program wpisuje pierwszy pobrany z pamięci bajt do obu górnych połówek argumentów (wskazują na to nazwy MAC0AH i MAC0BH), a drugi pobrany bajt do obu dolnych połówek argumentów. To znaczy, że mnożąc to liczy kwadrat 16-bitowej liczby pobranej z pamięci a akumulując to R3 razy (bo to jest MAC, czyli Multiply_Accumulate) na końcu masz sumę kwadratów tablicy 16-bitowych int-ów umieszczonej w zewnętrznym RAMie i wskazanej przez R0 🙂

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Nie spodziewałem się tak obszernej i rzeczowej pomocy, jestem zaskoczony i niezmiernie wdzięczny:)

Układ o któym mowa to C8051f120 od silicon labs. Pobrane dane nie są zewnętrzne lecz pochodzą z wewnętrznego przetwornika. Moim zadaniem jest tą funkcję zmodyfikować tak aby liczyć fft, a konkretnie daną harmoniczną. Uczę się asemblera stopniowo i tak naprawdę dopiero teraz poznaje mikrokontrolery. Jeszcze raz wielkie dzięki za naprawde pomocne odpowiedzi. Zapewne odezwę się z kolejnymi problemami. Pozdrawiam!

Udostępnij ten post


Link to post
Share on other sites

No to w tym kontekście (po uzupełnieniu o pierwiastek) ta liczy RMS zebranych próbek.

FFT to nie będzie modyfikacja, a napisanie dużej funkcji zupełnie od nowa. Myślałem, że czasy w których pisało się FFT w asemblerze bezpowrotnie minęły. U mnie jakieś 15 lat temu... Jeżeli kiedyś już takie rzeczy robiłeś np. w C, nie powinieneś mieć kłopotu z samym algorytmem i tutaj. Zanim jednak coś zaczniesz pisać oszacuj dobrze wymagania na pamięć. W małych procesorach zawsze są z tym problemy. FFT dobrze liczy się na zmiennym przecinku oraz potrzebuje (w większości przypadków) dwóch buforów na dane wejściowe i wyjściowe. Oprócz tego zespolone FFT wymaga jeszcze drugie tyle pamięci na części urojone. Poza tym 51 zupełnie nie wspiera adresowania z odwróconą propagacją przeniesienia, będziesz musiał dobrać okienkowanie, oszacować przecieki (lub dobrać częstotliwość próbkowania) itd.. Z ilu próbek chcesz to liczyć? Jeżeli Twoja mnożarka nie wspiera zmiennego przecinka, to przewiduję spore kłopoty z zakresem dynamiki i skalowaniem wszystkiego.

Jeżeli musisz wykryć i policzyć wysokość tylko jednego prążka a nie całe widmo, to są inne metody. Np. filtry FIR wręcz uwielbiają int-y i dość łatwo liczy się do nich współczynniki. Program sam mógłby sobie je liczyć w zależności od częstotliwości. Filtry IIR już gorzej (raczej double), ale za to są bardzo proste pojęciowo. Możesz też spróbować zrobić cyfrowy mieszacz zespolony (IQ mixer), przesunąć zespolone widmo tak by interesująca Cię częstotliwość wypadła w 0Hz a potem po prostu znaleźć składową stałą. W każdym razie przemyśl to FFT.

EDIT: Czy wspomniałem o tzw. algorytmie Goertzela? Chyba zapomniałem. To taki podwzbudzony rezonator cyfrowy z biegunem na okręgu jednostkowym. Jest szybki i wbrew pozorom (i podobieństwa do filtrów IIR) daje się liczyć na int-ach z uwagi na ograniczoną liczbę danych wyjściowych. Ma fajną, wąską ch-kę częstotliwościową i dobrze nadaje się do znajdowania obecności jednej częstotliwości w danych wejściowych. W odróżnieniu od FFT nie ma "fochów" związanych z niecałkowitymi wielokrotnościami fs/N.

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...