Rejestry
Celem systemu komputerowego jest wykonywanie przekształceń informacji, mających służyć człowiekowi.
Każdy procesor wyposażony jest w lokalną pamięć nazywaną rejestrem. Rejestr jest to najmniejsza lokalna pamięć położona najbliżej procesora. Innymi rodzajami pamięci są pamięci podręczne, które mogą w wielu przypadkach być wielopoziomowe. Służą do tego, aby przechowywać z zapasem (wyprzedzeniem, predykcją) dane rozkazy, które będą w przyszłości wykorzystane. Kolejnym rodzajem pamięci jest pamięć operacyjna. Pamięć ta jest poza procesorem, może jednak być wbudowana w strukturę układu.
Rejestry komputera - położone najbliżej procesora przechowują informacje, które zostały dostarczone bezpośrednio i dla których wykonuje operacje. Jest to specyficzna pamięć układu.
Słowo we współczesnych komputerach może mieć długość wielokrotności bajta i najczęściej jest wielokrotnością liczby 2. Mamy komputery o organizacji bajtowej, dwubajtowej (16 bitów), czterobajtowej (32 bity) jak i ośmiobajtowej (64 bity).
Niezależnie od długości słowa w każdym procesorze muszą być co najmniej 3 rejestry, aby procesor mógł wykonywać program:
akumulator - przechowuje daną, na której wykonuje się obliczenia;
licznik rozkazów (PC, IC) - jest rejestrem o długości adresu w komputerze, nie musi mieć takiej samej długości jak akumulator. Wskazuje adres następnego rozkazu do wykonania. Każdy program składa się z instrukcji w kodzie maszynowym;
wskaźnik stosu - bez stosu nie da się zorganizować podprogramów, przerwań i przetwarzania współbieżnego.
Oprócz tych 3 podstawowych rejestrów występują jeszcze inne rejestry:
rejestry służące do realizacji:
złożonych technik adresowania rozkazów;
segmentacji pamięci - jest to pewna logiczna organizacja pamięci wykorzystywana w celu uniknięcia jej fragmentacji.
rejestry bazowe, które przechowują adres bazowy, względnie punkt odniesienia dla programu. Zawartość tego rejestru może ulegać inkrementacji lub dekrementacji (przed i po wejściu);
rejestry indeksowe - automatycznie ulegają inkrementacji lub dekrementacji;
rejestr segmentowy - przechowuje adres początkowy segmentu danych umieszczonych na stosie.
Rozkazy
Cykl rozkazowy - opis, w jaki sposób wykonuje się rozkaz. Składa się on z trzech faz:
pobranie rozkazu z pamięci - aby rozkaz pobrać z pamięci potrzebna jest zawartość licznika rozkazów. Wskazuje ona miejsce w pamięci, w którym znajduje się kolejny rozkaz. Zawartość tego licznika kierowana jest na szynę adresową;
wykonanie rozkazu;
przerwanie i jego obsługa.
W zależności od tego, co jest argumentem rozkazu możemy mówić o rozkazach:
bezadresowych - jest to rodzaj rozkazu, w którym cały kod polecenia zajmuje jedno całe słowo. Przykładami tego typu rozkazów są:
rozkaz stopu - jedynym wyjściem z tego stanu jest fizyczny restart komputera;
rozkaz „nic nie rób”, który pobiera rozkaz z pamięci i powoduje zwiększenie licznika rozkazów o jeden albo o wielkość, jaką zajmuje rozkaz.
Składanie stron pamięci. Kolejne bity pobierane są z różnych kości pamięci. W jednym kroku można obsłużyć 8 kości pamięci. Odczyt jest niemal jednoczesny. Jeżeli rozkaz jest dwubajtowy, to otrzymujemy dwa kolejne bajty, które wędrują do umownego rejestru rozkazów i w sumie razem tworzą podrozkaz. Po to, aby odczytać rozkaz dwubajtowy z pamięci o organizacji jednobajtowej potrzebne są dwa cykle (odczyty), powodujące automatycznie zwiększenie o jeden wartości licznika rozkazów albo szyny adresowej. Rozkaz bezadresowy ma pewien adres. Adresem każdego rozkazu, z wyjątkiem rozkazu STOP, jest licznik rozkazów.
rozkaz, który ma jeden adres. Adres ten oznacza miejsce, w którym znajduje się argument rozkazu, czyli dana, na której na być wykonane działanie. Adres ten może być rejestrem
rozkaz z argumentem bezpośrednim. Dana do wykonania znajduje się bezpośrednio w kodzie rozkazu lub tuż za nim.
Dana jest sytuacja jak na rysunku poniżej. Za kodem są dwa adresy, które są dodatkowo podzielone. Instrukcja ta oznacza, że rozkaz ma dwa adresy, gdzie pierwszy z adresów oznacza źródło, drugi zaś przeznaczenie. Najczęściej taki sposób adresowania jest wykorzystywany w operacjach przesłania.
Przerwania
Przerwanie - jest to sygnał, który może pojawić się w dowolnym momencie czasu. Jakie to są sygnały z punktu widzenia komputera? Są to sygnały pochodzące z otoczenia, mówiące, że coś się stało. Może to być sygnał od sterownika czasowego, powiadomienie o fakcie naciśnięcia przez użytkownika klawisza klawiatury, wysłanie bajta informacji, odebranie bloku informacji. Co się dzieje, gdy przychodzi przerwanie? Aby to przerwanie zostało obsłużone, czyli aby został wykonany specyficzny program, fragment związany z programem, to muszą być spełnione warunki:
musi być ustawione odblokowanie przerwań programowych, tzn. procesor musi być w stanie obsłużyć owo przerwanie. Nie dotyczy to przerwań niemaskowalnych, które będą obsługiwane zawsze. Jeżeli warunek odblokowania programowego jest spełniony to przerwania mogą być przyjmowane w postaci priorytetów. Część działań obsługi przerwań jest wbudowana. Jeśli przerwania są odblokowane i można je obsłużyć, to:
aktualny licznik rozkazów jest wpisywany na stos. Jeżeli przerwanie pojawiło się w trakcie wykonania danego rozkazu to pokazuje on miejsce rozkazu, który będzie wykonany, gdy zakończy się rozkaz poprzedni
Stos - fragment pamięci operacyjnej, który jest interpretowany jako coś, co wskazuje miejsce w pamięci, które jest całkowicie zapełnione. Jest to rejestr, który adresuje pamięć w postaci kolejki: „ostatni wszedł, pierwszy zszedł” - „Last in, First Out” (LIFO), czyli to co na wierzch zostało włożone z wierzchu zostanie zdjęte. Są rozkazy praktycznie w każdym komputerze, które pozwalają na bezpośrednie operowanie na stosie. Są to rozkazy pozwalające wepchnąć na stos coś i zdjęcie czegoś ze stosu. Wepchnięcie i zdjęcie czegoś najczęściej dotyczy zawartości rejestru. Również w niektórych organizacjach istnieje możliwość zapakowania lub zdjęcia dowolnej wartości binarnej, którą umieści się w kodzie rozkazu. Jeżeli chcemy cokolwiek wpisać na stos to musi ulec zmniejszeniu wskaźnik stosu: SP - 1 ⇒ SP. SP wskazuje to miejsce, gdzie dane będą wpisane. Dane są zawsze w stosie wpisywane „w dół”. Muszą istnieć mechanizmy, które będą przeciwdziałać nadpisaniu czegoś używając operacji na stosie w miejsce, które nie powinno być nadpisane. Najczęściej są to zabezpieczenia programowe. Operacja zdejmowania czegoś ze stosu ma charakter odwrotny.
W fazie obsługi przerwania sprawdza się czy przerwania są odblokowane i czy dane przerwanie, które się pojawiło można obsłużyć. Jeśli te dwa warunki są spełnione to wykonują się kolejne operacje. Przechowanie śladu w liczniku rozkazów (adres lokacji na stos i status). Dalej wykonuje się skok. Polega on na wpisaniu do licznika rozkazów nowej wartości, która jest związana z przerwaniem i nosi nazwę wektora przerwań. Jest to nowa zawartość licznika stanu, która wskazuje miejsce w pamięci, gdzie zacznie się program. System przerwań pozwala na współpracę systemu komputerowego z otoczeniem oraz na współdzielenie procesora między programami.
Tryby adresowania
Tryby adresowania dotyczą obliczania adresu efektywnego. Adres efektywny jest to ten adres, który ostatecznie wskazuje lokalizację w pamięci argumentu rozkazu, czyli tej danej, która ma być pobrana i na której ma być wykonane obliczenie w danym rozkazie.
Adres argumentu = adres argumentu w rozkazie + modyfikator + ... + modyfikator
Każdy komputer działa w ten sposób, że pobiera z pamięci operacyjnej kolejne słowa, które interpretuje na kod rozkazu jako polecenie do wykonania. Polecenia te dotyczą operacji na danych w pamięci, na danej zawartości w rejestrze lub też na samych rejestrach. Przykładem rozkazu może być rozkaz skoku czyli rozkaz przejścia z jednego miejsca w programie do drugiego (warunkowy lub bezwarunkowy) i jest w rzeczywistości zmianą zawartości licznika rozkazów (licznika instrukcji).
Adresacja bezpośrednia - argument jest bezpośrednio wskazywany przez rozkaz. W trybie tym mamy dwie możliwości:
w rozkazie jest bezpośrednio wskazany rejestr, na którym należy wykonać operację. Mówimy wtedy o bezpośrednim adresowaniu, tzw. adresowaniu rejestrowym
argument lub dana dla rozkazu znajduje się bezpośrednio w kodzie rozkazu lub tuż za, czyli następne słowo lub następny bajt (zależnie od organizacji) jest tym argumentem, który jest daną dla rozkazu.
Najprostszy rozkaz - rozkaz skoku w swojej zawartości zawiera adres, do którego należy przejść. Podobny charakter ma rozkaz skoku względnego (BRENCH); w kodzie rozkazu zawarte jest względne przesunięcie względem aktualnej pozycji. Jest to aktualizacja, gdzie mamy przejść ze sterowaniem wykonania programu.
Przykłady adresacji bezpośredniej:
Adresacja pośrednia - tryb pośredni rejestrowy: argument dla rozkazu jest zawarty wewnątrz wskazanego rejestru, tzn. wykonujemy operację nie na rejestrze, tylko na tym co w nim tkwi w środku. Drugi tryb to taki, że argument umieszczony bezpośrednio w kodzie rozkazu lub za rozkazem jest adresem miejsca w pamięci, który zawiera tę daną, na której należy wykonać operację. Może wystąpić też specyficzny rodzaj adresowania pośredniego, tzw. Adresowanie podwójnie pośrednie - adres w tym przypadku nie jest adresem argumentu, lecz adresem adresu wskazującego argument. Mogą być następujące struktury rozkazu:
lub
Adresowanie względne - przesunięcie oznacza, że właściwy argument rozkazu jest przesunięty względem pewnego rejestru bazowego o +/- pewną wartość. W szczególnym przypadku rejestrem bazowym może być licznik rozkazów. Gdy występuje rozkaz „skocz względnie” oznacza to skok lokalnie pod pewną wartość w stosunku do aktualnej wartości
Adresowanie indeksowane - przesunięcie jest dodawane do zawartości rejestru, która może ulec autodekrementacji lub autoinkrementacji. Mówimy wtedy o zmniejszeniu lub zwiększeniu zawartości pewnego rejestru. Przy adresowaniu pośrednim to możemy dodać zawartość rejestru do rejestru indeksowego i dla takiej sumy szukać właściwy argument w pamięci lub też można pobrać dwukrotnie to coś, co jest wskazywane w rejestrze i dodać zawartość rejestru indeksowego. Jest to tzw. post- i preindeksacja.
Mamy tutaj taką sytuację, że zawartość rejestru indeksowego wskazuje miejsce w pamięci, w którym jest argument, tzn. mamy pośredniość indeksową i pośredniość pamięciową - dwa typy pośredniości zastosowane razem. W systemie UNIX mamy tryb indeksacyjnego adresowania bloków pamięci, gdzie wskazany blok w pamięci zawiera adresy kolejnych bloków lub też wskazań na dalsze bloki zawierające adresy. Taki sposób zagłębiania może wynieść 3, co pozwala nam zaadresować bardzo duży obszar pamięci.
Razem z trybami adresowania, przede wszystkim pośredniego łączone są tryby adresowania indeksowego i bazowego. Z trybem adresowania bazowego związany jest jeden ze sposobów technicznych adresowania pamięci operacyjnej w celu uniknięcia jej fragmentacji.
Jeżeli ustawimy rejestr, podany w sposób jawny, lub rejestr domniemany, to jeszcze dodatkowo mogą te tryby adresowania dotyczące rejestrów wymagać dalszej modyfikacji. Możemy dodać do tego co jest w rejestrze zawartość rejestru indeksowego i w ten sposób obliczyć finalny, ostateczny adres efektywny. Jeśli nie jest to tryb indeksowany, to dane są dostępne bezpośrednio, bo tkwią one w rejestrze. Jeżeli mamy podany adres, to jest on interpretowany dwojako. Albo jest on bezpośrednim argumentem rozkazu, albo wskazuje jakieś miejsce w pamięci, które zawiera argument i ten adres wskazywany może podlegać dalszej modyfikacji związanej z trybem indeksacyjnym i indeksowanym. Dodanie wartości rejestru indeksowego do adresu bazowego może być związane z autodekrementacją lub autoinkrementacją, co oznacza, że automatycznie będzie zwiększona lub zmniejszona zawartość tego rejestru indeksowego po wykonaniu operacji sumowania. Operacja ta może być pre- i post-, tzn. zwiększenie lub zmniejszenie zawartości rejestru indeksowego może się odbyć przed dodaniem lub po dodaniu.
Ogólny schemat obliczania adresu efektywnego elementu rozkazu.
W momencie kiedy zaczynamy obliczać adres efektywny, najpierw zadajemy pytanie: co jest argumentem bezpośrednim podanym w kodzie rozkazu? Czy jest to rejestr czy adres? Jeżeli jest to rejestr, to mamy dwie sytuacje. Albo rejestr ten jest w sposób jawny podany albo też mamy rozkaz, który posługuje się rejestrem domyślnym. W każdym komputerze są rejestry ogólnego przeznaczenia, rejestry podstawowe komputera, w których możemy stosować tzw. domyślność w przypadku adresowania w trybie rejestrowym. Dotyczy to licznika rozkazów, gdzie skoki względne i bezwzględne dotyczą zmiany jego zawartości. Jest to tryb adresowania domyślnego z domyślnym rejestrem. W rozkazie nie wskazuje się licznika rozkazów, sam kod rozkazu jednoznacznie określa, że o ten licznik chodzi i jego będzie dotyczyła bezpośrednio operacja. Może dotyczyć też np. wskaźnika stosu. Wszystkie rozkazy, które są związane z wywołaniem np. funkcji czy procedury danego kodu działają automatycznie na liczniku rozkazów i na stosie. Rozkazy powrotu z procedury również działają automatycznie na wskaźniku stosu, a w efekcie zmieniają zawartość licznika rozkazów. Są również rozkazy bezpośrednio operujące na wskaźniku stosu.
Fragmentacja i defragmentacja pamięci
Komputery równocześnie wykonują wiele różnych zadań, które nazywają się procesami. Przetwarzanie współbieżne polega na tym, że procesy ubiegają się i rywalizują o zasoby systemu. Zasobami oprócz pamięci operacyjnej jest procesor, wtedy, gdy jest to system jednoprocesorowy. Wszystkie systemy są systemami współbieżnymi z różnie realizowaną współbieżnością (systemy klasy UNIX i LINUX). Jeżeli każde zadanie, które ma być realizowane w komputerze będziemy „pakować” do pamięci operacyjnej w sposób ciągły, to zadanie to może się wykonać w dowolnym momencie czasu. W momencie kiedy to działanie zakończy się definitywnie, jest ono już niepotrzebne w pamięci i trzeba je usunąć. Usunięcie oznacza przekazanie obszaru pamięci, które zajmowało to zadanie do puli wolnych bloków. Nie oznacza to wymazania zawartości bloku, tylko logiczne wskazanie, że to miejsce stanie się blokiem. W związku z tym, gdy w kolejce czeka kolejne zadanie do wykonania, to może się okazać, że zadanie to wymaga większego bloku obszaru pamięci, niż wynosi wielkość właśnie zwolnionego obszaru. Nie jesteśmy w stanie przewidzieć, jaki obszar pamięci będzie czekał na to zadanie w chwili kiedy będzie ono wykonywane na komputerze. Kiedyś każde zadanie miało pewien obszar stały, który zawsze rezydował w pamięci, tzw. obszar nakładkowania lub wymiany. W obszar ten wymiennie pakowano kawałek kodu programu i ten kawałek był wykonywany. Aby sobie poradzić z tym problemem wprowadzono dwa rozwiązania: mechanizm segmentacji pamięci oraz mechanizm stronicowania.
mechanizm segmentacji pamięci. W Intelu 8086 i wyżej istnieje mechanizm segmentacji pamięci. Polega to na tym, że dla każdego kawałka programu dynamicznie wskazujemy początek obszaru wolnego, w który go wpakujemy. Następnie dzielimy kod programu na fragmenty: segment kodu, bazę tego segmentu (adres bazowy), segment danych, segment stosu i dopasowujemy wielkości segmentów do wolnej przestrzeni pamięci operacyjnej, która aktualnie jest dostępna. Od wartości rejestru bazowego zaczynają się obszary, których dotyczy nazwa tego segmentu. W kodzie rozkazu zawarte są przesunięcia względem początku segmentu.
mechanizm stronicowania. Jest to alternatywny sposób uniknięcia fragmentacji pamięci. Mechanizm ten stosowany jest w dużych komputerach. Polega on na tym, że dzielimy pamięć operacyjną na stałej wielkości bloki, zwane ramkami. Te stałej wielkości bloczki odpowiadają blokom programu, które nazywają się stronami. Wielkość adresowania i adres faktyczny, który jest adresem (argumentem) w programie dzielimy na dwie części. Mamy określoną długość rejestru stron i pozostałą długość adresu, która jest adresem związanym z przesunięciem. Przesunięcie pozostaje niezmienne, natomiast numer strony jest ciągły. Program jest tak skonstruowany, że kolejne strony występują bezpośrednio po sobie, natomiast program fizycznie w pamięci operacyjnej jest lokowany w różnych ramkach umieszczanych dowolnie. Po to aby znaleźć, w którym miejscu faktycznie dana dana znajduje się w pamięci operacyjnej trzeba dokonać konwersji. Dokonuje się konwersji lewej, bardziej znaczącej części adresu argumentu na fizyczny adres ramki. Wszystko to zapewnia nam sprzęt, ponieważ jest to mechanizm sprzętowy.
Różne rozkazy programu mogą być umieszczone w kolejnych blokach w pamięci po to aby można było dokonywać odczytów z pamięci bajt po bajcie posiadając w tym czasie możliwość odczytu „na siebie”. Taki mechanizm nazywa się przeplataniem. Wczytujemy do pamięci notatnikowej więcej niż jeden rozkaz. Najlepszym sposobem na przyspieszenie działania każdego procesora i w związku z tym każdego komputera jest pobranie do pamięci notatnikowej, która leży bardzo blisko procesora, więcej niż jednego rozkazu. Średni czas odczytu z pamięci operacyjnej jest rzędu dziesiątek ns (60, 50, 30 ns), natomiast czas odczytu z pamięci notatnikowej jest jeszcze szybszy (krótszy). Procesor jednak nie wie jak wygląda kod programu, ponieważ go nie interpretuje. W każdej chwili może wystąpić w kodzie rozkaz skoku. W takiej sytuacji sterowanie w sposób automatyczny przejdzie do nowego miejsca w pamięci i okazuje się wówczas, że te dane, które są wczytane do pamięci notatnikowej nie zawierają kodu rozkazu, który ma być wykonany. Trzeba wówczas na nowo zapełnić bufor pamięci podręcznej. Cały mechanizm stronicowania staje się bezużyteczny. Jeżeli korzystając ze stronicowanie odczytujemy coś naprzód, to trzeba to wycofać i na nowo odczytywać. Wczytując kolejne rozkazy, jeśli odczytamy prawidłowo z pamięci notatnikowej kolejny rozkaz, to trafiliśmy. Trafienie lub nietrafienie nazywa się współczynnikiem trafień. Im mamy większą tablicę stron, która dokonuje konwersji z numeru strony na numer ramki, tym bardziej czasochłonne są te operacje. W takim przypadku współczynnik trafień będzie gorszy. Sposobem na to może być zwiększenie rozmiaru strony. Jednak im większy rozmiar strony i równocześnie ramki, tym bardziej rosną średnie straty pamięci. Jeżeli jeden znak zajmuje całą ramkę, to średnia strata będzie wynosiła pół wielkości ramki (strony).
Mechanizm stronicowania jest jednym ze sposobów eliminacji fragmentacji pamięci operacyjnej. Jest to mechanizm zarządzany sprzętowo. Mechanizm stronicowania jest połączony z tzw. pamięcią wirtualną. Pamięć wirtualna jest to logiczne wydłużenie pamięci operacyjnej o pewien fragment pamięci dyskowej. Możemy zadeklarować, że plik wymiany ma pewien określony rozmiar, o którego wielkość zostaje zwiększony właśnie rozmiar pamięci operacyjnej.
Przykładowe organizacje systemów komputerowych
jedna wspólna szyna. Ma ona zespół nadajników i odbiorników. Przepływ informacji wygląda w ten sposób, że kolejny rozkaz, który ma być pobrany z pamięci jest wystawiany z licznika rozkazów na szynę adresową. Jest też bezpośrednio wysterowana pamięć, z której pobierany jest rozkaz do wykonania. Rozkaz ten płynie do sieci sterowania i podejmowana jest decyzja co ten rozkaz ma zrobić. Jeżeli rozkaz ten ma jakiś argument, to jest on pomniejszany na podstawie adresu zawartego w kodzie. W słowie bezpośrednio za kodem rozkazu, który musi być wykonany. W następnym kroku obliczany jest adres efektywny rozkazu i dana jest kierowana do obróbki. Są to tzw. szybkie obliczenia typu dodaj, odejmij, które odbywają się w układzie nazywanym ALU. Przepływ ma charakter „z góry na dół”, tzn. wyniki są kierowane do rejestru pomocniczego i ewentualnie są kierowane do akumulatora z rejestru pomocniczego.
dwie szyny danych. W tej sytuacji możliwe jest wykonywanie operacji naprzemiennego odczytu pamięci nakładających się na siebie. Oznacza to, że w trakcie wykonania (obróbki) słowa (bajta) można pobierać następne bajty z pamięci. Organizacja ta pozwala nam na to, ponieważ mamy dwie odrębne szyny zbierające informacje z pamięci.
dwie szyny danych (inna organizacja). W kolejnej organizacji mamy dwie szyny danych: szynę wejściową i szynę wyjściową. Szyny te pełnią funkcję magistral komunikacyjnych. Kolejne rozkazy są pobierane z pamięci. Jeżeli jest potrzeba pobrania dalszych argumentów z pamięci, to są one pobierane. Zawartość licznika rozkazów ulega kolejnej modyfikacji, po to aby wskazywać kolejne bajty rozkazów i argument lub informacja pobierana jest kierowana albo do rejestrów albo do akumulatora i do ALU. Wynik operacji wchodzi na szynę wyjściową i znowu jest przechowywany (zapis do pamięci). Następnie następuje rozdzielenie informacji wyjściowej przez multiplekser, który rozdziela sygnały w określone miejsca. Przekierowywanie strumieni odbywa się w zależności od tego jaki rozkaz jest wykonywany i gdzie wyniki tego rozkazu mogą być skierowane.
System komputerowy oparty na Intelu 8086 (16 bit.). Sam procesor składa się z:
ALU,
rejestru znaczników,
układu obliczającego adres efektywny,
rejestrów ogólnego przeznaczenia,
wskaźnika stosu.
Układy sprzęgające sprzęgają magistralę z pamięcią, np. RAM, ponieważ musi być możliwość komunikacji z otoczeniem, tzw. sprzęgi.
Intel charakteryzuje się tym sposobem adresowania pamięci eliminującym fragmentację, który nazywa się segmentacją, w związku z tym występują w nim rejestry segmentowe. Rejestr segmentu kodów (CS), licznik rozkazów, rejestry ogólnego przeznaczenia (rejestry typu akumulatory, rejestry bazowe i indeksowe), wskaźnik stosu (16 bit.). Rejestr stosu razem z segmentem (rejestr segmentu stosu) tworzą razem 20-bitowy adres miejsca w pamięci operacyjnej, gdzie jest wskaźnik stosu. Układ obliczania nie jest tylko elementem, który wylicza faktyczny adres na podstawie tzw. segmentacji. Wykonuje on również obliczenia adresu efektywnego. Proces ten jest wygląda następująco. Zawartość rejestru segmentowego jest przesuwana o 4 pozycje w lewo, czyli pomnożona przez 16, a następnie wykonywane jest sumowanie dwóch adresów: 20-bitowego adresu i 4-bitowego adresu przesunięcia. Razem tworzy to 20-bitowy adres efektywny argumentu.
Przetwarzanie
Program - zapis postępowania, algorytm przetłumaczony na kod + dane. Nie ma programu takiego, aby procesor nie musiał pracować. Aby procesor mógł reagować na warunki zewnętrzne musi wykonywać jakiś program, być w stanie oczekiwania na przerwanie.
Przetwarzanie oznacza, że obok programu i komputera musi istnieć użytkownik lub instytucja, która zleci nam przetwarzanie.
Model przetwarzania - obok samego przetwarzania musi zawierać to, co zarządza przetwarzaniem. Zarządzanie, czyli decydowanie o tym co ma zostać przetworzone jako pierwsze, co jako drugie, a co ma nie być wcale przetworzone.
Architektura - sposób skonfigurowania całego systemu, a w szczególności oprogramowania.
Typy przetwarzania:
scentralizowane - całość przetwarzania odbywa się na jednej jednostce obliczeniowej.
rozproszone - różne składniki tworzących całość aplikacji są rozrzucone po czymś, co się nazywa siecią lokalną i pełnią one swoje pewne określone zadania.
sieciowe - mamy tutaj przetwarzanie dwu- lub trzywarstwowe. W przypadku przetwarzania dwuwarstwowego (klient/serwer) aplikacja kliencka jest załadowana i uruchomiona na komputerze użytkownika, zaś serwery rozproszone są w sieci świadczą usługi na żądanie klienta. W przypadku przetwarzania trzywarstwowego istnieje jeszcze warstwa pośrednicząca, tzw. warstwa usługowa. Aplikacja kliencka jest zubożona, natomiast wszelkie zmiany są dokonywane w jednym punkcie, tzw. serwerze biznesowym lub serwerze usługowym, który zapewnia komunikację między aplikacją klienta, a docelowymi serwerami realizującymi zadania zlecone przez klienta.
zespołowe - nie dość, że jest to przetwarzanie sieciowe, to jeszcze o tym jak ma to być przetwarzane decyduje człowiek.
Przetwarzanie scentralizowane może być wykonane następującymi sposobami:
sekwencyjnie - czyli zadanie po zadaniu;
współbieżnie - wiele zadań wykonuje się równocześnie w pewnym przedziale czasu;
równolegle - pojedyncze zadanie (o ile się da) może być zrównoleglone. Może być ono organizowane dwojako:
na poziomie równoległości funkcji;
na poziomie równoległości danych.
Tryby adresowania w Motoroli
Adres - numer komórki pamięci.
Tryb adresowania - sposób wskazywania danych.
Można wyróżnić dwie grupy rozkazów:
rozkazy przesłań i rozkazy arytmetyczno-logiczne. W grupie tej adresowanie polega na umiejscowieniu argumentu operacji. Czyli podanie informacji, skąd pobrać dane, gdzie je umieścić, skąd pobrać argument (argumenty) operacji arytmetyczno-logicznej i dokąd przesłać wynik;
rozkazy skoków. Celem adresowania jest wskazanie danych, na podstawie których zostanie utworzony adres skoku, wprowadzony do licznika rozkazów w końcowej fazie realizacji rozkazu skoku.
Tryb wewnętrzny (wbudowany, nieodłącznie związany) - kod rozkazu jednoznacznie wskazuje gdzie jest argument.
CLRA - (clear A). Oznacza wyzerowanie zawartości akumulatora A;
TSX - (transfer stack to X). Przesłanie zawartości rejestru wskaźnika stosu do rejestru indeksowego X. Aby wykonać ten rozkaz potrzeba jednego dostępu do pamięci związanego z pobraniem kodu rozkazu z pamięci;
RTS - (return to subroutine). Powrót z podprogramu. Oznacza odtworzenie ze stosu na podstawie zawartości wskaźnika, wskazanych przez wskaźnik stosu tych nastaw licznika rozkazów w chwili wskazania rejestru. Potrzebne są co najmniej 3 dostępy do pamięci - jeden na odczytanie kodu rozkazu i dwa kolejne na pobranie nowej zawartości licznika rozkazów.
Tryb bezpośredni - za kodem rozkazu bezpośrednio występuje argument tego rozkazu.
LDAA #$FE - (load accumulator A). Ładuj akumulator A określoną wartością. Zapis asemblerowy będzie zajmował w pamięci dwa bajty. Jeden bajt będzie kodem rozkazu, a drugi argumentem - liczbą binarną;
LDX #$1234 - (load index register X). Zapisanie pewnej wartości w rejestrze o długości 16 bitów. W związku z tym argument musi być również 16-bitowy. Wykonanie tego rozkazu musi zająć co najmniej 3 dostępy do pamięci - jeden na pobranie kodu rozkazu i dwa kolejne do pobrania kolejnych części argumentu.
Po każdym pobraniu argumentu zawartość licznika rozkazów zwiększa się o 1. W chwili gdy zacznie się pobieranie drugiego bajta tego rozkazu licznik rozkazów będzie wskazywał pierwsze miejsce za argumentem. Natychmiast po wysłaniu zawartości licznika rozkazów na szynę adresową, czyli rozpoczęciu cyklu pobierania czegoś, co wskazuje licznik rozkazów, jego zawartość ulegnie zwiększeniu o 1. Licznik rozkazów wskazuje następny rozkaz do wykonania i możemy się o tym dowiedzieć tylko w tych momentach, gdy użytkownik może zobaczyć zawartość tego licznika, a dzieje się to tylko wtedy, gdy skończy się jeden rozkaz i nie zacznie się jeszcze drugi.
Tryb rozszerzony i pośredni. Argument jest 8-bitowy i oznacza adres miejsca pamięci w stosunku do pierwszych 256 bajtów. W trybie normalnym o standardowych, fabrycznych ustawieniach, po resecie RAM znajduje się w dolnych 256 bajtach. W związku z tym, gdy nie przestawiamy lokalizacji pamięci, to w tym trybie pracy możemy odwoływać się bezpośrednio do lokalizacji związanej z pamięcią RAM. W trybie pośrednim argumentem są adresy wskazujące miejsce w pamięci, gdzie znajduje się argument. Dla tego trybu adres jest 8-bitowy, przy milczącym założeniu, że osiem bardziej znaczących bitów jest równych zeru. W trybie normalnym rozszerzonym podajemy cały, 16-bitowy adres.
LDAA $1010 - oznacza, załaduj do akumulatora A zawartość miejsca w pamięci wskazywaną przez adres $1010 (heksalnie). Rozkaz ten wymaga 4 dostępów do pamięci - jeden na pobranie kodu rozkazu, dwa aby pobrać adres argumentu oraz jeden aby pobrać argument;
LDX $17 - załaduj rejestr X dwoma bajtami kolejno począwszy od adresu $17 heksalnie. W tym rozkazie również wymagane są 4 dostępy do pamięci - jeden do pobrania kodu rozkazu, jeden do pobrania adresu okrojonego do przesunięcia w obrębie pierwszych 256 bajtów oraz dwa do pobrania z tego adresu argumentu, który ma być wpisany do rejestru X.
Tryb adresowania indeksowego i względnego. Adresacja indeksowa to nic innego jak złożenie adresu argumentu rozkazu z dwóch wartości. Bazą jest zawartość wskazanego rejestru indeksowego, natomiast przesunięcie w stosunku do tego adresu będzie argumentem rozkazu.
LDAA OFFSET,X - zapisz akumulator A zawartością miejsca pamięci, którego adres jest sumą zawartości rejestru X i przesunięcia podanego w rozkazie (OFFSET). Będą potrzebne co najmniej 3 dostępy do pamięci (4 - gdy będzie to rozkaz z udziałem rejestru Y) - jeden do pobrania kodu rozkazu, jeden do pobrania przesunięcia. Teraz procesor dokona wyliczenia sumy zawartości rejestru X i przesunięcia i następnie w kolejnym dostępie do pamięci jest pobierany argument, który ma być wpisany do akumulatora.
Tryb adresowania względny. Wykorzystywany jest w rozkazach typu BRENCH (skocz lokalnie). Oznacza to przesunięcie miejsca w stosunku do licznika rozkazów w chwili zakończenia wykonywania programu. Przesunięcie będzie liczone w stosunku do pierwszego wolnego miejsca, które wystąpi po kodzie rozkazu. Jeżeli rozkaz zajmuje 1 bajt, to wielkość przesunięcia również będzie wynosić 1 bajt.
Podstawowe elementy budowy mikroprocesora Motoroli
W mikrokontrolerze Motoroli wbudowane są następujące układy:
układ czasowy - do realizacji funkcji kontroli czasowej;
układ zliczania impulsów;
porty szeregowe i równoległe;
przetwornik A/C;
ROM;
E2PROM
RAM.
Nóżki są współdzielone, w różnych trybach pracy różnego rodzaju bity statusowe (rejestr warunków CC) określają w jakim stanie dana nóżka ma się znajdować.
W mikrokontrolerze występują porty, które mogą spełniać różnego rodzaju alternatywne funkcje. Zmiany standardowego przeznaczenia portów dokonujemy poprzez odpowiednią konfigurację mikrokontrolera zapisując odpowiednie wartości w rejestrach konfiguracyjnych, które są umieszczone w przestrzeni 64 bajtów począwszy standardowo od adresu $1000. W inicjalizacji standardowej porty te mają następujące przeznaczenia:
Port A - jest portem mającym 4 wejścia (IC - input capture), które służą do obserwacji i rejestracji przede wszystkim zmiany poziomu zbocza sygnału impulsowego. Jeżeli port ten ma 4 wejścia, to musi posiadać także 4 wyjścia (OC - output compare). Układ może być skonfigurowany na 2 sposoby. Pierwszy z nich to 4 x IC + 4 x OC. Drugi to 4 x OC + 3 x IC + PC (pulse accumulator). PC - czyli licznik impulsów wejściowych może być zamieniony na piąte wyjście OC. Jeżeli port A zostanie zaprogramowany do pracy jako specyficzny układ do analizowania impulsów zewnętrznych lub do ich porównywania, to jest on standardowym wejściem/wyjściem.
Porty B i C - jeżeli nie są specyficznie skonfigurowane, to są zwykłymi portami. Port B - wyjściowy, port C - dwukierunkowy i równoległy. W przypadku, gdy cały mikrokontroler pracuje w trybie expanded (rozszerzonym) jest to ten tryb pracy, w którym możemy doczepić do mikrokontrolera zewnętrzną pamięć ROM i uruchamiać z niej programy, po to aby przetestować ich działanie zanim zostaną one na sztywno wsadzone do pamięci wbudowanej mikrokontrolera. W przypadku tego trybu port B jest ośmioma bardziej znaczącymi bitami adresu, a port C, w zależności od momentu cyklu rozkazowego albo ośmioma mniej znaczącymi bitami adresu, albo dwukierunkową szyną danych (8-bitową), gdzie dane możemy wpisywać lub odczytywać z mikrokontrolera.
Port D - pełni on 3 funkcje:
może służyć do transmisji asynchronicznej, wówczas wykorzystujemy dwie nóżki;
może służyć do transmisji szeregowej synchronicznej, wówczas wykorzystujemy sześć nóżek;
może być także portem ogólnego przeznaczenia.
Port E - może być portem ogólnego przeznaczenia ale jego zasadniczym przeznaczeniem jest praca jako portu pełniącego funkcję zewnętrznego konwertera sygnałów analogowo-cyfrowych.
MODA i MODB - mają znaczenie wtedy, gdy układ znajduje się w stanie bezpośrednio po resecie. Chwilę po resecie sczytywane są stany tych nóżek i tylko wtedy w zależności od ustawionej na nich wartości mają wpływ na wybór pracy układu.
IRQ, XRQ. IRQ (interrupt request) - żądanie przerwania; XRQ - niemaskowalne żądanie przerwania. Do tych nóżek dołączane są źródła sygnałów zewnętrznych, które są interpretowane przez mikrokontroler jako sygnały przerwań. Przerwanie - jest to sygnał, który jest interpretowany przez procesor w określonym miejscu cyklu rozkazowego o ile są odblokowane przyjęcia przerwań. Do tego kontrolera docierają tylko dwie grupy sygnałów. Pierwsza grupa sygnałów może być zamaskowana programowo, tzn. nie będziemy reagować na przychodzący sygnał. Drugi typ przerwań, to przerwania niemaskowalne. Wymagają one obsługi ze strony komputera bez względu na to co się wewnątrz dzieje. Może to być przerwanie oznaczające spadek napięcia zasilania poniżej jakiegoś progu. Jeżeli przerwanie niemaskowalne pojawi się to maskuje ono automatycznie możliwość przyjmowania przerwań maskowalnych, ponieważ ma ono wyższy priorytet, jest ono ważniejsze.
XTAL, EXTAL - dwie nóżki służące do dołączenia zewnętrznego generatora kwarcowego.
Podstawowe tryby pracy mikrokontrolera Motoroli
W Motoroli istnieje rejestr konfiguracyjny, który pozwala na relokację różnych pamięci, różnego typu. Układ z fabrycznymi nastawami w momencie włączenia zasilania będzie prezentował się następująco. Obszar pamięci RAM będzie zajmował pierwsze 256 bajtów, czyli adres od $0000 do $00FF. Wśród rejestrów znajduje się rejestr zbierający informację, gdzie który moduł jest ulokowany. Standardowo jest on umieszczony po włączeniu zasilania pod adresem $1000 i zajmuje on obszar 64 kolejnych bajtów. W układzie są też przydzielone dwa obszary pamięci na E2PROM i ROM. Ogólnie rzecz biorąc rejestr ten mówi nam, czy występuje w zestawie zewnętrzna wbudowana pamięć RAM i ROM, czy też nie. Rejestr ten może być zapisany w trakcie trwania pierwszych 64 cykli pamięciowych.
Tryb pracy wybierany jest w chwili gdy układ jest bezpośrednio po resecie. Wtedy badany jest stan nóżek MODA i MODB. Zawartość rejestrów konfiguracyjnych określa, w którym miejscu przestrzeni adresowej znajduje się która pamięć. Pamięć można zaprogramować podczas pierwszych 64 cykli maszynowych po każdym restarcie (resecie). Wobec tego trzeba tak zorganizować program, aby ustawić odpowiednio tryb pracy mikrokontrolera i dobrać odpowiednią lokalizację pamięci. Wszystkie te ustawienia są w rejestrze INIT. Jest to rejestr, który definiuje, w którym miejscu pamięci mają się znajdować pamięci RAM, oraz w którym miejscu ma znajdować się tablica rejestrów. Na obszar pamięci liczący 64 kilobajty mamy możliwość wpisania na 4 bitach 16 różnych kombinacji. Oznacza to, że dysponujemy tu kwantem relokacyjnym równym 4 kilobajty. Możemy zapakować 256 bajtów RAM-u na początek każdego segmentu 4-kilobajtowego na sztywno.
Ostatnie 64 bajty pamięci ROM tworzą tablicę wektorów przerwań. Każdy z tych wektorów jest słowem 16 bitowym zawierającym adres podprogramu obsługi konkretnego przerwania.
Tryb podstawowy pracy mikrokontrolera charakteryzuje się tym, że wszystkie 5 portów pracuje w przewidziany do tego sposób (podstawowy). Program, który jest wykonywany w mikrokontrolerze jest pobierany z pamięci ROM. Jest to tryb pracy nazywany trybem pracy układu wbudowanego (dedykowanego) Cały system jest sterowany zdarzeniami zewnętrznymi.
Tryb rozszerzony pozwala na przełączanie działania programu między pamięcią wbudowaną, a pamięcią dołączoną do mikrokontrolera. Do tego celu trzeba użyć dodatkowego układu PERI, który pozwala wyeksportować poza układ stan niektórych potrzebnych do tego celu linii. Układ ten pozwala na wyprowadzenie na zewnątrz 16-bitowej linii adresowej oraz linii danych. Nóżka E określa, z której pamięci należy pobrać program do wykonania. Tryb ten głównie jest wykorzystywany do testowania aplikacji.
Special boot, special test. Używane są do celów testowych. Special boot pozwala na załadowanie do wewnętrznej pamięci RAM pewnego krótkiego programu posługując się łączem szeregowym.
Resety
Resetu - ponowna inicjalizacja systemu. Mamy kilka rodzajów resetów:
reset związany z brakiem funkcjonowania zegara. Jeśli częstotliwość zegarowa spadnie poniżej pewnego progu to generowany jest sygnał resetu. Zapobiega to odłączeniu zegara;
reset związany ze startem komputera. Po włączeniu komputera musi być mechanizm wymuszający jego start z określonego miejsca;
reset związany z opadnięciem poziomu zasilania poniżej pewnego progu i podniesieniem się go z powrotem.
reset związany z układem WATCHDOG będącego układem sterownika czasowego w mikrokontrolerze. Watchdog'i stosowane są do przeciwdziałania zawieszenia się programu. Wygląda to następująco: istnieje pewien rejestr sterownika czasowego (watchdog), który jest przy restarcie lub po resecie komputera ustawiany pewną standardową wartością. Podczas pierwszych 64 cykli jak również i później może on zostać ustawiony na maksymalną wartość jaką można tylko zapisać - jest to zadanie programisty. Każdy cykl zegarowy, każde wykonanie rozkazu mającego kilka cykli rozkazowych powoduje zmniejszenie zawartości rejestru watchdog o pewną wartość. Jeżeli rejestr ten nie zostanie przez program ponownie odświeżony to po wyzerowaniu tego rejestru generowane jest przerwanie easy watchdog, po którym następuje reset komputera. Wadą tego systemu jest to, że jest on uzależniony od zegara, jeśli ten zaś zostanie uszkodzony to nie zostanie wykryte zawieszenie się programu. W tym celu powstało przerwanie informujące o fakcie przerwania przez zegar pracy. Watchdog rozpoczynają działanie wraz ze startem komputera - COP (computer operates properly).
Istnieje wektor obsługi przerwania jakim jest reset, ponieważ zawsze musi być taka sytuacja, że po włączeniu zasilania komputer musi ruszyć z pewnego miejsca. Wektor ten ma najwyższy priorytet. Reset jest niezależny od trybu pracy, który poprzednio istniał w mikrokontrolerze. Niezależnie czy był to tryb single chip czy expanded działanie resetu jest takie samo.
Co się dzieje, gdy wystąpi reset? Akcja jest taka sama jak przy przerwaniu z wyjątkiem zachowywania czegokolwiek na stosie. Po resecie zawartość wskaźnika stosu jest nieustalona i nie ma możliwości wpychania czegokolwiek na stos. Wtedy działanie mikrokontrolera startuje od określonego miejsca w pamięci. To co wpisze programista jako adres początku programu obsługi resetu, to od tego miejsca wystartuje program. W procesorze zapisany jest tylko licznik rozkazów zawartością miejsca pamięci wskazanego przez dany typ resetu. Zawartości akumulatora, rejestrów indeksowych i rejestru wskaźnika stosu są nieustalone. W rejestrze flag CCR bity I oraz X są ustawione na 1, co oznacza zablokowanie możliwości przyjmowania przerwań. Po resecie nie mogą być przyjęte jakiekolwiek przerwania, ponieważ nieustalona jest jeszcze zawartość wskaźnika stosu i przerwanie to nie mogłoby być poprawnie obsłużone. Mapę pamięci ustawia rejestr INIT. Do tego rejestru na określone pozycje wpisywana jest sekwencja $5, która oznacza, że RAM będzie od 0-256 bajtów. Obszar 64 rejestrów będzie od 4 kilobajta, a pamięć EPROM, ROM i E2PROM będzie lub nie w zależności od tego co jest zapisane w rejestrze CONFIG. Rejestr ten może być zapisany w czasie pierwszych 64 cykli po resecie. W rejestrze tym określamy kwestię obecności innych typów pamięci, takich jak ROM i E2PROM. Funkcje timera: licznik jest ustawiany na 0 i wstępny podzielnik też na 0, także inne flagi związane z przerwaniami również ustawiane są na 0 - co wskazuje, że nie wystąpiło żadne przerwanie. Po resecie większość układów wbudowanych wewnątrz mikrokontrolera ustawia się w taki stan, który nie wskazuje aby czekało jakieś przerwanie, ani że jest wykonywana jakaś operacja, która wskazuje konieczność obsługi. Watchdog jest uruchamiany jeśli odpowiedni bit w rejestrze CONFIG jest odblokowany. Prędkość bodowa jest nieustalona. Wszystkie przerwania związane z obsługą nadajnika i odbiornika są zablokowane co oznacza, że bufory nadajnika i odbiornika są puste - żaden znak nie czeka ani na nadanie, ani na odebranie. Łącze synchroniczne (dwie nóżki portu D są łączem asynchronicznym, 4 - synchronicznym) pełni funkcję łącza szeregowego synchronicznego lub asynchronicznego. Nóżki portu synchronicznego są „ubezwłasnowolnione” - jest to normalny port we/wy traktowany jako port ogólnego przeznaczenia. Konfiguracja konwertera jest nieokreślona. Flaga zakończenia konwersji jest ustawiona na 0, czyli tak jakby aktualnie nic się nie działo.
Rejestry w mikrokontrolerze
Mikrokontroler ma dwa rejestry akumulatora oznaczone jako rejestr A i B. Są one 8-bitowe. Cały mikrokontroler ma organizację bajtową (8-bitowy procesor). Szyna adresowa jest 16-bitowa, co pozwala zaadresować 64 kbajty pamięci. Ze względu na przestrzeń adresową muszą w tym procesorze wystąpić rejestry 16-bitowe, które będą służyć do przechowywania czegoś, co może być adresem. W związku z tym dwa połączone rejestry akumulatora tworzą tzw. akumulator podwójnej długości - rejestr double D.
Dwa rejestry indeksowe do realizacji trybu adresowania indeksowego. Oba są 16-bitowe i noszą nazwę rejestrów X i Y. Wszystkie rozkazy, które odwołują się do rejestru . Wszystkie rozkazy, które odwołują się do rejestru Y są poprzedzane bajtem poprzedzającym (prebajtem).
Licznik rozkazów (PC - program counter; IC - instruction counter). Jest to kluczowy rejestr komputera o wielkości 16 bitów, który przechowuje adres następnego rozkazu do wykonania.
Rejestr stosu zawiera wskaźnik, który wskazuje miejsce w pamięci RAM, które jest wierzchołkiem stosu. Inaczej mówiąc, pierwszym wolnym do zapisania bajtem pamięci, przy operacji na stosie. Operacje na stosie odbywają się w ten sposób, że zapisujemy bajt w miejsce wskazywane przez wskaźnik stosu i zmniejszamy jego zawartość o 1. Natomiast zdjęcie ze stosu musi być poprzedzone zwiększeniem wartości wskaźnika o 1.
Efekty działania na rejestrach akumulatora A i B znajdują odniesienie każdorazowo w rejestrze warunków CCR. Rejestr ten składa się z dwóch grup bitów. Jedna grupa bitów jest to grupa 5 bitów, które są ustawiane w efekcie wykonania każdego rozkazu, który powoduje jakikolwiek rezultat arytmetyczny. Druga grupa 3 bitów służy do maskowania przerwań lub zablokowania operacji STOP.
Bity w rejestrze warunków mają następujące znaczenia:
C (carry) - przeniesienie; jest on generowany przy operacji arytmetycznej poza najbardziej znaczącym bitem;
Z (zero) - w wyniku działania na akumulatorze wszystkie jego bity mają wartość równą zero;
N (negative) - bit znaku;
V (overflow) - przepełnienie akumulatora;
H (half carry) - w mikroprocesorze możliwe jest wykonywanie operacji na bazie kodu BCD. Operujemy wówczas cyframi dziesiętnymi zapisanymi na czterech bitach. Wówczas wykonanie takiej operacji na mniej znaczących bitach powoduje, w przypadku wygenerowania przeniesienia z 4 bitu na 5, ustawienie flagi H;
dwa najbardziej znaczące bity S i X oraz czwarty I pozwalają na zablokowanie odpowiednio możliwości zablokowania komputera, zablokowanie przerwań niemaskowalnych oraz maskowalnych. O ile bit przerwań maskowalnych można ustawić na 1 i zablokować przyjmowanie przerwań programowo, o tyle nie można tego zrobić z przerwaniami niemaskowalnymi. Bit przerwań niemaskowalnych jest ustawiany sprzętowo, gdy pojawi się przerwanie i może być odblokowane przez oprogramowanie. Możemy też zezwolić na przyjmowanie, gdy zakończy się obsługa przerwania.
Rejestr HPRIO odpowiedzialny jest za ustawienie stanu komputera po resecie. Prawa czwórka bitów (bit 0, 1, 2, 3) ma zastosowanie do ustawiania priorytetu przerwań maskowalnych. Można wybrać, które przerwanie maskowalne ma być na najwyższym priorytecie. W związku z tym mamy możliwość przewrócenia porządku przerwań maskowalnych, w sensie nadania któremuś z nich najwyższego priorytetu. Bit RBOOT związany jest bezpośrednio z dwiema nóżkami mikrokontrolera (MODA i MODB), których stan jest badany w chwili wyjścia komputera z resetu. Te dwie wymienione nóżki odpowiedzialne są za wybór trybu pracy mikrokontrolera. SMOD oznacza wybór trybu specjalnego. MDA oznacza zaś tryb normalny albo tryb specjalny.
Rejestr CONFIG. W czterech mniej znaczących bitach ustawia się fakt obecności pamięci. Bity 1 i 0 informują o tym, że występuje pamięć E2PROM (bit 0) lub pamięć ROM (bit 1). Jeżeli bit jest ustawiony na zero to oznacza to, że dana pa
mięć nie występuje w układzie. Bit 2 - NOCOP oznacza wyłączenie lub włączenie watchdoga.
Rejestr INIT - odpowiedzialny jest za ustawienie lokalizacji pamięci RAM oraz pamięci zespołu rejestrów (64 bajty). Rejestr ten może być zapełniony podczas pierwszych 64 cykli. Możemy ustawić w tym czasie informację, w której przestrzeni konfiguracyjnej ma się znajdować pamięć RAM oraz rejestry konfiguracyjne. Są one relokowane co 4 kilobajty, co daje nam 16 możliwości konfiguracji.
Rejestr OPTION pozwala na ustawienie opcji konfiguracji systemu. Cztery bity mogą być ustawiane tylko podczas pierwszych 64 cykli zegarowych po resecie. Bit IRQE określa charakter wyzwalania przerwań. Przerwania możemy wyzwalać poziomem albo
narastającym zboczem. Bit DLY oznacza włączenie czasu opóźnienia uruchomienia mikrokontrolera po resecie. Jest to okres 4000 cykli zegarowych, które przeczekuje mikrokontroler w celu ustabilizowania się drgań oscylatora. Bit ADPU konfiguruje port E i jeżeli jest 1 to przetwornik AC pracuje jako układ wejściowy. Bit CSEL nie jest ustawiany podczas pierwszych 64 cykli zegarowych. Oznacza on możliwość sterowania nagrywaniem E2PROM czyli wpisywaniem do niego jakichś informacji. Bity CR1 i CR0 ustawiają skalę działania watchdoga poprzez ustalenie pewnego mnożnika lub dzielnika, według którego następuje ustalenie zakresu działania tego układu kontrolującego. Bit CME odblokowuje sygnalizację przerwań zegara w momencie gdy zegar przestaje funkcjonować.
Działanie wybranych rozkazów
LDX, LDY, LDS - zapisz jakąś wartość do rejestru, rozkazy te dotyczą pobrania czegoś z pamięci i zapisania do wskazanego rejestru. W pamięci zapisywane są wartości w takiej kolejności, że jako pierwszy o adresie mniejszym jest zapisywany bardziej znaczący bajt.
PULA, PULB - oznacza pobranie czegokolwiek według wskazań wskaźnika stosu. Przy pobieraniu czegoś ze stosu, najpierw jest zwiększana zawartość stosu o 1, bowiem stos w danej chwili wskazuje pierwsze wolne miejsce do zapisania. Wówczas, jeżeli chcemy cokolwiek ze stosu zdjąć, najpierw musimy zwiększyć wskaźnik stosu o 1 i wtedy on wskazuje pierwsze miejsce ostatnio zapisane. Operacje zapisu również za pomocą wskaźnika stosu. W tym przypadku jednak najpierw zapisujemy określoną daną w miejsce wskazane przez wskaźnik, a dopiero potem zmniejszamy jego wartość o 1.
STAA - wpisanie do pamięci zawartości danego rejestru. W przypadku rejestrów dwubajtowych wpis odbywa się w ten sposób, że najpierw zapisujemy bardziej znaczący bajt, a potem mniej znaczący. W adresie niższym znajduje się bardziej znaczący bajt. Rozkazy typu store wymagają kilku dostępów do pamięci: pobranie kodu rozkazu; dwa cykle dostępu aby pobrać adres, do którego należy zapisać to coś co jest w rejestrze; dwa dostępy, aby w kolejnych dwóch bajtach począwszy od podanego adresu zapisać określony 16-bitowy długi rejestr, podwójny akumulator, rejestr indeksowy X lub Y, rejestr stosu SP.
TBA - przeniesienie zawartości rejestru B do rejestru A. W wyniku działania tej operacji oba rejestry będą miały taką samą zawartość jaką miał przed operacją rejestr B.
TAB - sytuacja odwrotna do poprzedniej. Rejestry będą mieć taką samą zawartość jak przed operacją rejestr A. W tych dwóch operacjach została poruszona kwestia tego, że przesłanie czegoś z rejestru do pamięci, czy do rejestru, nie niszczy zawartości rejestru źródłowego.
TXS, TYS, TSX, TSY - operacje przesłania zawartości rejestrów indeksowych do rejestrów stosu lub odwrotnie. Służą one do zmiany wartości wskaźnika stosu. Rozkazy, które pozwalają zmienić zawartość podwójnego akumulatora i rejestru indeksowego jak i również wymienić zawartości rejestrów indeksowego i stosu, pozwalają na obliczeniowe „szachrajstwa” z użyciem wskaźnika stosu.
DECA, DECB, DES, DEX, DEY, INCA, INCB, INS, INX, INY - instrukcje służące do manipulacji zawartością rejestrów. Często zachodzi potrzeba zwiększania lub zmniejszania o 1 zawartości rejestru, najczęściej sytuacja taka ma miejsce przy realizacji różnego rodzaju pętli. Instrukcjami tymi możemy zwiększać lub zmniejszać o 1 także zawartości rejestrów podwójnych oraz wartości wybranej komórki pamięci. Rozkazy, które zwiększają lub zmniejszają dane, w szczególności jeżeli będą dotyczyły zawartości określonych komórek pamięci czyli będą wykorzystywały jeden z trybów adresowania najczęściej indeksowy lub pośredni będą wymagały kilku dostępów do pamięci. Operacje te wymagają co najmniej 5 tych dostępów i jednego lub dwóch cykli rozkazowych. W przypadku kiedy jest to rozkaz wykorzystujący rejestr indeksowy, będzie potrzebny dodatkowy dostęp do pamięci. Należy też zauważyć, że wszystkie rozkazy dotyczące rejestru indeksowego Y mają tzw. prebajt, czyli bajt poprzedzający czyli identyfikujący, że chodzi właśnie o operacje na rejestrze Y. Ile trzeba dostępów do pamięci, aby wykonać zwiększenie o 1 zawartości wskazanej komórki pamięci? Jeden cykl na pobranie kodu rozkazu; dwa kolejne na pobranie adresu miejsca pamięci, pod którym znajduje się argument; jeden cykl na pobranie zawartości miejsca w pamięci; po zwiększeniu o 1 w kolejnym cyklu wpisanie do tego samego miejsca w pamięci już zmodyfikowanej liczby. Należy zauważyć, że najczęściej typowe pamięci RAM nie mają możliwości bezpośredniego zwiększania o 1 wskazanej komórki pamięci.
NEG, NEGA, NEGB - instrukcje te służą do zanegowania określonego miejsca w pamięci lub rejestru, czyli konkretnie dokonania uzupełnienia do zera. Większość pamięci nie ma możliwości dokonania takiej operacji bezpośrednio, więc w związku z tym potrzebne jest kilka dostępów do pamięci. Są one następujące: jeden cykl na pobranie kodu, dwa na pobranie adresu (lub jeden w zależności od typu adresowania), pobranie wartości z odpowiedniego miejsca w pamięci i po dokonaniu operacji na tej wartości ponowne jej wpisanie w następnym cyklu z powrotem do pierwotnego miejsca w pamięci. Dostępy do pamięci rozdzielone obliczeniem nowej wartości traktowane są jako jeden rozkaz, więc nie będą rozdzielone żadnym przerwaniem. W omawianym kontrolerze istnieje możliwość zanegowania bitów - jest to nic innego, jak wpisanie na pewne określone bity pewnej określonej maski jedynek i wykonanie sumy logicznej. W przypadku zerowania wykonuje się iloczyn logiczny z zanegowaną maską, czyli te bity, które są ustawione na 1 w masce są wyzerowane. W przypadku takiego rozkazu będzie potrzebnych 5 (lub 6) dostępów do pamięci - pobranie rozkazu; pobranie maski; dostęp do pamięci ażeby pobrać jego zawartość i po wykonaniu iloczynu zapisanie jego wyniku do pamięci.
ROL, ROLA, ROLB, ROR, RORA, RORB - operacje pomocne do konwersji bitowych, do zamiany kolejności bitów w słowie. Jeżeli mamy bajt, w którym tak chcemy ułożyć bity, aby bit pierwszy stał się ostatnim, co jest równoznaczne z odbiciem symetrycznym. W odpowiednich zastosowaniach może też wchodzić w rachubę zamiana czwórek bitów, co ma miejsce przy operowaniu na liczbach w kodzie BCD.
Przesunięcie cykliczne dokonuje się z użyciem rejestru jednobitowego (CARRY). Przy przesunięciu arytmetycznym w lewo, lub w prawo w miejsce skrajnych bitów wchodzą zera, zaś w przypadku przesunięcia arytmetycznego w prawo najbardziej znaczący bit (bit znaku) jest powielany.
Rozkazy typu BRANCH - są to rozkazy posługujące się przesunięciem względnym i dotyczą one możliwości przemieszczenia zawartości licznika rozkazów w stosunku do aktualnej wartości o <-128;127>. Do tych wartości trzeba jeszcze dodać 2 jako efektywny wynik działania rozkazu, ponieważ w momencie wykonania rozkazu licznik rozkazów wskazuje pierwsze wolne miejsce w pamięci za rozkazem BRANCH. Ten zaś zajmuje właśnie dwa bajty: kod rozkazu i wartość przesunięcia.
Rozkazy skoków długich warunkowych nie występują w mikrokontrolerze Motoroli. Istnieje tylko rozkaz JUMP TO ADDRESS. Skok ten ma trzy bajty. Zawsze w każdej sytuacji zmieni zawartość licznika rozkazów, czyli wpisze atrybuty lub argument tego rozkazu do licznika rozkazów. Skoro nie ma skoków długich warunkowych, no to mamy problem jeżeli budujemy program i chcemy wykonać rozwidlenia w tym programie sięgające głębiej niż 128 bajtów w górę lub w dół. Takie rozwidlenie w programie musimy zorganizować w sposób dwojaki: zamiast posłużyć się jednym rozkazem skoku warunkowego musimy użyć dwóch. Załóżmy, że mamy jakąś sekwencję rozkazów w pamięci typu ROM, patrz rysunek obok. Mamy tutaj instrukcję BREQ. Jeżeli za jej pomocą chcemy zdecydować o skoku w miejsce odległe o więcej niż 127 bajtów to rozkaz ten nie wykona tego skoku. Możemy to zrealizować poprzez wstawienie rozkazu JUMP. Trzeba użyć co najmniej dwóch rozkazów takich skoków, aby zrealizować rozszerzenie warunkowe w programie, tzw. długie, dalekosiężne. W szczególności trzeba użyć tej konstrukcji wtedy, gdy przekierowanie w górę lub w dół będzie dalekosiężne. Do tego celu niestety nie można użyć skoku do podprogramu, ponieważ powrót z podprogramu wymaga zastosowania odpowiedniej instrukcji. Skok do programu jest wykonywany w ten sposób, że ślad miejsca aktualnie wykonywanego programu jest odkładany na stosie po to, aby wrócić w to samo miejsce. Jest to alternatywny sposób rozwiązania długiego skoku. Na rysunku obok mamy ustawienie warunku i BRANCH (BR). Jeżeli zamiast brancha użyjemy JSR (jump to subroutine). Jeżeli warunek jest spełniony to program przechodzi do kolejnego JMP, jeśli zaś nie jest spełniony to wykonuje się jakaś tam procedura i wracamy do tzw. „punktu ścieku”. Jest to miejsce, gdzie spotykają się dwie „nitki” - gdy warunek jest spełniony i gdy warunek nie jest spełniony. W przypadku, gdy warunek jest spełniony to wykona się pewna dodatkowa procedura. Powrót z podprogramu musi odtworzyć ślad (czyli jest to licznik rozkazów). Aby wykonać rozkaz JSR potrzeba 5 dostępów do pamięci: aby pobrać kod rozkazu; aby pobrać dwa bajty adresu podprogramu, do którego mamy przejść; dwa dostępy aby zapamiętać na stosie ślad programu czyli aktualną zawartość licznika rozkazów - będzie to pierwsze wolne miejsce za drugim bajtem adresu programu. Gdy będziemy wracać z tej procedury i wykonamy instrukcję RTS (returm from subroutine) to zostanie odtworzony licznik rozkazów, który był przechowywany na stosie.
Wyżej wymienione instrukcje wykorzystuje się do budowania systemów czasu rzeczywistego, w których pracuje kilka procesów (niezależnych programów) i w trakcie ich działania jest przełączany kontekst, tzn. że wszelkie zdarzenia zewnętrzne mogą spowodować to, że zostanie „zabrany” procesor (możliwość wykonywania kodu programu) jednemu procesowi, jego ślad zostanie zapamiętany i inny proces ze swoim działaniem wskoczy na jego miejsce.
Rozkazy ustawiające warunki (conditional branch instructions) wykonują operacje logiczne, dokonują testowania, badania określonych bitów albo dokonują porównań. Porównanie nie zmienia niczego w komputerze - ani zawartości akumulatora, ani tego z czym tą zawartość porównujemy. Bowiem wszystkie operacje typu compare dotyczą porównania akumulatora z innym rejestrem albo z jakąś lokalizacją pamięci, którą możemy wybrać na kilka sposobów w zależności od trybu adresowania użytego w rozkazie. Testowanie zaś oznacza wykonanie iloczynu logicznego zawartości akumulatora wskazanego w kodzie rozkazu z maską. Maska jest argumentem takiego rozkazu.
ANDA, ANDB - jest to iloczyn logiczny z maską. Tam gdzie maska jest równa 1 to zostanie przepisany bit w akumulatorze, zaś tam gdzie maska jest równa 0 to bit zostanie ustawiony „twardo” na 0.
ORAA, ORAB - jest to suma logiczna i oznacza to, że wszędzie tam gdzie w masce występuje 1 będzie 1, a wszędzie tam gdzie jest 0 zostanie przepisana wartość bitu.
EORA, EORB - suma wyłączająca: 1 ⊕ 1 ⇒ 0; 1 ⊕ 0 ⇒ 1; 0 ⊕ 1 ⇒ 1; 0 ⊕ 0 ⇒ 0;
Mamy możliwość wykonania operacji mnożenia i dzielenia arytmetycznego. Dzielenie oznacza to, że dzielimy podwójny akumulator przez rejestr X. Wynik pojawia się z powrotem w X, a reszta będzie w podwójnym akumulatorze. Mamy również częściowe dzielenie, które ma znaczenie wtedy, kiedy dokonujemy konwersji np. liczby binarnej na dziesiętną.
Dodawanie z przeniesieniem - operacja ta pozwala budować podprogramy, które operują na długich słowach. Jeżeli chcemy dodać do siebie dwie liczby stałoprzecinkowe (integer) to wynik będzie składał się z 4 bajtów. Aby wykonać to dodawanie z użyciem akumulatorów A i B musimy wpisać dane do A i do B, wykonać dodawanie, wynik wpisać do miejsca w pamięci, w którym ma być wykonany wynik. Następnie ponownie do akumulatora należy wpisać dwa bajty i wykonać dodawanie A + B + C (carry) po to, aby przeniesienie z poprzedniej operacji zostało dodane do kolejnego częściowego wyniku, który również zostanie wpisany do następnego miejsca w pamięci, dając w rezultacie z poprzednim wynikiem końcowy wynik dodawania liczb typu integer.
Przesunięcie arytmetyczne w lewo jest to mnożenie przez 2, zaś przesunięcie arytmetyczne w prawo jest dzieleniem przez 2. Jeżeli przesuwamy akumulator w lewo arytmetycznie to na mniej znaczące pozycje z prawej strony wchodzi 0. Jeżeli zaś przesuwamy w prawo arytmetycznie to na najbardziej znaczący bit wchodzi bit znaku.
Przesunięcia cykliczne odbywają się z użyciem rejestru carry. Bit najbardziej znaczący wędruje do tego rejestru, zaś poprzednia jego zawartość przesuwa się na pozycję najmniej znaczącą.
Obsługa przerwań w mikrokontrolerze
Przerwanie jest to sygnał, który zdarza się w dowolnym momencie czasu. Obsługa przerwania jest to procedura, która odbywa się w dwóch etapach. Pierwsza część wykonywana jest automatycznie przez procesor, druga zaś to już działanie zaprogramowane przez użytkownika (programistę) i jest to tzw. funkcja obsługi przerwania. Część automatyczna to zapisanie na stosie 9 bajtów. Zapis odbywa się od góry do dołu od adresów wyższych do adresów niższych. Stos jest strukturą z autodekrementacją przy zapisie i z autoinkrementacją przy odczycie. Najpierw na stos wędruje licznik rozkazów potem rejestr indeksowy Y, następnie X, podwójny akumulator i rejestr flag. Rejestr warunków zawiera 5 bitów niosących informację o ostatnio wykonanej operacji arytmetycznej oraz 3 bity mające możliwość zablokowania operacji STOP oraz zamaskowania przerwań maskowalnych i niemaskowalnych. O ile programista (użytkownik) nie może zablokować możliwości przyjmowania przerwań niemaskowalnych, to można za to ręcznie lub w programie zablokować możliwość przyjmowania przerwań maskowalnych. Wśród przerwań maskowalnych jest przerwanie czasu rzeczywistego zapewniające możliwość dołączenia z zewnątrz dowolnej liczby przerwań dowolnego rodzaju. Przerwania możemy wyzwalać zboczem lub poziomem (najczęściej zerem). Po dokonaniu wepchnięcia na stos poprzednio wymienionych 9 bajtów sterowanie automatycznie przechodzi do wektora przerwań. Wektory przerwań są pobierane z określonego miejsca w pamięci - z samej góry pamięci operacyjnej. W przypadku resetu pobierany jest wektor z adresu $FFFF i $FFFE. Liczba wektorów przerwań jest równa liczbie rozróżnialnych priorytetów przerwań. Najwyższy priorytet mają grupy sygnałów zaliczających się do przerwań niemaskowalnych. Kolejność jest następująca:
`RESET;
clock monitor;
cop watchdog;
illegal opcode - nielegalny kod rozkazu;
`XRQ - sprzętowe przerwanie niemaskowalne. Gdy odblokujemy przerwanie sprzętowe `XRQ to nie można ich później zamaskować w programie;
SWI (software interrupt) - przerwanie programowe, czyli po prostu określony rozkaz z listy rozkazów. Wybranie tego rozkazu powoduje takie same skutki jak sygnał przerwania. Zaletą jest możliwość budowania funkcji służących do przechowywania na stosie wszystkich rejestrów;
przerwania maskowalne zewnętrzne - IRQ. Do tej linii możemy doczepić sygnał z urządzenia zewnętrznego, które będzie informowało o zajściu jakiegoś zdarzenia, które warto by było obsłużyć z punktu widzenia procesora.
W momencie, kiedy zakończy się obsługa przerwania - to wykonanie instrukcji RTI (return from interrupt) powoduje odtworzenie śladu i powrót do tego miejsca, w którym przerwaliśmy działanie programu.
Jeśli nadejdzie przerwanie maskowalne to wpisywana jest jedynka do rejestru CCR na miejscu bitu I, czyli zablokowana zostaje możliwość przyjęcia przerwań na tym poziomie. Mogą zostać przyjęte jedynie przerwania z grupy niemaskowalnych. Jeśli zaś nadejdzie przerwanie niemaskowalne to zapisze ono bity I oraz X, co spowoduje zablokowanie przyjmowania obu typów przerwań. Tak długo dopóki nie odblokujemy wewnątrz procedury obsługi przerwań, tak długo żadne przerwanie nie zostanie obsłużone. Istnieje możliwość zbudowania wielopiętrowej obsługi przerwań, czyli w trakcie obsługi jakiegoś przerwania można przyjąć inne przerwanie, ale prowadzi to do „zamieszania” dwojakiego rodzaju. Jednym z nich jest to, że mamy do dyspozycji tylko 256 bajtów RAM'u i jakakolwiek realizacja obsługująca przerwania musi przewidzieć, że stos powinien być odpowiednio dużym obszarem, w którym będą mogły zostać przechowane odpowiednie dane potrzebne do realizacji problemu wielopiętrowej obsługi przerwań.
Przerwanie SWI jest to przerwanie niemaskowalne programowe. Służy ono do realizacji instrukcji przerwań programowych poprzez instrukcję SWI. Po zinterpretowaniu przez mikrokontroler tego rozkazu zostanie wykonane to wszystko co jest związane z obsługą przerwania czyli zostanie wypchnięty na stos ślad programu - licznik rozkazu wskazujący pierwsze wolne miejsce po rozkazie SWI. Za tym rozkazem możemy umieścić parametry. Najczęściej pierwszy parametr jest identyfikatorem procedury, pozostałe parametry są zaś zazwyczaj danymi dla tej procedury. Taka konstrukcja pozwala na zbudowanie funkcji z przekazywanymi parametrami w obrębie asemblera. Należy zauważyć, że pobierając parametry tej funkcji należy odpowiednio zmodyfikować wypchniętą już na stos zawartość licznika rozkazów, tak aby wskazywał on na miejsce tuż za tymi parametrami. Gwarantuje nam to, że funkcja ta zawsze się wykona nawet jeśli nadejdzie inne przerwanie.
Transmisja synchroniczna
Transmisja synchroniczna używa łącza synchronicznego (SPI - Serial Port Interface). Polega ona na tym, że przesyłamy bloki informacji składających się z wielu słów, które mogą być bajtami. Słów może być dowolna liczba. Na początku musi wystąpić tzw. ciąg synchronizujący. Przed i po „ramce” są poziomy zerowe. Wewnątrz transmisji bit przylega do bitu bez żadnych przerw - dlatego jest to transmisja synchroniczna, bowiem w obrębie całego bloku mamy stałą prędkość bitową (bodową).
Body jest to liczba zmian sygnału na sekundę.
Aby taka transmisja mogła być realizowana to musi wystąpić sekwencja synchronizująca, której zadaniem jest przeprowadzenie synchronizacji bitowej i bajtowej. Synchronizacja bitowa jest to procedura, którą wykonuje odbiornik - jego zadaniem jest znalezienie środka każdej pozycji w słowie - każdego bitu w przypadku transmisji binarnej. Synchronizacja bajtowa jest to znalezienie w sekwencji bitów miejsca, w którym zaczyna się słowo. Razem z ciągiem transmisji jest nadawany przez nadajnik zegar wyznaczający swoimi narastającymi zboczami położenie środka każdego bitu - każdy bit jest taktowany przez nadajnik. Następuje wymuszona synchronizacja ze strony nadajnika i odbiornik automatycznie się synchronizuje. Sygnału zegarowego nie przesyłamy jednak oddzielną linią, tylko poprzedzając właściwy bajt informacji pewną sekwencją synchronizującą. Jej zadaniem jest umożliwienie odbiornikowi wykrycie rytmu, w którym będą pojawiać się środki poszczególnych bitów.
Czasami umieszcza się dodatkowe informacje po ciągu synchronizującym: header może mówić np. ile znaków jest w bloku. W nagłówku dalej jest podawany adresat przesyłki. Na zakończenie bloku niektóre transmisje używają znaku końca (znacznika końca).
Na końcu może wystąpić suma kontrolna. Jej zadaniem jest stwierdzenie poprawności transmisji lub wykrycie ewentualnych błędów podczas transmisji. Mamy dwie możliwości wykrywania błędów.
Wykrywanie błędów w przesyłce i wtedy protokół może zażądać aby odbiornik wysłał do nadajnika żądanie powtórzenia transmisji - jest to wówczas przykład systemu ze sprzężeniem zwrotnym. Jednak nie wszystkie błędy zostaną wykryte przez sumę kontrolną. Jeżeli ciąg błędów ma postać akceptowalnego ciągu kodowego i jest on zsumowany z ciągiem wiadomości to powstanie nowa wiadomość, która nie będzie w niczym odróżnialna od poprawnej wiadomości. W kodach liniowych suma dwóch ciągów kodowych daje w wyniku trzeci ciąg kodowy (poprawny). Jeżeli ciąg główny będzie miał postać ciągu kodowego to nie zostanie on wykryty. Jednak na pocieszenie należy zauważyć, że prawdopodobieństwo wystąpienia takiego ciągu jest stosunkowo niskie. Jeżeli ciąg kodowy będzie krótszy niż suma kontrolna to zawsze zostanie on wykryty, ponieważ sumy kontrolne mają zdolność wykrywania dowolnych serii błędów krótszych niż ciąg sumy kontrolnej.
Kolejny sposób - to każdy bajt danej opatrujemy pewnym nadmiarem kodowym i w wyniku tego mamy część informacyjną i część kontrolną. Część kontrolna służy do wykrywania i ewentualnej korekcji błędów w ciągu kodowym. Im więcej błędów chcemy korygować tym musi być większy nadmiar kodowy.
Przeznaczeniem transmisji synchronicznej jest komunikacja na poziomie sygnałów cyfrowych z pewnymi podzespołami mikrokontrolera takimi jak np. wyświetlacze ciekłokrystaliczne. Nie są to transmisje dalekie i nie korzysta się w nich z modemu.
Transmisja asynchroniczna
Transmisji tej dokonujemy wykorzystując łącze szeregowe asynchroniczne (SCI - Serial Communications Interface). Każde słowo, bajt informacji przesyłamy oddzielnie. Każde pojedyncze słowo przesyłamy w ten sposób, że na poziomie jednego słowa czy bajta mamy pewien bit startu i bit stopu. Musi być sygnalizacja początku informacji i końca - gdzie pojedyncza informacją jest bajt lub słowo. Mamy tu 8-9 bitów. Cała przesyłka jednego słowa w transmisji asynchronicznej jest to 10 lub 11 bajtów w przypadku Motoroli. Transmisja asynchroniczna jest powszechnie stosowana. Między znakami może występować sygnał bezczynności. Sygnał ten może być brakiem sygnału lub może być też jakimś logicznym sygnałem. Częściej zachodzi jednak sytuacja pierwsza, ponieważ wysłanie jakiegokolwiek sygnału, który nie niesie żadnej informacji kosztuje energię.
Różnica między transmisją synchroniczną a asynchroniczną. W transmisji synchronicznej przesyłamy cały blok słów, bajtów danych bez żadnych odstępów między nimi. W transmisji asynchronicznej taktowane w myśl prędkości bodowej są tylko poszczególne bity pojedynczych znaków. Kolejne znaki całych wiadomości mogą być wysyłane w dowolnych odstępach. Każdy znak w transmisji asynchronicznej jest opatrzony bitem startu oraz co najmniej jednym bitem stopu (np. 2).
Format danych w transmisji asynchronicznej jest następujący. Bitem startu jest „0” i trwa on 1 bit. Bitem stopu jest „1”. Odstępy pomiędzy kolejnymi słowami mogą być dowolne. Po każdym bicie stopu może zaraz wystąpić bit startu następnego słowa. Jeżeli zdążymy „wpychać” do bufora nadajnika kolejne znaki wiadomości w tempie wystarczającym aby je wysyłać, to ta transmisja może wyglądać prawie tak jak synchroniczna. Synchronizacja na poziomie bitu odbywa się niezależnie dla każdego przesyłanego słowa. Bit startu służy do „złapania” synchronizacji na poziomie bitu. Stan nieaktywny jest to stan wysoki i musi on spaść na „0” aby wykryć początek transmitowanego bajta. W przypadku 9-bitowej długości słowa bit dziewiąty może zostać wykorzystany do sygnalizacji początku bloku lub jako bit parzystości. Razem z sygnałem niosącym informację nie jest przesyłany żaden sygnał taktujący. Odbiornik musi badając stan linii wykryć początek słowa, prawidłowo się zsynchronizować ustawiając własną częstotliwość taktowania ciągu oraz ustalić środkowe położenie każdego bitu w słowie.
Budowa i sposób działania nadajnika i odbiornika
Odbiornik i nadajnik korzystają z buforów dwupoziomowych albo z dwóch buforów umieszczonych na różnych poziomach. W przypadku nadajnika wpisujemy dane do nadajnika równolegle od strony komputera poprzez szynę danych. Zawartość bufora nadajnika jest przepisywana do drugiego bufora będącego rejestrem przesuwnym taktowanym w tempie prędkości bodowej albo prędkości bitowej. Wysuwane są bity w prawo do linii komunikacyjnej począwszy od najmniej znaczącego bitu. Przy przepisywaniu, jeżeli bufor właściwy nadajnika jest pusty to następuje automatyczne przepisanie tego, co jest w buforze nadajnika piętro wyżej. Jeżeli i tam nie jest nic umieszczone to następuje odpowiednia sygnalizacja o tym, że bufory są puste. Program użytkownika jest w stanie zorientować się na jakim etapie nadawania znajduje się nadajnik. Przy przepisywaniu danej (8-9 bitów) automatycznie jest uzupełniany bit startu i bit stopu. Aby te bity uwzględnić to rejestr przesuwny jest 11-bitowy.
W przypadku odbiornika wchodzą bity z linii tylko jeśli istnieje logiczny sygnał, jeżeli jest zero logiczne, to nie wchodzi nic. Zero nie może być, ponieważ jest bitem startu - musi zaistnieć logiczna jedynka. Linia pracuje na poziomie zanegowania. Pojawienie się bitu stopu (zero) - jeżeli bufor odbiornika jest pusty to układy odbiornika czekają na opadające zbocze sygnału. Jest ono początkiem uruchomienia procedury synchronizacji bitowej.
Synchronizacja bitowa. Częstotliwość próbkowania bitów jest krotnie większa niż częstotliwość bitowa transmisji. W związku z tym, że układ pracuje np. z szybkością 300 bodów (jest to najniższa znormalizowana prędkość bitowa dla łącza szeregowego) to częstotliwość próbkowania każdego bitu będzie 16 razy większa (300 * 16 = 4.8 kHz). Są pobierane 3 próbki i jeśli są one zerami to oznacza to, że pojawiło się zbocze opadające. Wybiera się 3 próbki z oczekiwanego miejsca środka bitu i podejmowana jest większościowa decyzja co do wartości bitu. Jeżeli są trzy zera lub trzy jedynki to wartość jest jednoznacznie określona. Jeżeli zaś mamy inną sytuację to wybierana jest przeważająca wartość i sygnalizowany jest błąd. Program obsługujący odbiornik może stwierdzić, że w którymkolwiek z bitów wystąpiła taka sytuacja.
W odbiorniku i nadajniku dla transmisji asynchronicznej mamy podwójne buforowanie zarówno po stronie nadajnika jak i odbiornika. Oznacza to, że w przypadku nadajnika wkładamy znak do wysłania do wewnętrznego bufora procesora, który następnie jest przepisywany przez układ sterowania nadawaniem asynchronicznym do tzw. rejestru przesuwającego będącego drugą warstwą buforu. W momencie gdy górny bufor opróżni, czyli znak zostanie wysłany, to możemy wpisać następny znak do nadania i czekać aż zostanie znowu przepisany. W przypadku transmisji synchronicznej jesteśmy w stanie nadążyć z tempem nadawania znaków do nadajnika. W odbiorniku jest sytuacja odwrotna. W przypadku transmisji asynchronicznej bity wchodzące z linii do rejestru przesuwającego są grupowane w paczki i po prawidłowym wykryciu bitu stopu są przenoszone do bufora wewnętrznego skąd mogą być pobrane przez procesor. W układzie transmisji synchronicznej (SPI) występuje pojedynczy bufor dla nadajnika i podwójny dla odbiornika. Nie ma górnego bufora dla nadajnika. Znak do nadania jest ładowany do bufora i jak tylko jest on włożony to zaczyna się transmisja. W rytm trwania zegara kolejne bity są wysuwane na linię. Fakt wysuwania na linię ostatniego bitu jest sygnalizowany w słowie stanu układu synchronizującego transmisję.
Mamy 5 rejestrów 8-bitowych sterujących działaniem układów transmisji asynchronicznej. Jednym z nich jest rejestr BAUD służący do ustawienia prędkości transmisji czyli ustawienia podzielnika częstotliwości zegarowej w taki sposób aby uzyskać odpowiednią prędkość bodową. Występują w nim dwa dzielniki. Bity oznaczone SCP1, SCP0 ustalają podzielnik o wartościach 2, 3, 4, 12. Pozostałe bity (najmniej znaczące) tworzą tzw. podzielnik wstępny. Podzielnik częstotliwości zegarowej ma skalę wykładniczą. Łącząc podzielniki ze sobą możemy wybrać taki sposób podzielenia częstotliwości zegarowej, aby uzyskać częstotliwość zbliżoną do 300, 600, 1200, 2400, 4800, 9600, 19200, ... , 131k. Są to standardowe prędkości bodowe i nie ma możliwości zastosowania innych.
Rejestr danych SCDR składa się on rzeczywiście z dwóch 8-bitowych rejestrów. Jeden z nich jest tylko do odczytu, drugi tylko do zapisu. Operacja zapisu do rejestru danych oznacza wpisanie znaku do bufora nadajnika. Operacja odczytu oznacza zaś odczytanie znaku z bufora odbiornika. Nie ma możliwości odczytania znaku z bufora nadajnika i nie ma możliwości wpisania znaku do bufora odbiornika.
Rejestr SCSR obrazuje swoją zawartością to, co się dzieje w układzie. W rejestrze tym mamy następujące flagi:
TDRE - informuje o tym, że górna warstwa bufora jest pusta;
TC - informuje o opróżnieniu bufora nadajnika. Oznacza to wysunięcie na linię transmisyjną ostatniego bitu słowa przeznaczonego do nadania, jest to 8 lub 9 bit. W obu sytuacjach a) i b) program użytkownika powinien zareagować na sygnalizację, że bufor jest pusty. Oznacza to, że możemy podać kolejny bajt do nadania oraz że aktualnie trwa nadawanie tego co uprzednio włożyliśmy. Ustawienie flagi TC oznacza, że wysunął się z nadajnika ostatni bit nadawanej wiadomości ostatniego słowa. W związku z tym oba rejestry: przesuwny i rejestr danych są puste. Nie ma sytuacji takiej, aby była sygnalizacja TC bez wcześniejszego sygnalizowania, że bufor nadajnika jest pusty. Druga sytuacja oznacza, że możemy fizycznie zamknąć nadajnik, mamy wtedy 100% pewność, że wszystkie bity ostatniego słowa podanego do nadania opuściły nadajnik.
RDRF - zapełnił się bufor odbiornika, tzn. znak który odbierano został przepisany z rejestru przesuwającego (z dołu) do góry i jest gotowy do odebrania przez program. Natomiast układ odbiorczy nasłuchuje linię i gdy pojawi się kolejne zero danej to będzie ona bit po bicie pobierana do wnętrza. Pozostałe bity w rejestrze służą do sygnalizacji błędów.
IDLE - jest to sygnał samych jedynek, linia jest ustawiona w wysoki stan. Po stronie odbiorczej ciąg samych jedynek oznacza, że linia jest bezczynna czyli, że wystąpiła przerwa w nadawaniu i nic nie jest wówczas odbierane.
OR (overrun) - sytuacja najmniej korzystna z punktu widzenia odbiornika. Jeżeli oprogramowanie użytkownika, które steruje pobieraniem informacji z bufora odbiornika nie odbiera znaku, który pojawił się w rejestrze, a w międzyczasie kolejny znak zostanie wczytany przez dolny rejestr odbiornika to wystąpi próba nadpisania znaku z dołu do góry. Jest to sytuacja przepełnienia. Sytuacja ta oznacza zgubienie znaku przez odbiornik.
NF (no flow) - oznacza pojawienie się sytuacji takiej, że była podejmowana decyzja większościowa w odbiorniku. Oznacza to, że w rozpoznawanym bicie wystąpiły dwa zera i jedynka albo jedno zero i dwie jedynki. Jest to oznaką wystąpienia zakłóceń lub zaszumień. Bit NF pozwala zwrócić użytkownikowi uwagę na pewną podejrzliwość w stosunku do odebranej informacji.
FE - bit stopu nie pojawił się tam, gdzie pojawić się powinien. Po 8 lub 9 bicie danych słowa oczekujemy skoku na „1”. Jeżeli tej jedynki tam nie ma albo nastąpił wcześniejszy skok na „0” albo nie nastąpi powrót na „1” po zerze to zostanie ustawiona ta flaga. Oznacza to, że nastąpiło przesunięcie ramki poza spodziewaną długość słowa. Zgubiliśmy synchronizację na poziomie bitu.
Rejestr SCCR1. Bit R8 pełni rolę dziewiątego bitu danych odbiornika, zaś T8 nadajnika. Rejestry są organizacji 8-bitowej i jeśli przyjmiemy, że będziemy transmitować słowa asynchronicznie o długości 9 bitów to ostatni bit musi być umieszczony gdzieś w innym miejscu. Bit M wiąże się z wyborem długości słowa: „0” - 8 bitów, „1” - 9 bitów. Bit WAKE służy do wyboru sposobu budzenia odbiornika z trybu idle. Określa on czy odbiornik ma reagować na zero czy na jedynkę na najbardziej znaczącej pozycji w słowie wiadomości. Możemy bowiem całą wiadomość podzielić na kawałki 8-bitowe i do każdego z tych kawałków dołożyć dziewiąty bit informujący o tym, który kontroler ma to słowo odebrać. Oznacza to możliwość generacji transmisji kierowanych do wielu użytkowników, gdzie identyfikacja pozwala interesować się wiadomością wtedy, gdy pojawi się jej początek (0 albo 1). Oznacza to także istnienie w sieci wielu mikrokontrolerów nasłuchujących linię i budzących się w momencie gdy nastąpi fakt odebrania pierwszego słowa (wiadomości) 9-bitowego, w którym najbardziej znaczącym bitem jest „1” albo „0”.
Rejestr SCCR2 ma kluczowe zadanie sterowania działaniem układu transmisji asynchronicznej. Bity TE i RE odpowiadają one za wystartowanie działania odpowiednio nadajnika i odbiornika. Układy odbiornika i nadajnika mogą pracować oddzielnie. Bit TCIE jest odpowiedzialny za odblokowanie przerwań nadajnika. Wystąpią one w momencie gdy bufor nadajnika jest pusty lub gdy bufor nadajnika zostanie opróżniony. Bity TIE i RIE rozpoczynają nadawanie i odbieranie.
W transmisji synchronicznej mamy następujące rejestry: rejestr statusowy, rejestr sterujący i rejestr danych. Pojawia się inny format transmisji co wiąże się z dodatkowymi parametrami. Oprócz dzielnika zegara są to: polaryzacja i faza - odpowiedzialne za nie są dwa bity. Dla polaryzacji „0” sygnałem nieaktywnym jest „0”, zaś dla polaryzacji „1” analogicznie „1”. Konsekwencją tego jest to, że albo zbocze narastające albo opadające taktu zegarowego będzie wskazywało na środek bitu. Dwa różne formaty transmisji związane są w sposób kluczowy ze znakiem fazy, bowiem ona to wyznacza sposób transmisji całego słowa. W przypadku, gdy faza jest równa „0”, to początek transmisji oznacza opadnięcie w dół sygnału SS (slave select). W transmisji synchronicznej biorą udział 4 nóżki mikrokontrolera. Są to: linia nadawcza, linia odbiorcza, zegar i nóżka SS na której opadnięcie sygnału oznacza moment rozpoczęcia transmisji. W przypadku, gdy faza jest równa 1, to faza zegara dla polaryzacji 1 i 0 są przesunięte o 180°. Początek transmisji wyznacza tu sygnał zegarowy. Sygnał SS służy tu tylko do uaktywnienia odbiornika. Dopiero pierwsze narastające albo opadające zbocze wyznacza rozpoczęcie transmisji natomiast drugie z kolei zbocze wyznacza środek bitu. Konsekwencją tego mogą być dwa rodzaje błędów mogących wystąpić w układzie.
Pierwszy rodzaj błędu pojawia się, gdy mamy do czynienia z siecią mikrokontrolerów wśród których są co najmniej dwa układy master. Błędy związane z tzw. Mode Fault (błąd trybu) pojawia się wtedy, gdy jednocześnie dwa układy master próbują rozpocząć nadawanie. Wtedy dochodzi do rekonfiguracji układu, a konkretnie części odpowiedzialnej za łącze szeregowe. W takiej sytuacji układ, który jako drugi włączał się do transmisji usiłując być zarządcą linii transmisyjnej staje się w sposób wymuszony układem slave. Następuje wyresetowanie części odpowiedzialnej za transmisję synchroniczną, zostają skasowane wszystkie nastawy i układ staje się układem slave. W takiej sytuacji zostaje wygenerowane przerwanie i program sterujący układem transmisji synchronicznej musi podjąć decyzję co dalej należy zrobić - najczęściej jest to ponowna inicjalizacja układu.
Drugi rodzaj błędów bezpośrednio wynika z budowy nadajnika, a jest nim nadpisanie bufora danych. Błąd ten pojawia się dla mastera i dla slave'a. Master niby wie kiedy nadaje, ale jednak może nastąpić sytuacja kiedy wystąpi nadpisanie bufora nadajnika.
W przypadku resetu ani transmisja synchroniczna ani asynchroniczna nie są zainicjowane i wówczas port D pracuje jako zwykły port wejścia/wyjścia. Zanim rozpoczniemy transmisję należy ustawić jej pewne parametry. W rejestrze SPCR (Signalization Port Control Register) ustawiamy dwa bity będące wartością dzielnika częstotliwości zegara, wyznaczają one jednocześnie szybkość taktowania poszczególnych bitów. Musimy ustawić rodzaj polaryzacji i fazy. Ustawienie fazy jest związane z wyborem formatu transmisji (master ⇒ slave), zaś polaryzacja określa, które zbocze zegara wyznacza środek bitu. Następnie należy ustalić czy układ jest master czy slave. Trzeba uaktywnić możliwość generowania przerwań z tytułu możliwości zasygnalizowania zakończenia transmisji lub wystąpienia błędu. Na końcu należy też ustawić stan na nóżce SS.
Przetwornik A/C
Mamy możliwość próbkowania 16 kanałów. Mamy 8 nóżek w mikrokontrolerze, 8 kanałów zewnętrznych i 8 kanałów wewnętrznych. Można wybrać 1 z 16 lub jedną z grup czterech kanałów po 4. Pozostałe 4 służą do realizacji testów fabrycznych - do pomiarów napięcia zasilania i poziomu masy wewnątrz mikrokontrolera.
Mamy możliwość realizacji wyboru w jednym kanale 4 kolejnych aproksymacji (próbkowań A/C) dla jednego kanału albo dla wybranej grupy 4 kanałów w jednym cyklu dokonujemy 4 próbkowań. Konsekwencją tego podejścia jest to, że muszą istnieć w układzie mikrokontrolera 4 rejestry danych do przechowywania 4 wyników konwersji. W tych rejestrach będą przechowywane albo 4 kolejne pobrane próbki jednej linii, albo 4 różne próbki z 4 linii wybranych jako jedna grupa. Mamy następujące rejestry związane z przetwornikiem A/C:
Rejestr ADCTL. Bity CD, CC, CB, CA służą do wyboru albo jednego z 16 kanałów wejściowych albo pomijając dwa najbardziej znaczące bity CD i CC do wyboru grupy 4 wejść. Bit SCAN służy do wyboru między próbkowaniem jednokrotnym a ciągłym. Próbkowanie odbywa się cyklicznie, bez przerwy. Po każdym próbkowaniu zapalany jest najbardziej znaczący bit CCF informujący o zakończeniu konwersji. Poprzez bit MULT mamy możliwość wyboru jedno lub wielokanałowej konwersji. Z rejestrem sterowania konwersją współdziałają dwa najstarsze bity umieszczone w rejestrze OPTION dające nam możliwość wyboru zegara wewnętrznego lub zewnętrznego wyznaczającego rytm próbkowania. Jeżeli częstotliwość zegara zewnętrznego będzie na poziome 2 MHz to nie używamy wewnętrznego zegara. W przeciwnym wypadku należy użyć wbudowanego generatora RC działającego samodzielnie, wystarczy podać tylko stałe napięcie. Wyboru zegara dokonujemy przez odpowiednie ustawienie bitu CSEL (clock selection). Bit ADPU oznacza sposób ustawienia konwertera w przypadku włączenia zasilania. Po resecie bowiem kontroler jest zablokowany i pracuje jako zwykły port wejścia/wyjścia.
Sposób dokonania konwersji sygnału analogowego na cyfrowy. Używane są kondensatory wbudowane wewnątrz mikrokontrolera. Są one wielowarstwowe i identyczne pod względem pojemności. Ich zasada działania jest związana z redystrybucją ładunku przechowywanego w kondensatorze - jest to aproksymacja schodkowa. Najpierw przyłączamy górny klucz - sprowadzamy kondensator do masy VL („0”). W stanie początkowym wszystkie kondensatory są nienaładowane. Nie ma znaczenia jakie pojemności mają kondensatory, byle ich stosunki pojemności były w takiej proporcji w jakiej są wagi liczb binarnych (potęg). Przyłączamy napięcie mierzone VX i następuje ładowanie kondensatora. Ładunek odłożony na każdym kondensatorze jest równy Q = UC. Chcemy doprowadzić do takiego stanu aby podać kolejne napięcia z każdego z kondensatorów na komparator i dokonać porównania na nim przełączając między napięciami i porównując napięcie kondensatora z napięciem maksymalnym i minimalnym. W drugiej fazie następuje zatrzymanie ładunku. Jest to faza dokonywania porównań. Zaciski kondensatora są dołączane między napięciem niskim i wysokim. Napięcie to doprowadzane jest to komparatora i porównywane z napięciem odniesienia zerowym. Na wyjściu komparatora uzyskujemy wyniki, że raz jest większe, a raz mniejsze napięcie. Otrzymujemy pewne wartości binarne 0 i 1. Mają one wpływ na to w jaki stan inicjalny ustawić komparator i jaką decyzję co do porównania podjąć w stosunku do następnego kondensatora. Wyniki porównań są wpisywane do rejestru. Porównania zaczynamy od najbardziej znaczącej wartości.
Komparator ten ma zastosowanie jako układ automatyki do pomiaru poziomu napięcia zewnętrznego analogowego i na tej podstawie podejmowania różnych decyzji. Konwerter ten nie generuje żadnych przerwań.
Technika mikroprocesorowa Opracowanie na podstawie wykładu: Bartłomiej Szymański
- 19 -
Kod
ModA
RA
ModB
RB
adres A
adres B
rejestr A
rejestr B
SP
SP - 1 ⇒ SP
kod
rejestr
znacznik lub flaga
kod
Ustawienie jakiegoś znacznika
1 część adresu
kod
2 część adresu
Cały adres:
2 część adresu
1 część adresu
rozkaz skoku
kod
rejestr
adres 1
kod
adres 2
przesunięcie
kod
kod
rejestr
przesunięcie
Procesor
S
O
adres logiczny
O
R
.
.
.
R
Pamięć
opera-
cyjna
.
.
.
CMP
operand
BREQ
parametr
JUMP
JUMP
Poniżej obszaru 127 bajtów
> 127 bajtów
warunek
(BR)
JSR
JMP
punkt ścieku
RBOOT
SMOD
PSEL1
PSEL2
PSEL3
IRVNE
MDA
PSEL0
Bit 0
Bit 7
Bit 7
Bit 0
EEON
NOSEC
NOCOP
ROMON
Bit 7
Bit 0
REG0
RAM1
RAM0
REG3
REG2
REG1
RAM2
RAM3
Bit 7
Bit 0
CR0
IRQE
DLY
CME
CR1
CSEL
ADPU
Bit 7
Bit 0
TDRF
IDLE
OR
NF
FE
TC
TDRE
Bit 7
Bit 0
M
WAKE
T8
R8
Bit 7
Bit 0
SBK
RIE
ILIE
TE
RE
RWU
TCIE
TIE
Bit 7
Bit 0
CA
SCAN
MULT
CD
CC
CB
CCF