Alokacja zmiennej w określonym typie pamięci
Kompilator SDCC umożliwia alokację zmiennych we wszystkich dostępnych typach pamięci występujących w mikrokontrolerach rodziny MCS-51. Wybór typu pamięci dla zmiennej zależy od wielu czynników. Jak wiadomo dostęp do wewnętrznej pamięci danych jest znacznie szybszy niż do pamięci zewnętrznej, zatem zmienne do których występują częste odwołania należy umieszczać w pamięci wewnętrznej. Z kolei dostęp do zewnętrznej pamięci danych jest znacznie wolniejszy, ale za to jej rozmiar jest znacznie wiekszy, zatem w tej pamięci należałoby umieszczać duże i rzadziej używane zmienne. Dodatkowo alokacja zmiennej w określonym typie pamięci może być zrealizowana jawnie lub niejawnie.
Jawna deklaracja typu pamięci
Dołącznie do deklaracji zmiennej jednego ze słów kluczowych przedstawionych w poniższej tabeli umożliwia jawną deklarację typu pamięci, w której będzie przechowywana deklarowana zmienna.
Tabela 6.2. Specyfikatory typów pamięci
Typ pamięci | Opis |
---|---|
__data |
Wewnętrzna pamięć danych adresowana bezpośrednio. Adresy: 00h..7Fh |
__idata |
Wewnętrzna pamięć danych adresowana pośrednio Adresy: 00h..FFh |
__bit |
Wewnętrzna pamięć danych adresowana bitowo Adresy: 20h..2Fh |
__xdata |
Zewnętrzna pamięć danych Adresy: 0000h..FFFFh |
__pdata |
Strona zewnętrznej pamięci danych Ciągły obszar adresów o rozmiarze 256 bajtów |
__code |
Pamięć programu Adresy: 0000h..FFFFh |
__data
Zmienne deklarowane ze specyfikatorem __data
będą alokowane w wewnętrznej pamięci danych adresowanej bezpośrednio. W tym wypadku dostęp do zmiennych będzie odbywał się z wykorzystaniem instrukcji MOV
, ale tylko w tej wersji, gdzie jako argumenty występują adresy bezpośrenie. Jak wspomniano wcześniej dostęp do wewnętrznej pamięci danych jest szybszy niż do pamięci zewnętrznej, dlatego ten typ pamięci powinien być stosowany dla zmiennych, do których wystepuje częsty dostęp lub sama specyfika program wymaga szybkiego dostępu do nich.
__data unsigned char licznik;
Powyżej przedstawiono przykładową deklarację zmiennej licznik
z wykorzystaniem omawianego słowa kluczowego. Przedstawiona poniżej linia kodu
licznik = 0;
zostanie zamieniona przez kompilator na następującą instrukcję asemblerową
MOV _licznik, #0x00
__idata
Specyfikator __idata
pozwala na alokację zmiennych w wewnętrznej pamięci danych adresowanej pośrednio. W tym wypadku, podobnie jak przy specyfikatorze data
, dostęp do tego typu zmiennych realizowany jest przez instrukcję MOV
, ale w wersji z adresowaniem pośrednim, tj. za pomocą rejestru R0 lub R1. Zatem zapis do zmiennej zadeklarowanej jak poniżej
__idata unsigned char licznik;
i realizowany przez następujący kod
licznik = 0x0F;
będzie zamieniony na następujący ciąg instrukcji asemblerowych
MOV R0,#_licznik MOV @R0,#0x0F
Należy zauważyć, że początkowe 128 bajtów wewnętrznej pamięci danych jest dostępne zarówno przez adresowanie pośrednie jak i bezpośrednie. Zatem zmienne deklarowane ze specyfikatorem __data
i __idata
mogą być fizycznie umieszczone w tym samym typie pamięci.
__bit
W przypadku zmiennych bitowych specyfikator typu jest jednocześnie specyfikatorem klasy pamięci, w jakiej będzie alokowana deklarowana zmienna. Zatem deklaracja zmiennej bitowej wymaga tylko słowa kluczowego __bit
. Poniżej przestawiono przykładową deklarację zmiennej.
__bit znacznik
Zapis wartości 1 do tego typu zmiennej, tj.
znacznik = 1;
spowoduje wygenerowanie następującego kodu asemblerowego
SETB _znacznik
__xdata
Deklaracja zmiennej ze specyfikatorem typu pamięci __xdata
powoduje alokację tej zmiennej w zewnętrznej pamięci danych.
__xdata unsigned char licznik
Dostęp do tego typu zmiennych odbywa się z wykorzystaniem instrukcji MOVX
w wersji z rejestrem DPTR
. Zatem zapis jakiejś wartości do zadeklarowanej powyżej zmiennej
licznik = 0xFF
powoduje jej zamianę na następujący ciąg instrukcji asemblerowych
MOV DPTR,#_licznik MOV A,#0xFF MOVX @DPTR,A
__pdata
Użycie specyfikatora typu pamięci __idata
przy deklaracji zmiennej powoduje, że zmienna ta jest alokowana w zewnętrznej pamięci danych tak, jak w przypadku specyfikatora __xdata
. Różnica polega na tym, iż dostęp do zmiennych deklarowanych z tym specyfikatorem jest ograniczony do obszaru obejmującego 256 bajtów (tzw. jednej strony pamięci), gdyż kompilator realizuje go poprzez instrukcję MOVX
opartą o rejestr R0
lub R1
. Wybór strony pamięci zależy od wartości ustawionej na liniach portu P2
, gdyż to on wyznacza starszy bajt adresu przy dostępie do zewnętrznej pamięci danych.
Dla przykładu deklarując zmienną w poniższy sposób
__pdata unsigned char licznik;
i umieszczając w programie kod, który dokonuje do niej zapisu jakiejś wartości, np.
licznik = 0x20;
spowoduje, że kompilator wygeneruje następujący kod asemblerowy dla powyższej linii kodu
MOV R0,#_licznik MOV A,#0x20 MOVX @R0,A
__code
'Zmienne' deklarowane ze specyfikatorem __code
będą alokowane w pamięci programu. Dostęp do 'zmiennych' będzie odbywał się z wykorzystaniem instrukcji MOVC
. Jak wiadomo, z punktu widzenia programu pamięć kodu może być tylko odczytywana, dlatego 'zmienne' deklarowane z użyciem tego słowa kluczowego są de facto stałymi, gdyż ich wartości nie moga być zmienniane przez instrukcje programu.
__code char napis[] = "Numer kanalu:";
W powyższym przykładzie zadeklarowano ciąg znakowy. Poszczególne znaki tego ciągu mogą być odczytywane w programie np. poprzez instrukcję
znak = napis[1];
która w tym przypadku powoduje przepisanie do zmiennej znak
kodu drugiego znaku z tablicy napis
(zmienna znak
powinna być zadeklarowana jako zmienna typu char
). Kompilator zamieni przedstawioną linię kodu na ciąg następujących instrukcji asemblerowych
MOV A,#0x01 MOV DPTR,#_napis MOVC A,@A+DPTR MOV _znak,A
Nie jest natomiast możliwa zmiana znaków ciągu napis
, tj. niemożliwa jest kompilacja następującej linii kodu
napis[2] = 0x30;
Domyślna deklaracja typu pamięci
W przypadku braku słowa kluczowego specyfikującego typ pamięci podczas deklaracji zmiennej, kompilator SDCC alokuje daną zmienną w domyślnie przyjmowanym typie pamięci, który zależy od wybranego modelu pamięci.