W odróżnieniu od procesora Z80, tu sprawa użycia staje się trochę bardziej złożona. Wynika to z większej różnorodności wariantów rozwiązań sprzętowych (o ile w kwestii peryferali nie ma to istotnego znaczenia, o tyle w kwestii rozwiązań wewnętrznej pamięci RAM ma istotny wpływ na generowany kod). Tu warto pamiętać, że podstawowy, standardowy model mikrokontrolera (o oznaczeniu 8031/8051) ma 128 bajtów wewnętrznej pamięci RAM. Pierwsza wersja rozwojowa tego mikrokontrolera, o oznaczeniu 8052 ma 256 bajtów pamięci wewnętrznej, co stanowi bardzo istotną różnicę. W obrębie samego miktokontrolera 8051 istnieje możliwość dołączenia zewnętrznej pamięci RAM nawet do wielkości 64kB (plus rzecz jasna wewnętrzna pamięć RAM).
Ta różnorodność musi w jakiś sposób mieć swoje odbicie w „zaklęciach” dla kompilatora, by wygenerował kod spełniający „zachcianki” programisty. W tym celu kompilator posługuje się pojęciem modelu pamięci. Dla procków z rodziny C51 oferowane są następujące modele pamięci (w dokumentacji znajduje się informacja, że w przypadku, gdy program jest zawarty w kilku plikach, każdy z nich musi być kompilowany ze wskazaniem na jednakowy model pamięci):
- --model-small – generuje kod programu lokując zmienne w wewnętrznej pamięci RAM, ten model pamięci jest domyślnym,
- --model-medium – generuje kod dla „średnich” modeli pamięci i oznacza użycie zewnętrznej pamięci RAM,
- --model-large – generuje kod dla „dużych” modeli pamięci i oznacza użycie zewnętrznej pamięci RAM,
- --model-huge – generuje kod dla „ogromnych” modeli pamięci (nie będę się tym na razie zajmować).
Ze względu na różne rozmiary pamięci RAM i różne przestrzenie adresowe, by „zmusić” kompilator do zamierzonego potraktowania zmiennych, należy użyć odpowiedniego zaklęcia przy deklaracji zmiennej. Kompilator SDCC oferuje następujące zaklęcia:
- __data – zmienna należy do obszaru wewnętrznej pamięci RAM o wielkości 128 bajtów,
- __idata – zmienna należy do obszaru wewnętrznej pamięci RAM o wielkości 256 bajtów,
- __pdata – zmienna należy do obszaru zewnętrznej pamięci RAM o wielkości 256 bajtów o początkowym adresie 0 (adresy z przedziału 0..255),
- __xdata – zmienna należy do obszaru zewnętrznej pamięci RAM o dowolnej lokacji,
- __code – zmienna położona jest w przestrzeni kodu programu (trudno tu użyć określenia „zmienna”, dotyczy to stałych obszarów zmiennych).
Kod: Zaznacz cały
unsigned char GloblVar ;
main ( )
{
unsigned char j ;
/*---------------------------------------------------*/
while ( 1 )
{
GloblVar = 1 ;
for ( j = 0 ; j < 4 ; j++ )
{
GloblVar = GloblVar << 1 ;
} /* for */ ;
} /* while */ ;
} /* main */e:\sdcc\bin\sdcc -mmcs51 --model-small test1.c
Kompilacja przebiega bezboleśnie.Wygenerowany kod program jest zapisany w pliku o nazwie test1.ihx. By obejrzeć, co nawyczyniał kompilator, zastosowany jest program AVSIM51. Wykonując program krokowo, dochodzimy do pewnej dziwności.Kompilator wygenerował kod do wyzerowania wewnętrznej pamięci RAM o wielkości 256 bajtów, pomimo że miał zadany model small. Sądzę, że dla samego procka nie będzie miało to istotnego znaczenia, gdyż wystąpią operacje zapisu do nieistniejących obszarów pamięci. Jednak symulator AVSIM51 taką sytuację wykrył no i się odpowiednio wyraził. Zanim zacząłem urągać kompilatorowi, to zastanowiłem się nad zjawiskiem. Zamiast szukać wad u innych w pierwszej kolejności warto przyjrzeć się własnemu postępowaniu. Przy lekturze dokumentacji powstała myśl, że może należy podać wielkość obszaru pamięci.
Korekta makropolecenia CC.BAT do następującej postaci:
e:\sdcc\bin\sdcc -mmcs51 --model-small --iram-size 128 test1.c
i ponowna kompilacja daje właściwy wynik:Tym razem zerowany jest obszar pamięci RAM o właściwej wielkości. Dalsza symulacja program doprowadza do realizacji instrukcji zawartych w programie napisanym w języku C (do tej pory to był startup).Realizując program krokowo, nasuwa się wniosek, że kompilator zrobił to właściwie. Nawet można wywnioskować, że zmienna programu GlobalVar ma adres 8 w przestrzeni adresowej (symbol R0' na ekranie symulatora odpowiada adresowi 8). Ma to swoje potwierdzenie w dokumencie test1.map:
Value Global Global Defined In Module
----- -------------------------------- ------------------------
00000008 _GloblVar test1
Na sztuki wszystko się teraz zgadza. Pierwsze starcie zakończyło się powodzeniem, udało się dogadać z kompilatorem i przekazać mu precyzyjne informacje dotyczące generacji kodu programu.
