MCS-51
Opis rozszerzeń języka C w kompilatorze SDCC

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.