Wykład z budowy i programowania układów
mikroprocesorowych
Wykład prowadził profesor Jerzy Jakubiec.
Notowali Rafał Kała i Adam Szojda.
Spis rzeczy
1
Programowanie w j ˛ezyku asembler
1
1.1
Podstawowe wła´sciwo´sci asemblera . . . . . . . . . . . . . . . . . . . . . . .
1
1.1.1
Proces powstawania i tłumaczenia programu
. . . . . . . . . . . . . .
1
1.1.2
Składnia instrukcji asemblera
. . . . . . . . . . . . . . . . . . . . . .
2
1.1.3
Komentowanie programu . . . . . . . . . . . . . . . . . . . . . . . . .
3
1.1.4
Elementarne obiekty j˛ezyka . . . . . . . . . . . . . . . . . . . . . . .
3
1.1.5
Tworzenie nazw i operacje na słowniku . . . . . . . . . . . . . . . . .
5
1.1.6
Dyrektywy rezerwacji pami˛eci . . . . . . . . . . . . . . . . . . . . . .
6
1.1.7
Dyrektywa ko ´ncz ˛
aca program . . . . . . . . . . . . . . . . . . . . . .
7
1.2
Makroasembler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
1.2.1
Ogólne wła´sciwo´sci makroasemblera . . . . . . . . . . . . . . . . . .
7
1.2.2
Asemblacja warunkowa
. . . . . . . . . . . . . . . . . . . . . . . . .
7
1.2.3
Makrodefinicje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
1.3
Tworzenie programów w postaci modułowej
. . . . . . . . . . . . . . . . . .
8
1.3.1
Moduły programowe . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
1.3.2
Absolutne i wzgl˛edne tłumaczenie modułów programowych . . . . . .
10
1.3.3
Atrybuty nazw w programach modułowych . . . . . . . . . . . . . . .
11
1.3.4
Relokowalo´s´c modułów . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.3.5
Współu˙zywanie nazw w modułach . . . . . . . . . . . . . . . . . . . .
13
1.3.6
Doł ˛
aczanie modułu zawieraj ˛
acego kod ´zródłowy programu . . . . . . .
14
1.4
Sekcje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
1.4.1
Typy sekcji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
1.4.2
Składnia dyrektywy .SECTION . . . . . . . . . . . . . . . . . . . . .
15
1.4.3
Sekcje rejestrowe i sekcje bitowe
. . . . . . . . . . . . . . . . . . . .
15
1.5
Lokowanie sekcji w pami˛eci . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
1.5.1
Sposoby lokowania sekcji . . . . . . . . . . . . . . . . . . . . . . . .
16
1.5.2
Zwi ˛
azki mi˛edzy sekcjami
. . . . . . . . . . . . . . . . . . . . . . . .
16
1.5.3
Sterowanie lokowaniem sekcji . . . . . . . . . . . . . . . . . . . . . .
17
1.5.4
Konsolidacja programu o strukturze sekcyjnej . . . . . . . . . . . . . .
18
2
Programowanie w C
µ
K rodziny Intel 8051
21
2.1
Proces uzyskiwania programu wynikowego dla programów w C . . . . . . . .
21
2.2
Program rozruchowy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
2.2.1
Rodzaje programu rozruchowego
. . . . . . . . . . . . . . . . . . . .
22
2.2.2
Definiowanie rodzaju mikrokontrolera . . . . . . . . . . . . . . . . . .
23
i
Spis rzeczy
2.2.3
Deklaracja rejestrów roboczych . . . . . . . . . . . . . . . . . . . . .
26
2.2.4
Przesuwanie danych . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
2.2.5
Przygotowanie stosu . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
2.2.6
Wywołanie programu w C . . . . . . . . . . . . . . . . . . . . . . . .
28
2.3
Organizacja danych w C . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
2.3.1
Typy danych i ich modyfikatory . . . . . . . . . . . . . . . . . . . . .
29
2.3.2
Organizacja ramki stosu . . . . . . . . . . . . . . . . . . . . . . . . .
30
2.3.3
Przekazywanie argumentów do funkcji
. . . . . . . . . . . . . . . . .
31
2.3.4
Rozmieszczenie zmiennych lokalnych w ramce stosu . . . . . . . . . .
33
2.3.5
Przechowywanie warto´sci zwracanych przez funkcj˛e . . . . . . . . . .
36
2.4
Przekazywanie danych mi˛edzy funkcjami a instrukcjami asemblera . . . . . . .
37
2.4.1
Wprowadzanie instrukcji asemblera do programu w C . . . . . . . . .
37
2.4.2
Dost˛ep do zmiennych lokalnych . . . . . . . . . . . . . . . . . . . . .
38
2.4.3
Dost˛ep do argumentów funkcji j˛ezyka C . . . . . . . . . . . . . . . . .
38
2.4.4
Adresowanie bezpo´srednie i po´srednie w programach w C . . . . . . .
39
Indeks
43
ii
Spis rysunków
1.1
Proces tworzenia programu . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1.2
Proces tworzenia programów w postaci modułowej . . . . . . . . . . . . . . .
10
1.3
Zwi ˛
azki mi˛edzy sekcjami . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
2.1
Proces uzyskiwania programu wynikowego dla programów w C . . . . . . . .
21
2.2
Struktura wewn˛etrznej pami˛eci RAM po zainicjowaniu stosu . . . . . . . . . .
29
2.3
Ramka stosu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
2.4
Kolejno´s´c argumentów funkcji w ramce stosu . . . . . . . . . . . . . . . . . .
32
2.5
Ramka stosu dla przykładu ze strony 33 . . . . . . . . . . . . . . . . . . . . .
34
2.6
Mapa pami˛eci zmiennych lokalnych . . . . . . . . . . . . . . . . . . . . . . .
34
2.7
Mapa ramki stosu funkcji z przykłady ze strony 33
. . . . . . . . . . . . . . .
36
iii
Spis rysunków
iv
1 Programowanie w j ˛ezyku asembler
1.1
Podstawowe wła ´sciwo ´sci asemblera
1.1.1
Proces powstawania i tłumaczenia programu
Program z´ródłowy
Program wynikowy
Tłumaczenie
Rysunek 1.1: Proces tworzenia programu
Proces tworzenia programu u˙zytkowego, niezale˙znie od zastosowanego j˛ezyka programo-
wania, przebiega w sposób przedstawiony ogólnie na rysunku 1.1. Proces ten mo˙zna okre ´sli´c
jako zespół działa ´n słu˙z ˛
acych przetworzeniu programu, tworzonego w sposób dogodny dla pro-
gramisty i specyficzny dla rodzaju oprogramowywanego zadania, na posta ´c dostosowan ˛
a do
potrzeb procesora realizuj ˛
acego program. Ta pierwotna posta ´c programu, nazywana programem
´zródłowym, ma zawsze posta´c symboliczn ˛
a i powstaje przy u˙zyciu edytora tekstu
1
. Program
wynikowy ma posta´c binarn ˛
a wyra˙zon ˛
a j˛ezykiem wewn˛etrznym (maszynowym) procesora. Pro-
ces tłumaczenia polega na nadawaniu warto´sci liczbowych nazwom symbolicznym. Elementem
składowym tego procesu jest równie˙z organizacja i zapis pami˛eci danych. Program ´zródłowy
stanowi ci ˛
ag instrukcji uszeregowanych w sposób wła´sciwy dla celów realizacji okre´slonego za-
dania. Posta´c instrukcji narzuca sposób tłumaczenia programu, okre´slaj ˛
ac zarazem podstawowy
podział j˛ezyków programowania. Wyró˙znia si˛e dwa podstawowe rodzaje j˛ezyków:
j˛ezyki maszynowo (sprz˛etowo) zorientowane nazywane asemblerami a w rozwini˛etej wer-
sji makroasemblerami,
j˛ezyki proceduralnie zorientowane, czyli tzw. j˛ezyki wy˙zszego rz˛edu.
Budowa asemblera dostosowana jest do wła´sciwo´sci sprz˛etowych procesora i urz ˛
adze ´n z nim
współpracuj ˛
acych. Wyst˛epuje wi˛ec ´scisły zwi ˛
azek mi˛edzy budow ˛
a mikrokomputera a postaci ˛
a
instrukcji j˛ezyka typu asembler. Zewn˛etrznie ten zwi ˛
azek przejawia si˛e w taki sposób, ˙ze jedna
instrukcja w j˛ezyku asemblerowym koduje jeden rozkaz maszynowy (jest to tzw. własno´s´c jeden
na jeden). Symbolika j˛ezyka sprowadza si˛e do u˙zywania:
1
Czyli MS Word odpada, na szcz˛e´scie . . . ;-)
1
1
Programowanie w j˛ezyku asembler
symbolicznych (mnemonicznych) kodów rozkazów,
symbolicznych adresów i danych.
Reasumuj ˛
ac mo˙zna powiedzie´c, ˙ze j˛ezyk typu asembler jest j˛ezykiem symbolicznym sprz˛etowo
zorientowanym.
Podstawow ˛
a cech ˛
a j˛ezyka wy˙zszego poziomu jest orientacja proceduralna, tzn. ˙ze j˛ezyki te
s ˛
a budowane pod k ˛
atem optymalizacji okre´slonego rodzaju zada ´n. Dzieli si˛e je na:
j˛ezyki algorytmiczne,
j˛ezyki symulacyjne,
j˛ezyki do tworzenia baz danych, itp. itd.
Programy pisane w tych j˛ezykach maj ˛
a praktycznie tak ˛
a sam ˛
a posta ´c dla ró˙znych typów kom-
puterów. Ró˙zni ˛
a si˛e natomiast programy tłumacz ˛
ace, które musz ˛
a by ´c inne dla ka˙zdego typu
komputera (procesora). Istotn ˛
a zewn˛etrzn ˛
a cech ˛
a j˛ezyków wy˙zszego rz˛edu jest zast˛epowanie
ka˙zdej ich instrukcji wieloma rozkazami maszynowymi.
1.1.2
Składnia instrukcji asemblera
Instrukcja jest elementarnym poleceniem dla programu tłumacz ˛
acego. Inaczej mo˙zna po-
wiedzie´c, ˙ze instrukcja jest podstawowym elementem j˛ezyka. Instrukcja mo˙ze:
kodowa´c rozkaz,
zawiera´c dyrektyw˛e,
by´c pusta (komentarz).
Dyrektywa jest to taki rodzaj instrukcji, która słu˙zy do organizowania programu. Na ogół
dyrektywy nie generuj ˛
a kodu, za wyj ˛
atkiem takich, które wprowadzaj ˛
a liczby do pami˛eci da-
nych.
Instrukcja jest zapisana w oddzielnej linii programu ´zródłowego, zatem linia programu jest
jednostk ˛
a organizacji programu ´zródłowego. W linii programu wyró˙znia si˛e cztery pola (zawar-
to´s´c ka˙zdego z nich mo˙ze by´c pusta):
pole_etykiety: pole_operacji pole_argumentów ;pole komentarza
Dwukropek jest wyró˙znikiem pola etykiety, przed komentarzem zawsze musi wyst˛epowa ´c ´sred-
nik. W polu etykiety umieszczana jest nazwa wprowadzana przez programist˛e. U˙zycie nazwy
w polu etykiety nadaje jej warto´s´c w procesie tłumaczenia programu według okre´slonych reguł.
Nazwa w polu etykiety musi by´c zako ´nczona dwukropkiem. Długo´s´c nazwy w polu etykiety
zale˙zy od dopuszczalnej długo´sci nazw danej wersji asemblera. W przypadku pakietu 2500AD
wynosi ona 32 znaki, przy czym zalecane jest u˙zywanie nie wi˛ecej ni˙z 10 znaków. Zawarto ´s´c
2
1.1
Podstawowe wła´sciwo´sci asemblera
pola operacji okre´sla rozkaz maszynowy lub dyrektyw˛e. Natomiast pole argumentówpodaje
dodatkowe argumenty, których liczba i rodzaj zale˙z ˛
a od zawarto´sci pola operacji. Pole komen-
tarza, poprzedzone ´srednikiem, mo˙ze zawiera´c dowolny ci ˛
ag znaków. Komentarz w procesie
tłumaczenia jest przez asembler pomijany. Przykład:
int0:
ACALL przeslij ;prze´
slij komunikat na P1
RETI
komunikat_1: .db ’komunikat 1’,0Dh,0Ah,0
1.1.3
Komentowanie programu
Standardowo komentarz realizuje si˛e przy u˙zyciu ´srednika. Przykład:
;To jest komentarz
;************************
;* Data: xx-xx-xxxx
*
;* Nazwisko programisty *
;* Wersja programu
*
;************************
U˙zycie dyrektywy
.COMMENT
pozwala na swobodne operowanie komentarzem. Cały tekst mi˛e-
dzy znakami przyj˛etymi przez programist˛e jako ograniczniki stanowi komentarz. Przykład:
.comment #
To jest przykład u˙
zycia dyrektywy .comment
Cały tekst zawarty mi˛
edzy hash-ami jest komentarzem
Taki komentarz mo˙
ze mie´
c wiele linii, ale te 3 chyba wystarcz ˛
a...
#
1.1.4
Elementarne obiekty j ˛ezyka
Elementarnymi obiektami j˛ezyka typu asembler, czyli wielko´sciami, na których j˛ezyk wy-
konuje działania, s ˛
a:
stałe,
nazwy,
wyra˙zenia arytmetyczne.
Stałe mog ˛
a by´c zapisane jako:
1. dziesi˛etne: D
2. dwójkowe: B
3. ósemkowe: O, Q
3
1
Programowanie w j˛ezyku asembler
4. szesnastkowe: H
5. znakowe
Stałe liczbowe opatrzone s ˛
a odpowiednim symbolem literowym. Pomini˛ecie symbolu oznacza
liczb˛e dziesi˛etn ˛
a. U˙zycie dyrektywy
.RADIX
powoduje zmian˛e standardowej podstawy liczb
u˙zywanych w programie. Argumentem tej dyrektywy jest jeden z wymienionych symboli lub
liczba b˛ed ˛
aca podstaw ˛
a danego kodu
2
. Stałe znakowe ograniczone s ˛
a znakami pojedynczego
lub podwójnego cudzysłowu. Przykład:
127
;stała dziesi˛
etna
101101101b
;stała binarna
0A3h
;stała szestnastkowa. Je˙
zeli pierwsza cyfra stałej
;jest liter ˛
a to nale˙
zy j ˛
a poprzedzi´
c zerem
’napis’
;pi˛
ecio bajtowa stała znakowa
.radix 16
;ustaw standard liczb szesnastkowy
Nazwa jest ci ˛
agiem liter i cyfr zaczynaj ˛
acym si˛e od litery. Liczba znaków w nazwie zale˙zy
od standardu asemblera. W ró˙znych asemblerach zmienia si˛e tak˙ze zbiór dozwolonych znaków
alfanumerycznych, z których mog ˛
a by´c budowane nazwy i inne obiekty j˛ezyka.
Ostatni ˛
a konstrukcj ˛
a składniow ˛
a jest wyra˙zenie arytmetyczne b˛ed ˛
ace ci ˛
agiem nazw i stałych
przedzielonych dwuargumentowymi operatorami arytmetycznymi. Ka˙zda nazwa lub stała mo˙ze
by´c poprzedzona operatorem jednoargumentowym. Dopuszcza si˛e stosowanie nawiasów w celu
ł ˛
aczenia argumentów. Operatory wyra˙ze ´n arytmetycznych:
1. Operatory jednoargumentowe
‘
.NOT.
’, ‘
\
’,
‘!
’ – zaprzeczenie logiczne,
‘
+
’ – opcjonalne oznacza argument dodatni,
‘
-
’ – negacja arytmetyczna (uzupełnienie dwójkowe),
‘
<
’, ‘
.HIGH.
’ – starszy bajt szesnastobitowego słowa,
‘
>
’, ‘
.LOW.
’ – młodszy bajt szesnastobitowego słowa.
2. Operatory dwuargumentowe
‘
**
’ – pot˛egowanie całkowite,
‘
*
’ – mno˙zenie całkowite,
‘
/
’ – dzielenie całkowite,
‘
.SHR.
’ – przesuw w prawo,
‘
.SHL.
’ – przesuw w lewo,
‘
+
’ – suma arytmetyczna,
2
2, 8, 10 lub 16
4
1.1
Podstawowe wła´sciwo´sci asemblera
‘
-
’ – ró˙znica arytmetyczna,
‘
.AND.
’, ‘
&
’ – iloczyn logiczny,
‘
.OR.
’, ‘
^
’ – suma logiczna,
‘
.XOR.
’ – suma modulo 2 (ró˙znica symetryczna)
Warto´sci wyra˙ze ´n arytmetycznych zapisywane s ˛
a w słowie o´smio lub szesnastobitowym w za-
le˙zno´sci od kontekstu wyra˙zenia. Nale˙zy podkre´sli´c, ˙ze w asemblerze wyra˙zenia arytmetyczne
słu˙z ˛
a do obliczania warto´sci nazw, a nie do realizacji oblicze ´n przez program wynikowy. War-
to´sci wyra˙ze ´n arytmetycznych s ˛
a obliczane podczas procesu tłumaczenia, a nie w trakcie jego
realizacji.
W trakcie asemblacji mo˙zliwe jest stosowanie porówna ´n, których wynikiem jest
1
gdy wa-
runek jest spełniony lub
0
gdy nie jest. Operatory porówna ´n:
‘
=
’, ‘
.EQ.
’ – równo´s´c,
‘
>
’, ‘
.GT.
’ – wi˛eksze ni˙z,
‘
<
’, ‘
.LT.
’ – mniejsze ni˙z,
‘
.UGT.
’ – wi˛eksze ni˙z dla liczb bez znaku (ang. unsigned),
‘
.ULT.
’ – mniejsze ni˙z dla liczb bez znaku.
1.1.5
Tworzenie nazw i operacje na słowniku
Asembler w chwili rozpocz˛ecia tłumaczenia zawiera pewien wst˛epnie zdefiniowany słownik
Umieszczone s ˛
a w nim nazwy rozkazów procesora, nazwy dyrektyw, nazwy innych obiektów
j˛ezyka (np. nazwy rejestrów). Nazwy te mog ˛
a by ´c u˙zywane w programie wg. okre´slonych reguł,
zgodnie ze sposobem budowy rozkazów mikroprocesora i konstrukcji asemblera. Podstawowym
sposobem dopisania nowej nazwy do słownika jest umieszczenie jej w polu etykiety. W procesie
tłumaczenia nazwa b˛ed ˛
aca etykiet ˛
a uzyskuje warto´s´c równ ˛
a bie˙z ˛
acemu wska´znikowi umiesz-
czenia
3
. Bie˙z ˛
acy wska´znik umieszczenia jest zmienn ˛
a procesu tłumaczenia przybieraj ˛
ac ˛
a war-
to´sci równe adresom, pod którymi lokowany jest kod wynikowy. Programista powinien ustawi ´c
warto´s´c wska´znika przed napisaniem pierwszej linii programu zawieraj ˛
acej rozkaz. Do tego celu
słu˙zy dyrektywa
.ORG
4
, której argumentem jest warto´s´c adresu nadawana, przy ka˙zdym u˙zyciu
dyrektywy, bie˙z ˛
acemu wska´znikowi umieszczenia. W pakiecie 2500AD pomini˛ecie pocz ˛
atko-
wej dyrektywy
.ORG
powoduje przyj˛ecie domy´slnej warto´sci wska´znika umieszczenia
$=0000
.
Przykład:
;program przykładowy
.org 0
;$=0000h
ajmp start
.org 3
;obsługa przerwania INT0
3
Oznaczanym ‘
$
’
4
ORIGIN
5
1
Programowanie w j˛ezyku asembler
int0:
acall 100h ;prze´
slij komunikat na port P1
reti
.org 30h
start:
acall 40h
;inicjacja mikrokontrolera
czekaj: nop
ajmp czekaj
;czekaj na przerwanie
Innym sposobem dopisania nazwy do słownika, czyli nadania jej warto ´sci, jest u˙zycie jednej
z dyrektyw
.SET
lub
.EQU
, których argumentem jest wyra˙zenie arytmetyczne. Ró˙znica pomi˛e-
dzy
.SET
a
.EQU
sprowadza si˛e do tego, ˙ze nazwa zdefiniowana przez
.SET
mo˙ze by ´c w tym
samym programie okre´slana wielokrotnie w ró˙znych miejscach – nazwa redefiniowalna. Nato-
miast zdefiniowanie nazwy dyrektyw ˛
a
.EQU
wyklucza jej powtórne okre´slenie. Nazwa taka jest
nieredefiniowajna i nazywana jest cz˛esto absolutn ˛
a.
Program tłumacz ˛
acy musi jednoznacznie przypisa ´c ka˙zdej nowej nazwie odpowiedni ˛
a war-
to´s´c. Proces tłumaczenia przebiega sekwencyjnie linia po linii od pocz ˛
atku programu. Ist-
nieje mo˙zliwo´s´c wielokrotnego definiowania tych samych nazw, a ponadto mo˙ze si˛e zdarzy ´c, ˙ze
w procesie tłumaczenia danej linii nazwa w niej u˙zyta nie została jeszcze zdefiniowana. Z po-
wy˙zszych powodów ka˙zdej tworzonej przez programist˛e nazwie musz ˛
a by ´c przyporz ˛
adkowane
atrybuty maj ˛
ace posta´c jednobitowej informacji towarzysz ˛
acej nazwie. Podstawowe atrybuty to:
1. warto´s´c (
0
– brak warto´sci,
1
– jest warto´s´c) ,
2. logiczne – redefiniowalno´s´c
Atrybut okre´slono´sci mówi o tym, czy w chwili tłumaczenia danej linii nazwa ma ju˙z warto ´s´c.
Warunkiem koniecznym poprawno´sci programu jest to, aby po przetłumaczeniu ostatniej linii
programu wszystkiem nazwy w słowniku były okre´slone.
1.1.6
Dyrektywy rezerwacji pami ˛eci
Słu˙z ˛
a do rezerwowania pami˛eci operacyjnej na pola robocze programu (s ˛
a to elementy pa-
mi˛eci danych) oraz do ustalania pocz ˛
atkowych warto´sci tych pól.
Dyrektywa
.DB
.DB lista_argumentów
Po przetworzeniu tej dyrektywy w kolejnych bajtach kodu wynikowego s ˛
a umieszczane warto ´sci
odpowiednich wyra˙ze ´n arytmetycznych lub warto´sci kodów ASCII znaków tworz ˛
acych stałe
znakowe.
Dyrektywa
.DW
Dyrektywa ta ma analogiczn ˛
a składni˛e jak
.DB
, z tym ˙ze jej argumenty słu˙z ˛
a do okre ´slania
warto´sci szesnastobitowych.
6
1.2
Makroasembler
Dyrektywa
.DS
Słu˙zy do rezerwacji liczby komórek okre´slonej przez parametr b˛ed ˛
acy jej argumentem.
W rezerwowany obszar nie jest wpisywana ˙zadna informacja lub jest on zerowany (na ogół
na ˙z ˛
adanie programisty).
1.1.7
Dyrektywa ko ´
ncz ˛
aca program
Dyrektyw ˛
a ko ´ncz ˛
ac ˛
a program jest dyrektywa
.END
.
1.2
Makroasembler
1.2.1
Ogólne wła ´sciwo ´sci makroasemblera
Makroasembler jest asemblerem rozsze˙zonym o dodatkowe dyrektywy i konstrukcje, któ-
rych u˙zycie pozwala programi´scie na wykonanie pewnych operacji na tek´scie programu ´zródło-
wego. W wyniku tych operacji mo˙zna:
kre´sli´c warunek uwzgl˛ednienia lub zignorowania fragmentu programu ´zródłowego,
zdefiniowa´c pewn ˛
a instrukcj˛e, której u˙zycie jest równoznaczne wstawieniu ci ˛
agu linii pro-
gramu,
spowodowa´c wstawienie w program ´zródłowy ci ˛
agu linii skojarzonych z wcze´sniej okre-
´slon ˛
a instrukcj ˛
a.
W przypadku makroasemblera proces tłumaczenia ró˙zni si˛e w pewnym stopniu od tłumaczenia
w prostym asemblerze. Ka˙zda wczytana linia podlega wst˛epnej analizie i ew. przetworzeniu.
W wyniku tego linia mo˙ze:
zosta´c zignorowana,
by´c przekazana do dalszej asemblacji bez zmian,
doprowadzi´c do wytworzenia ci˛egu linii z jednej linii wczytanej.
Operacje te zawsze poprzedzaj ˛
a wła´sciwe tłumaczenie w sensie prostego asemblera.
1.2.2
Asemblacja warunkowa
Podstawowa konstrukcja programowa słu˙z ˛
aca do warunkowego tłumaczenia programu ma
nast˛epuj ˛
ac ˛
a posta´c:
.if [warunek]
.
;program tłumaczony je´
sli warunek spełniony (1)
.
7
1
Programowanie w j˛ezyku asembler
.else
.
;program tłumaczony je´
sli warunek nie jest spełniony (0)
.
.endif
Dyrektywa
.ELSE
nie jest obligatoryjna. Jej brak oznacza, ˙ze dany fragment programu jest tłu-
maczony, lub nie, bez ˙zadnej alternatywy. Argument dyrektywy
.IF
okre ´sla warto´s´c logiczn ˛
a
w ten sposób, ˙ze warto´s´c wyra˙zenia arytmetycznego u˙zytego jako argument ró˙znej od zera od-
powiada prawda, warto´sci równej zero odpowiada fałsz.
1.2.3
Makrodefinicje
Makrodefinicje definuje si˛e przez umieszczenie fragmentu programu ´zródłowego mi˛edzy
dyrektywami
.MACRO
i
.ENDM
w nast˛epuj ˛
acy sposób:
nazwa: .macro lista,parametrów,formalnych
.
.
;tre´
s´
c makrodefinicji
.
.
.endm
Przykład:
wstaw:
.macro rozkaz, warto´
s´
c
rozkaz
etykieta: .db warto´
s´
c
.endm
Tre´s´c makrodefinicji mo˙ze stanowi´c dowolny ci ˛
ag znaków, który nie musi miec składni popraw-
nej instrukcji i mo˙ze si˛e składa´c z praktycznie dowolnej liczby linii. Ogólnie definicja makroin-
strukcji słu˙zy do tego, aby za pomoc ˛
a jednej linii programu wstawi ´c ci ˛
ag linii okre´slony w tej
definicji. Lini˛e zawieraj ˛
ac ˛
a nazw˛e makrodefinicji nazywa si˛e wywołaniem makroinstrukcji. Za-
wiera ona w polu parametrów ci ˛
ag wyra˙ze ´n arytmetycznych w liczbie odpowiadaj ˛
acej liczbie
parametrów formalnych. Argumenty te nazywa si˛e parametrami aktualnymi. Makroasembler
przetwarzaj ˛
ac wywołanie makroinstrukcji (rozwijaj ˛
ac makroinstrukcj˛e) zast˛epuje odpowiednie
parametry formalne ich aktualnymi warto´sciami. Wywołanie mo˙ze by´c powtarzane dowoln ˛
a
ilo´s´c razy.
1.3
Tworzenie programów w postaci modułowej
1.3.1
Moduły programowe
Ko´ncowa posta´c programu wynikowego powstaje z reguły jako wynik scalania wielu jego
ró˙znych fragmentów. Przyczyny tego maj ˛
a ró˙zny charakter. Wynikaj ˛
a one przede wszystkim
8
1.3
Tworzenie programów w postaci modułowej
z konieczno´sci tworzenia programu przez zespół programistów, a zatem podziału na fragmenty
tworzone równolegle. Bardzo cz˛esto korzysta si˛e przy tym z bibliotek programów standar-
dowych (np. mno˙zenia i dzielenia zmiennoprzecinkowego, konwersji liczb. . . ) tworzonych
i przechowywanych w postaci odr˛ebnych modułów. Równie˙z wła´sciwo´sci fizyczne oprogra-
mowywanego procesora zmuszaj ˛
a do wyodr˛ebnienia fragmentów programu. Na przykład dla
mikrokontrolerów z rozdzielon ˛
a pami˛eci ˛
a programu i danych kod wynikowy trzeba rozdzieli ´c
zgodnie z przeznaczeniem do odpowiednich rodzajów pami˛eci. Podział logiczny dokonywany
jest przez programist˛e w celu wyodr˛ebnienia samodzielnych fragmentów nazywanych proce-
durami. Z reguły procedura jest podprogramem komunikuj ˛
acym si˛e z innymi procedurami za
pomoc ˛
a okre´slonych standardów przekazywania danych. Zatem procedury mog ˛
a by ´c budowane
niezale˙znie – zmiany wprowadzone w ich obr˛ebie nie maj ˛
a bezpo´sredniego wpływu na inne
procedury. Taki sposób tworzenia programu nazywany jest modularnym i stanowi jeden z pod-
stawowych standardów dobrego programowania.
Podstawow ˛
a jednostk ˛
a programow ˛
a z punktu widzenia asemblera jest moduł
5
. Jest to taki
ci ˛
ag linii programu, który dla asemblera stanowi jedn ˛
a cało´s´c. Oznacza to, ˙ze dla ka˙zdego
modułu asembler rozpoczyna swoje działanie od pocz ˛
atku (mówi si˛e, ˙ze ma miejsce restart
asemblera). Przede wszystkim modułem jest plik z programem ´zródłowym. Mo˙zna jednak
wyodr˛ebni´c moduły w ramach pojedynczego pliku. Słu˙z ˛
a do tego dyrektywy asemblera
.MOD
i
.ENDMOD
.
Z tego, ˙ze poszczególne moduły tłumaczone s ˛
a niezale˙zne, a nast˛epnie zestawiane w jedn ˛
a
cało´s´c, wynikaj ˛
a dwa istotne fakty:
kod programu uzyskany w wyniku asemblacji musi mie ´c tak ˛
a postac aby mógł by´c umiesz-
czony w dowolnym obszarze pami˛eci – posta ´c taka nazywa si˛e postaci ˛
a relokowaln ˛
a
(przesuwaln ˛
a),
z konieczno´sci tworzenia programów z po´srednich postaci przesuwalnej wynika potrzeba
dwustopniowej realizacji procesu tłumaczenia (rys. 1.2). W pierwszej fazie przy u˙zyciu
asemblera tworzone s ˛
a programy w postaci relokowalnej, w drugiej fazie moduły relo-
kowalne s ˛
a zespalane w procesie konsolidacji
6
w jedn ˛
a cało´s´c lokowan ˛
a w obszarach
pami˛eci o ´sci´sle okre´slonych adresach. T ˛
a drug ˛
a faz˛e realizuje program nazywany konso-
lidatorem lub programem ł ˛
acz ˛
acym
7
.
Techniczne aspekty procesu konsolidacji wymagaj ˛
a podziału modułów na mniejsze cz˛e ´sci, ele-
mentarne z punktu widzenia konsolidatora. Wynika to przedewszystkim z konieczno ´sci podziału
ka˙zdego modułu na cz˛e´sci zawieraj ˛
ace program i dane, a tak˙ze na inne fragmenty zwi ˛
azane ze
specyfik ˛
a konstrukcji procesera. Dla INTEL 8051 wyodr˛ebnianie fragmentów programu zwi ˛
a-
zane jest z podziałem pami˛eci RAM na wewn˛etrzn ˛
a i zewn˛etrzn ˛
a, wydzieleniem rejestrów ro-
boczych i specjalnych oraz pami˛eci adresowanej bitowo.
Definiuje si˛e poj˛ecie sekcji
8
lub segmentu jako takiego, spójnego logicznie, fragmentu pro-
gramu, który jest traktowany przez konsolidator jako jedna elementarna cało ´s´c. Oznacza to, ˙ze
5
ang. module
6
ł ˛
aczenia, linkowania
7
ang. linker
8
ang. section
9
1
Programowanie w j˛ezyku asembler
Asembler
Moduł 1
Moduł n
Asembler
Konsolidator
Program
wynikowy
*.obj
*.asm
*.asm
*.obj
*.exe
Rysunek 1.2: Proces tworzenia programów w postaci modułowej
mo˙zna wskaza´c konsolidatorowi adres, pod którym nale˙zy umie´sci´c dan ˛
a sekcj˛e oraz dodatkowe
parametry okre´slaj ˛
ace typ sekcji (np. sekcja z programem, danymi, sekcja rejestrowa. . . ).
Bior ˛
ac pod uwag˛e, ˙ze w procesie konsolidacji zespalane mo˙ze by ´c wiele modułów w ka˙z-
dym z nich mo˙zna na ogół wyró˙zni´c sekcje tego samego typu. Sekcje takie powinny by ´c ł ˛
aczone
ze sob ˛
a i umieszczane w zwartym obszrze pami˛eci. Zatem cz˛esto wygodzniej jest operowa ´c na
wi˛ekszych cało´sciach nazywanych grupami sekcji lub grupami. Grupa jest to zespół sekcji o ta-
kich samych nazwach w ró˙znych modułach traktowanych przez konsolidator tak jak pojedyncza
sekcja.
1.3.2
Absolutne i wzgl ˛edne tłumaczenie modułów programowych
Budowanie programu w postaci modułowej wymaga uzyskiwania po asemblacji kodu w po-
staci przesuwalnej umo˙zliwiaj ˛
acej ulokowanie modułu w dowolnym obszarze pami˛eci. Powo-
duje to z kolei konieczno´s´c przyporz ˛
adkowania ka˙zdemu modułowi adresu bazowego, który
stanowi adres odniesienia, wzgl˛edem którego okre´slane s ˛
a warto´sci wszystkich przesuwalnych
(relokowalnych) nazw w danym module. Ilustruje to poni˙zszy przykład
9
:
;program wyprowadzania komunikatu przez port P1
;adres pocz ˛
atku komunikatu w DPTR
.org
BAZA
pisz_kom1:
mov
dptr,#komunikat_1 ;ładuj rejestr bazowy
mov
r0,#0
;licznik znaków
dalej:
mov
a,r0
movc
a,@a+dptr
;pobierz znak
cjne
a,#0,nie_koniec ;czy koniec ła´
ncuch znaków?
ret
;tak
nie_koniec:
mov
p1,a
;nie
inc
r0
ajmp
dalej
;komunikat nr 1
kom_end:
.equ 0
;znak ko´
nca
komunikat_1: .db ’komunikat 1’,0ah,0dh,kom_end
9
U˙zyta w nim nazwa
BAZA
symbolizuje jedynie adres bazowy i słu˙zy do uwidocznienia relacji mi˛edzy tym adresem
a warto´sci ˛
a nazw relokowalnych.
10
1.3
Tworzenie programów w postaci modułowej
Program ´zródłowy
Program wynikowy
aders (hex)
kod (hex)
.org BAZA
BAZA
pisz_kom1:
mov
dptr,#komunikat
_
1
BAZA
90 00 10
mov
r0,#0
BAZA+0003
78 00
dalej:
mov
a,r0
BAZA+0005
e8
movc a,@a+dptr
BAZA+0006
93
cjne a,#0,nie_koniec
BAZA+0007
b4 00 01
ret
BAZA+000a
22
nie_koniec:
mov
p1,a
BAZA+000b
f5 90
inc
r0
BAZA+000d
08
ajmp dalej
BAZA+000e
01 05
kom_end:
.equ 0
BAZA+0010
komunikat_1:
.db ’komunikat 1’,0ah,0dh,kom_end
BAZA+0010
6b 6f 6d
75 6e 69
itd. . .
Analizuj ˛
ac uzyskany program wynikowy mo˙zna stwierdzi ´c, ˙ze adres ka˙zdej komórki pami˛eci
daje si˛e wyrazi´c w postaci sumy dwóch składników: adresu bazowego (który tutaj symbolizuje
ogólnie nazwa
BAZA
) oraz cz˛e´sci stałej. Adres bazowy jest jednakowy dla wszystkich komórek
przechowuj ˛
acych kod wynikowy danego modułu programowego, przy czym ulega on zmianie
wraz ze zmian ˛
a poło˙zenia modułu w pami˛eci. Cz˛e´s´c stała adresu komórki nie zmienia si˛e nie-
zale˙znie od lokalizacji modułu bowiem wskazuje ona odległo´s´c od pocz ˛
atku modułu. Z powy˙z-
szego wynika, ˙ze operacje zwi ˛
azane z działaniem na adresach komórek przy zmianie poło˙zenia
modułu w pami˛eci s ˛
a proste – polegaj ˛
a na dodaniu do ka˙zdej warto ´sci stałej, zwi ˛
azanej nie-
rozł ˛
acznie z ka˙zdym kodem rozkazu uzyskanym po asemblacji, adresu bazowego okre ´slaj ˛
acego
aktualne poło˙zenie modułu w pami˛eci. Programista ma do dyspozycji szereg mo˙zliwo ´sci od-
działywania na adres bazowy modułu – zarówno przy u˙zyciu asemblera jak i w trakcie procesu
konsolidacji.
1.3.3
Atrybuty nazw w programach modułowych
W ka˙zdym programie wyst˛epuj ˛
a etykiety, czyli nazwy symblolizuj ˛
ace adresy okre ´slonych
miejsc w pami˛eci. W trakcie zmiany poło˙zenia modułu w pami˛eci musz ˛
a one podlega ´c takim
samym regułom przemieszczania jak inne adresy. Ponadto mo˙zna równie˙z definiowa ´c nazwy,
które zachowuj ˛
a stał ˛
a warto´s´c niezale˙znie od poło˙zenia modułu. Dla powy˙zszego przykładu
mo˙zna zestawi´c nast˛epuj ˛
ac ˛
a tablic˛e nazw:
Nazwa
Warto´s´c
Atrybyt absolutno´sci
pisz_kom1
BAZA+0000
0
dalej
BAZA+0005
0
nie_koniec
BAZA+000b
0
komunikat_1
BAZA+0010
0
kom_end
00
1
11
1
Programowanie w j˛ezyku asembler
Nazwy, których warto´s´c zale˙zy od poło˙zenia modułu w pami˛eci nazywane s ˛
a przesuwalnymi
(relokowalnymi), natomiast nazwy o stałych warto´sciach – absolutnymi. Ka˙zdej nazwie mo˙zna
przypisa´c atrybut absolutno´sci, który stanowi dla programu tłumacz ˛
acego wska´znik czy nale˙zy,
lub nie, modyfikowa´c nazw˛e przy zmianie poło˙zenia modułu.
1.3.4
Relokowalo ´s ´c modułów
Mo˙zna nakaza´c tłumaczenie fragmentów programu w sposób absolutny umieszczaj ˛
ac je
mi˛edzy dyrektywami:
.ABSOLUTE
,
.RELATIVE
.
Dyrektywa
.ABSOLUTE
powoduje przej´scie asemblera w tryb tłumaczenia absolutnego, co ozna-
cza, ˙ze wszystkie nazwy w tym trybie maj ˛
a atrybut absolutno´sci równy 1. Dyrektywa
.RELATIVE
przywraca tryb wzgl˛edny działania asemblera. Tryb ten jest zazwyczaj trybem domy ´slnym
asemblera o ile programista nie naka˙ze inaczej.
Tryb absolutny powinien by´c stosowany tylko w szczególnych przypadkach, poniewa˙z po-
ł ˛
aczenie modułów absolutnych z relokowalnymi mo˙ze prowadzi ´c do utworzenia niepoprawnych
sekwencji programowych. Poniewa˙z cz˛esto przyjmuje si˛e zasad˛e, ˙ze nie wyró˙znia si˛e w spe-
cjalny sposób modułów absolutnych, w zwi ˛
azku z czym s ˛
a one ł ˛
aczone z innymi modułami na
takich samych zasadach. Oznacza to, ˙ze w module absolutnym mog ˛
a ulega ´c przesuni˛eciu adresy
komórek pami˛eci natomiast nazwy definiowane w tym module pozostaj ˛
a stałe. Przykład:
adres
kod
.absolute
.org 20
petla:
nop
0020
00
ajmp petla
0021
01 20
Nazwa
PETLA
w tym przykładzie uzyskuje warto´s´c absolutn ˛
a
0020h
. Załó˙zmy, ˙ze ł ˛
aczy si˛e po-
wy˙zszy program z innymi, w efekcie czego program ten zostaje umieszczony od adresu
1000h
:
adres
kod
petla:
nop
1020
00
ajmp petla
1021
01 20
Zatem posta´c ko ´ncowa (wynikowa) tego fragmentu programu jest niepoprawna. Wynika st ˛
ad
wniosek, ˙ze za wyj ˛
atkiem szczególnych przypadków moduły programowe nale˙zy tłumaczy ´c
w sposób wzgl˛edny, a ich wła´sciw ˛
a lokalizacj˛e w pami˛eci okre´sla´c dopiero w trakcie konsolida-
cji.
Przykład ten ilustruje równie˙z specyfik˛e stosowania dyrektywy
.ORG
w modułach przesu-
walnych – wskazuje ona odległo´s´c miejsca w module programowym od pocz ˛
atku modułu wska-
zywanego przez adres bazowy. Standardowo przyjmuje si˛e w procesie asemblacji, ˙ze adres
bazowy ka˙zdego z modułów równa si˛e zera. W trakcie konsolidacji do tego adresu dodawany
12
1.3
Tworzenie programów w postaci modułowej
jest adres przesuni˛ecia modułu (ang. offset), który jest dodawany do wszystkich adresów wska-
zywanych przez dyrektyw˛e
.ORG
. Powoduje to, ˙ze argument tej dyrektywy i przesuni˛ecie dodaj ˛
a
si˛e.
1.3.5
Współu˙zywanie nazw w modułach
Budowanie programu w postaci modułowej, a nast˛epnie ł ˛
aczenie modułów w jeden wspólny
program wymaga definiowania nazw wspólnych dla wielu modułów. Równie˙z w przypadku
doł ˛
aczania modułów bibliotecznych niezb˛edne jest u˙zycie nazw definiowanych przez moduły.
To wszystko powoduje, ˙ze w trakcie asemblacji w pewnych modułach pojawiaj ˛
a si˛e nazwy,
których warto´sci nie s ˛
a okre´slone w danym module.
Nazwa, która jest definowana w danym module i jest udost˛epniana równie˙z na zewn ˛
atrz
modułu, co oznacza ˙ze jest wa˙zna w całym programie, nazywana jest nazw ˛
a globaln ˛
a. Wskazy-
wanie nazw globalnych odbywa si˛e przy u˙zyciu dyrektywy:
.GLOBAL ci ˛
ag,nazw
Dyrektywa ta nadaje nazw ˛
a atrybut globalno´sci.
Nazwy, które s ˛
a u˙zywane w danym module, przy zało˙zeniu, ˙ze s ˛
a definiowane w innym, na-
zywane s ˛
a zewn˛etrznymi z punktu widzenia tego modułu. Nazwy takie wskazuje si˛e dyrektyw ˛
a:
.EXTERNAL ci ˛
ag,nazw
U˙zycie tej dyrektywy powoduje nadanie wskazanym nazw ˛
a atrybutu zewn˛etrzno´sci.
Z powy˙zszych uwag wynika, ˙ze modułowe tworzenie programów wymaga wyposa˙zenia
nazw w trzy dodatkowe atrybuty: absolutno´sci, globalno´sci i zewn˛etrzno´sci. Atrybuty te s ˛
a
niezb˛edne w procesie konsolidacji do uzyskania kodu programu wynikowego i stwierdzenia
poprawno´sci wszystkich działa ´n składaj ˛
acych si˛e na ten proces.
Przykład ilustruj ˛
acy sposób posługiwania si˛e nazwami współu˙zywanymi w ró˙znych mody-
łach:
.module ;moduł 1
.global start
.external init
start: acall init
.endmod
.module ;moduł 2
.global init
init:
mov a,#10h
.
.
.
ret
.endmod
13
1
Programowanie w j˛ezyku asembler
1.3.6
Doł ˛
aczanie modułu zawieraj ˛
acego kod ´zródłowy programu
Podstawowy moduł programowy ma posta´c pliku. Wyró˙znikiem pliku jest jego nazwa
(w przykadku modułów asemblerowych wymagane jest rozszerzenie
*.asm
). Ka˙zdy moduł jest
tłumaczony oddzielnie, w wyniku czego uzyskiwany jest plik z kodem przesuwalnym (
*.obj
)
nosz ˛
acy na ogół tak ˛
a sam ˛
a nazw˛e jak plik ´zródłowy. Pliki z kodem przesuwalnym poddawane s ˛
a
konsolidacji polegaj ˛
acej na zespoleniu odpowiednich fragmentów programu (sekcji) z ró˙znych
modułów i lokowanie ich w wybranych obszarach pami˛eci.
Istnieje sposób bardzo prosty cho´c znacznie mniej elestyczny od wy˙zej wymienionego słu-
˙z ˛
acy do ł ˛
aczenia modułów. Jest ono wówczas wykonywane na poziomie tekstu programu ´zró-
dłowego za pomoc ˛
a dyrektywy:
.INCLUDE nazwa_pliku.asm
1.4
Sekcje
1.4.1
Typy sekcji
Sekcja – wyró˙zniony fragment programu stanowi ˛
acy elementarn ˛
a cało ´s´c z punktu widze-
nia konsolidatora. Nadaje on sekcji jedno stałe przesuni˛ecie (ang. offset). Cz˛esto takie same
konstrukcje programowe jak sekcje nazywane s ˛
a w innych asemblerach segmantami, przy czym
na ogół sposób definiowania segmentów nie pozwala na tak du˙z ˛
a eleastyczno ´s´c struktury pro-
gramu jak to ma miejsce w przypadku sekcji. Opisany sposób definiowania sekcji zwi ˛
azany jest
ze specyficznymi cechami budowy mikrokontrolerów rodziny INTEL 8051. Mo˙zna wskaza ´c
dwa sposoby definiowania sekcji: przy u˙zyciu standardowych dyrektyw tybów sekcji oraz jako
sekcji u˙zytkowanika.
U˙zycie standardowych typów sekcji powoduje, ˙ze w trakcie konsolidacji s ˛
a one traktowane
priorytetowo w stosunku do sekcji definiowanych przez u˙zytkownika. Oznacza to, ˙ze s ˛
a one lo-
kowane jako pierwsze, przy czym priorytet lokowania samych sekcji standardowych jest zgodny
z zestawieniem.
.CODE
– sekcja z programem,
.DATA
– sekcja z danymi,
.RSECT
– sekcja rejestrowa,
.BSECT
– sekcja w pami˛eci bitowej.
Typ
.CODE
ma najwy˙zszy priorytet, a ponadto jest standardowym (domy´slnym) typem sekcji
– ka˙zdemu fragmentowi programu ´zródłowego o nieokre´slonym typie sekcji nadawany jest ten
typ.
14
1.4
Sekcje
1.4.2
Składnia dyrektywy .SECTION
U˙zytkownik definiuje sekcje za pomoc ˛
a dyrektywy:
nazwa_sekcji: .SECTION argumenty_opcjonalne
Argumenty dyrektywy wskazuj ˛
a sposób lokowania sekcji w pami˛eci. Nazwa zdefiniowana przy
u˙zyciu dyrektywy
.SECTION
sama mo˙ze by´c u˙zywana jak dyrektywa, a konkretnie jako prze-
ł ˛
acznik sekcji. Przykład:
nop
;sekcja CODE
.DATA
;przeł ˛
acz na sekcj˛
e DATA
.ds 1
;bajt w sekcji DATA
SEKCJA_1 .SECTION
;definiuje i aktywizuje sekcj˛
e u˙
zytkownika
nop
;rozkaz w sekcji SEKCJA_1
.CODE
nop
;a ten w sekcji CODE
.SEKCJA_1 ;przeł ˛
acza na sekcje u˙
zytkownika
nop
;sekcja u˙
zytkownika mo˙
ze zawiera´
c rozkazy
.ds 1
;i dane
Powy˙zszy przykład pokazuje, ˙ze poszczególne fragmenty programu mo˙zna zestawia ´c w sekcje
w sposób praktycznie dowolny. Bior ˛
ac pod uwag˛e, ˙ze sekcje tego samego typu (w przypadku
sekcji u˙zytkownika oznacza to sekcje o tej samej nazwie) z ró˙znych modułów s ˛
a zespalane
w jedn ˛
a cało´s´c przez konsolidator daje to programi´scie elastyczne narz˛edzie tworzenia struk-
tur programowych dostasowanych zarówno do specyfiki budowy pami˛eci mikrokontrolera jak
i konstrukcji programu.
1.4.3
Sekcje rejestrowe i sekcje bitowe
Sekcje rejestrowe – konstrukcje obejmuj ˛
ace pojedyncze rejestry lub ich grupy. Definiowane
s ˛
a za pomoc ˛
a dyrektywy
.RSECT
lub przy u˙zyciu modyfikatora
REG
po dyrektywie
.SECTION
.
Jedyn ˛
a dyrektyw ˛
a, która mo˙ze wyst˛epowa ´c wewn ˛
atrz sekcji rejestrowej jest dyrektywa
.DS
.
Sposób tworzenia sekcji ilustruje przykład:
.RSECT
;przeł ˛
acza na sekcj˛
e rejestrow ˛
a
reg1:
.ds 1
sekcja_rej: .section reg ;definiuje rejestrow ˛
a sekcj˛
e u˙
zytkownika
reg2:
.ds 1
reg3:
.ds 1
Sekcje bitowe – umo˙zliwiaj ˛
a indywidualne adresowanie bitów. Mo˙zna utworzy ´c j ˛
a za po-
moc ˛
a standardowej dyrektywy
.BSECT
lub za pomoc ˛
a modyfikatora
BIT
. Wewn ˛
atrz sekcji bito-
wej mo˙zna u˙zywa´c jedynie dyrektywy
.DS
.
15
1
Programowanie w j˛ezyku asembler
1.5
Lokowanie sekcji w pami ˛eci
1.5.1
Sposoby lokowania sekcji
Umieszczenie sekcji w okre´slonym miejscu pami˛eci polega na podaniu adresu sekcji, tj.
adresu pierwszej komórki pami˛eci zadeklarowanej jako pocz˛etek sekcji oraz ew. adresu ko ´nca
sekcji (chocia˙zby w celu unikni˛ecia braku pamieci – przepełnienia). Adres sekcji mo˙ze by ´c
wskazany w programie ´zródłowym jako argument dyrektywy
.SECTION
lub w trakcie konsoli-
dacji. Zalecany jest drugi sposób bo zapewnia znacznie wi˛eksz ˛
a elastyczno ´s´c procesu lokowa-
nia.
Mo˙zna wyró˙zni´c kilka rodzajów sekcji ze wzgl˛edu na ich sposób lokowania w pami˛eci.
Bior ˛
ac pod uwag˛e sposób wykorzystania celowe jest wyodr˛ebnienie trzech rodzajów sekcji:
sekcje bezpo´srednio lokowane w pami˛eci (ang. direct),
sekcje po´srednio lokowane w pami˛eci (ang. indirect),
sekcje referencyjne (ang. reference only).
Sekcja bezpo´srednia charakteryzuje si˛e tym, ˙ze jest u˙zywana w tym obszarze pami˛eci, w którym
została ulokowana w trakcie konsolidacji. Oznacza to, ˙ze kod wynikowy i wszystkie nazwy
zdefiniowane dla danej sekcji nie podlegaj ˛
a ˙zadnym zmianom w trakcie realizacji programu
u˙zytkowego.
Po´srednie lokowanie sekcji polega na tym, ˙ze sekcja po konsolidacji jest umieszczona w jed-
nym miejscu, a nast˛epnie po rozpocz˛eciu pracy programu zostaje przeniesiona w inne niejsce
gdzie jest u˙zytkowana. Oznacza to, ˙ze warto´sci wszystkich nazw definiowanych w danej sek-
cji s ˛
a wyznaczane nie dla miejsca umieszczenia jej po konsolidacji lecz zgodnie z lokalizacj ˛
a
sekcji w trakcie jej u˙zytkowania przez program (np. dla sekcji z danymi przemieszczenie jej
z pami˛eci programu ROM do pami˛eci danych RAM mo˙ze mie ´c na celu umo˙zliwienie jej aktu-
alizacji w trakcie realizacji programu).
Sekcja refernecyjna jest sekcj ˛
a pust ˛
a tzn. w trakcie konsolidacji nie jest w niej lokowany
˙zaden kod wynikowy. Jest kreowana jedynie dla celów wyznaczania warto ´sci adresów niezb˛ed-
nych dla programu u˙zytkowego. (np. mo˙ze to by ´c tablica w pami˛eci danych, której adresy
s ˛
a wyznaczane w trakcie kosolidacji i przekazywane pod postaci ˛
a odpowiednich nazw do pro-
gramu u˙zytkowego w celu umo˙zliwienia działania na elementach tej tablicy.)
1.5.2
Zwi ˛
azki mi ˛edzy sekcjami
Sekcje po przeprowadzeniu konsolidacji mog ˛
a by ´c:
odseparowane tzn. lokowane w oddzielnych obszarach pami˛eci np. jako sekcje z danymi
i programem,
sklejone (ang. stacked),
nało˙zone na siebie (ang. common).
16
1.5
Lokowanie sekcji w pami˛eci
Pamie˛c´
Sekcja 1
Sekcja 2
Pamie˛c´
Adres kon´ca sekcji 2
Adres pocz. sekcji 1
Sekcja 1
Sekcja 2
Adres kon´ca sekcji1 =
Adres pocz. sekcji 2
Pamie˛c´
Sekcja 1
Sekcja 2
Adres kon´ca sekcji 1
Adres kon´ca sekcji 2
Adres pocz. sekcji 1 =
Adres pocz. sekcji 2
odseparowane
sklejone
nało˙zone na siebie
Rysunek 1.3: Zwi ˛
azki mi˛edzy sekcjami
1.5.3
Sterowanie lokowaniem sekcji
Rozmieszczenie sekcji w pami˛eci mo˙ze by ´c sterowane z poziomu asemblera za pomoc ˛
a
argumentów dyretywy
.SECTION
:
OFFSET
Argument
OFFSET adres
powoduje bezpo´srednie umieszczenie sekcji pod wskaza-
nym adresem przy zało˙zeniu, ˙ze adres pocz ˛
atku sekcji wynosi zero. U˙zycie dyrek-
tywy:
sekcja1:
.section offset 100h
powoduje utworzenie sekcji o nazwie “
sekcja1
” i nakazuje ulokowanie jej w pa-
mi˛eci programu z przesuni˛eciem
100h
w stosunku do pocz ˛
atku sekcji okre ´slonego
dyrektyw ˛
a
.ORG
.
INDIRECT
Po´srednie lokowanie sekcji umo˙zliwia argument
INDIRECT addres
, gdzie
adres
wskazuje miejsce, do którego sekcja zostanie przeniesiona po rozpocz˛eciu pracy
programu. U˙zycie dyrektywy:
sekcja1:
.section offset 100h, indirect 200h
spowoduje fizyczne umieszcznie sekcji w pami˛eci programu ROM pocz ˛
awszy od
adresu
100h
, przy czym etykiety definiowane w tej sekcji uzyskuj ˛
a warto ´sci, jak
gdyby sekcja była lokowana od adresu
200h
. Po inicjacji program u˙zytkowy w pierw-
szej fazie działania przemieszcza sekcje z pami˛eci ROM do pami˛eci RAM pod adres
200h
i dysponuj ˛
ac warto´sciami adresów wła´sciwymi dla tego obszaru mo˙ze od tego
momentu u˙zywa´c przemieszczonej sekcji.
STACKED
Argument
STACKED
powoduje lokoawnie sekcji tu˙z nad sekcj ˛
a poprzedni ˛
a. Nazywa
si˛e to sklejaniem sekcji. Sekcja poprzednia musi by ´c zdefiniowana jako bezpo´sred-
nia. Np. zdefiniowanie sekcji w sposób jak ni˙zej:
sekcja1:
.section offset 100h
;sekcja bezpo´
srednia
a nast˛epnie:
sekcja2:
.section stacked
powoduje, ˙ze
sekcja2
jest lokowana tu˙z nad
sekcja1
.
17
1
Programowanie w j˛ezyku asembler
AUTO_STACK
W praktyce cz˛esto jest stosowana technika polegaj ˛
aca na sklejaniu sekcji z frag-
mentów umieszczonych w ró˙znych plikach (modułach). Sklejanie takich fragmen-
tów umo˙zliwia argument
AUTO_STACK
. Nazwy sklejanych fragmentów definiowa-
nych równie˙z jako sekcje musz ˛
a by´c we wszystkich plikach jednakowe.
REF_ONLY
Wskazanie sekcji referencyjnej nast˛epuje za pomoc ˛
a argumentu
REF_ONLY
. U˙zycie
dyrektywy:
sekcja1:
.
section offset 100h, ref_only
spowoduje jedynie takie wyznaczenie adresów i nazw zwi ˛
azanych z
sekcja1
ja-
kie s ˛
a wła´sciwe w przypadku umieszczenia jej z przesuni˛eciem
100h
. Jednak bez
fizycznego umieszczania sekcji w tym obszarze.
RANGE
Ka˙zdej sekcji mo˙zna przypisa´c obszar umieszczenia za pomoc ˛
a parametrów:
RANGE adres1 adres2
COMMON
Sekcje o tej samej nazwie w ró˙znych plikach mog ˛
a by´c nakładane na siebie przy
u˙zyciu arguemntu
COMMON
. Jednak w trakcie deklaracji sekcji tego rodzaju w pierw-
szym pliku nie mo˙zna u˙zy´c argumentu
COMMON
. Sekcja w pozostałych plikach mu-
sz ˛
a by´c natomiast deklarowane z tym argumentem oraz musz ˛
a by´c typu referencyj-
nego, gdy˙z inaczej w pliku wynikowym pojawiłoby si˛e wiele rekordów z kodem
odnosz ˛
acym si˛e do tego obszaru adresowego.
1.5.4
Konsolidacja programu o strukturze sekcyjnej
Wskazywanie miejsca, gdzie wstawi´c sekcj˛e realizowane z poziomu asemblera ma ograni-
czone zastosowanie. Nie wszystkie działania mog ˛
a by ´c wykonane (np. te z doł ˛
aczaniem modu-
łów bibliotecznych), a ponadto ich elastyczno´s´c jest znacznie mniejsza od działa ´n realizowanych
przez konsolidator. A tak˙ze ka˙zda zmiana sposobu i miejsca lokowania sekcji zmusza do zmiany
programu ´zródłowego, który tym samym musi by ´c znów tłumaczony. Wła´snie dlatego zalecane
jest, aby wszystkich manipulacji na sekcjach dokonywa ´c z poziomu konsolidatora (w trakcie
konsolidacji). Cz˛esto konsolidatory wyposa˙zone s ˛
a w ´srodki przeznaczone do tego celu.
Konsolidator pakietu 2500AD dysponuje specjalnym j˛ezykiem przeznaczonym do przekazy-
wania polece ´n konsolidacji w postaci pliku wsadowego. Nazwy polece ´n stanowi ˛
a słowa angiel-
skie dobrane tak, ˙ze ich zestawienia stanowi ˛
a pełny komentarz do działa ´n zleconych konsoli-
datorowi. Zatem analiza pliku wsadowego steruj ˛
acego procesem konsolidacji w takim trybie,
nazywanym rozszerzonym (ang. enhanced) pozwala na uzyskanie pełnego obrazu konsolidacji.
Zmiany tego procesu wymagaj ˛
a tylko poprawek w pliku wsadowym, co realizuje si˛e za pomoc ˛
a
prostego edytora tekstu.
Przykład 1:
Załó˙zmy, ˙ze konsolidowany jest pojedynczy plik ´zródłowy stanowi ˛
acy jedn ˛
a sek-
cj˛e. Zawiera dyrektyw˛e
ORIGIN
wskazuj ˛
ac ˛
a adres pocz ˛
atku programu. Plik wsadowy steruj ˛
acy
konsolidacj ˛
a program w trybie rozszerzonym ma posta ´c:
version v0.1.1
option: executable
18
1.5
Lokowanie sekcji w pami˛eci
input: nazwa_pliku_wej´
sciowego
output: nazwa_pliku_wyj´
sciowego
locate: CODE at 0h
Poszczególne linie w tym przykładzie zawieraj ˛
a polecenia konsolidacji, przy czym
‘:
’ stanowi
separator oddzielaj ˛
acy nazw˛e polecenia od jego argumentu. Znaczenie poszczególnych linii:
1. Słowo kluczowe
version
wskazuje, ˙ze dany plik zawiera polecenia w trybie rozszerzo-
nym. Jest to niezb˛edne, bo stosowany jest tak˙ze standardowy tryb wsadowy, w którym
polecenia maj ˛
a inn ˛
a posta´c.
2. Słowo
option
wskazuje rodzaj pliku wyj´sciowego:
executable
– plik z kodem binarnym,
intel hex
– plik z kodem w standardzie HEX Intela,
high level
– nakazuje utworzenie dodatkowego pliku wyj´sciowego z danymi nie-
zb˛ednymi w trakcie uruchamiania programu przy u˙zyciu symulatora,
load map
.
3. Argumentem polecenia
input
jest nazwa pliku wej´sciowego poddawanego konsolidacji.
4. Polecenie
output
zawiera nazw˛e pliku wyj´sciowego, którego rodzaj okre´slaj ˛
a argumenty
polecenia
option
5. Polecenie
locate
wskazuje adres umieszczenia poszczególnych sekcji. Interpretowane
jest jako dodatkowe przesuni˛ecie w stosunku do adresu pocz ˛
atku programu okre ´slonego
dyrektyw ˛
a
ORIGIN.
Przykład 2:
Dla zało˙ze ´n jak w poprzednim przykładzie nale˙zy zbudowa ´c plik wsadowy taki,
aby mo˙zna było przył ˛
aczy´c moduły biblioteczne, a plik wyj´sciowy był w standardzie
intel
hex
, a zarazem aby został utworzony plik uruchomieniowy za pomoc ˛
a symulatora. Plik konso-
lidacji ma wówczas posta´c:
version
option: loca map, intel hex
input: nazwa_pliku_wej´
sciowego
output: nazwa_pliku_wyj´
sciowego
library: nazwa_pliku bibliotecznego
locate: CODE at 0h
19
1
Programowanie w j˛ezyku asembler
20
2 Programowanie w C
µ
K rodziny Intel 8051
2.1
Proces uzyskiwania programu wynikowego dla programów w C
Pliki doła˛czene przez
uz˙ytkownika
w C
Plik z´ródłowy
Standardowe pliki nagłówkowe doła˛czane
na poziomie je˛zyka C (*.h)
Pliki doła˛czene przez
uz˙ytkownika
uz˙ytkownika
biblioteczne
Programy
Standardowe
programy
biblioteczne
Kompilator
asemblerowy
Plik z´ródłowy
programu rozruch.
Asembler
s´rodowisko (*.def)
Pliki definiuja˛ce
Pliki
relokowalne
rozruchowy
Konsolidator
Plik
Program
Bibliotekarz
Raport z kompilacji
(*.lst)
Pliki z kodem wynikowym
(*.hex, *.exe, *.sym, *.def)
programu (*.map)
Plik z mapa˛ pamie˛ci
Rysunek 2.1: Proces uzyskiwania programu wynikowego dla programów w C
Doprowadzenie programu napisanego w C do realizacji przez mikrokontroler (lub jego sy-
mulator) jest procesem wieloetapowym. Mo˙zna wyró˙zni ´c w nim conajmniej pi˛e´c niezb˛ednych
kroków:
napisanie w j˛ezyku asembler programu rozruchowego,
przetłumaczenie programu rozruchowego,
21
2
Programowanie w C µK rodziny Intel 8051
kompilacja programu w C do postaci asemblerowej, a nast˛epnie przetłumaczenie go do
postaci relokowalnej,
wskazanie standardowych plików bibliotecznych doł ˛
aczanych w trakcie konsolidacji,
konsolidacja programu rozruchowego, programu w C oraz programów bibliotecznych
w wymienionej kolejno´sci.
Programy w j˛ezyku C wymagaj ˛
a przygotowania ´srodowiska, w którym s ˛
a realizowane. Polega
to ogólnie na zarezerwowaniu miejsca w pami˛eci dla okre´slonego rodzaju danych, zainicjowa-
nia układów wej´scia-wyj´scia do komunikacji z otoczeniem, przygotowania stosu a nast˛epnie na
oddaniu sterowania do programu w C, który standardowo rozpoczyna si˛e od funkcji
main()
.
Powy˙zsze działania realizuje program rozruchowy (ang. runtime start up program), który jest
napisany w j˛ezyku asembler. Jest on zwykle dostarczany przez producenta kompilatora, mo˙ze
by´c równie˙z zbudowany przez u˙zytkownika. Jest on dostosowywany do ró˙znych typów mi-
krokontrolerów rodziny 8051 za pomoc ˛
a plików definiuj ˛
acych struktur˛e rejestrów. Maj ˛
a one
rozszerzenie
*.def
i doł ˛
aczane s ˛
a za pomoc ˛
a dyrektywy
include
. U˙zytkownik mo˙ze modyfi-
kowa´c te pliki, mo˙ze równie˙z tworzy´c własne pliki definicyjne.
Programy w C równie˙z wymagaj ˛
a doł ˛
aczenia plików definicyjnych, które maj ˛
a jednak nieco
inny charakter. S ˛
a to tzw. pliki nagłówkowe
1
słu˙z ˛
ace do tworzenia prototypów funkcji biblio-
tecznych. Ich brak uniemo˙zliwia działanie tych funkcji. U˙zytkownik mo˙ze doł ˛
acza ´c równie˙z
własne pliki nagłówkowe.
Tłumaczenie programu w C odbywa si˛e dwuetapowo. Najpierw program w C tłumaczony
jest na program w asemblerze, a nast˛epnie program asemblerowy tłumaczony jest do postaci
relokowalnej. U˙zywaj ˛
ac odpowiedniego przeł ˛
acznika kompilatora powy˙zsze etapy mo˙zna zre-
alizowa´c jako jedn ˛
a cało´s´c.
Postacie relokowalne programu w C i programu rozruchowego s ˛
a poddane nast˛epnie kon-
solidacji ł ˛
acznie z programami bibliotecznymi. Tego rodzaju programy s ˛
a dostarczane przez
producenta. Mo˙zna równie˙z tworzy´c własne programy biblioteczne. U˙zytkownik mo˙ze doł ˛
a-
cza´c własne programy relokowalne do standardowej biblioteki za pomoc ˛
a programu o nazwie
librarian
2
. Wynikiem konsolidacji jest plik wykonywalny
*.exe
lub cz˛e´sciej jego posta´c he-
xadecymalna
*.hex
. Mo˙zna równie˙z uzyska´c pliki
*.sym
i
*.def
niezb˛edne gdy u˙zywa si˛e
symulatora. Ponadto programista mo˙ze za˙zyczy ´c sobie utworzenia raportu z kompilacji
*.lst
oraz pliku z map ˛
a programu
*.map
zawieraj ˛
acego dane na temat obszarów pami˛eci zajmowa-
nych przez sekcje oraz warto´sci nazw globalnych.
2.2
Program rozruchowy
2.2.1
Rodzaje programu rozruchowego
Program ten napisany jest w asemblerze i spełnia nast˛epuj ˛
ace zadania:
przygotowanie stosu i wywołanie pocz ˛
atkowej funkcji C (
main()
),
1
ang. header files
2
bibliotekarz
22
2.2
Program rozruchowy
zapewnienie komunikacji mi˛edzy fizycznym urz ˛
adzeniem wej´scia-wyj´scia (lub systemem
operacyjnym) a programem w C,
zarezerwowanie obszarów na dane,
przeniesienie danych z pami˛eci programu do pami˛eci danych.
Pakiet 2500AD dostarcza trzy rodzaje programów rozruchowych:
przeznaczonych do zastosowanie w sytuacji gdy do przechowywania danych u˙zywa si˛e
wył ˛
acznie wewn˛etrznej pami˛eci RAM. Jest to tzw. tryb wewn˛etrzny kompilatora (ang.
internal memory mode). Program rozruchowy nosi nazw˛e
c8051ir.src
. W przypadku
gdy u˙zywa si˛e symulatora nale˙zy zastosowa ´c wersj˛e
c851sir.src
.
przeznaczonych do u˙zytku wył ˛
acznie z zewn˛etrzn ˛
a pami˛eci ˛
a RAM jako miejsca przecho-
wywania danych programu w C, co nazywane jest trybem zewn˛etrznym (ang. external
memory mode). Stosowane s ˛
a wtedy odpowiednio programy rozruchowe:
c8051er.src
i
c8051ser.src
.
przeznaczonych do ł ˛
acznego wykorzystania obu rodzajów pami˛eci RAM. Jest to tzw. tryb
mieszany (ang. mixed memory mode):
c8051mr.src
i
c8051smr.src
.
Podj˛ecie decyzji co do rodzaju pami˛eci RAM, a wi˛ec i trybu kompilacji programu, wi ˛
a˙ze si˛e nie
tylko z wyborem rodzaju programu rozruchowego, ale równie˙z mi˛edzy innymi z wykorzysta-
niem odpowiednich programów bibliotecznych, sposobem definiowania zmiennych globalnych
itd. . . .
2.2.2
Definiowanie rodzaju mikrokontrolera
Rodzina 8051 obejmuje kilkadziesi ˛
at typów mikrokontrolerów. Program jest natomiast pi-
sany dla konkretnego typu, co oznacza, ˙ze u˙zywa on nazw rejestrów specjalnych odpowiednich
dla danego typu. Nazwy te s ˛
a u˙zywane zarówno na poziomie asemblera jak i j˛ezyka C. Nazwy
rejestrów specjalnych u˙zywane na tych poziomach s ˛
a ró˙zne. Oznacza to konieczno ´s´c realizacji
nast˛epuj ˛
acych działa ´n:
Na pocz ˛
atku programu rozruchowego nale˙zy u˙zy ´c dyrektywy
.CHIP
z argumentem okre-
´slaj ˛
acym typ mikrokontrolera (np.
.chip 8052
). Powoduje to doł ˛
aczenie do słownika
nazw asemblera całej grupy nazw rejestrów specjalnych i nazw bitów specyficznych dla
wskazanego typu mikrokontrolera. Od tego momentu nazwom tym zostaj ˛
a przypisane
warto´sci odpowiadaj ˛
ace adresom rejestrów i bitów, które nie mog ˛
a by ´c redefiniowane.
Umo˙zliwia to wskazanie tych nazw przez programist˛e bez konieczno ´sci odwoływanie si˛e
do adresów zwi ˛
azanych z tymi nazwami.
Na pocz ˛
atku sekcji
program
programu rozruchowego nale˙zy doł ˛
aczy ´c plik
c????sr.def
zawieraj ˛
acy globalne definicje nazw rejestrów specjalnych.
23
2
Programowanie w C µK rodziny Intel 8051
Tak zdefiniowane nazwy poprzedzone doln ˛
a kresk ˛
a
3
(
_
) mog ˛
a by´c u˙zywane we wszystkich mo-
dułach pod warunkiem zdefiniowania ich jako zewn˛etrzne dla tych modułów. Dla programu
w C realizowane jest to za pomoc ˛
a makropolecenia doł ˛
aczaj ˛
acego plik nagłówkowy:
#include "c8052sr.h"
Zawarto ´s ´c plików definicyjnych
Plik
c8052sr.def
ma posta´c:
***********************************************************
* 8052 C compiler special functions registers definitions *
***********************************************************
spec_func_regs: .section reg,offset 0,ref_only
.globals on
_P0;
.reg 80h
_PCON:
.reg 77h
.
.
.
_SFB:
.reg 80h
.globals off
.ends
Plik nagłówkowy programu w C o nazwie
c8052sr.h
ma posta ´c:
/************************************************************/
/* 8052 C compiler special functions registers declarations */
/************************************************************/
.asm
.chip 8052
.endasm
extern near char P0; /* port 0 */
.
.
.
extern near char PCON; /* power control */
.
.
.
extern near char IE; /* interrupt enable control */
/*******************************************************/
/* 8052 C compiler special functions bits declarations */
/*******************************************************/
near struct special_finction bits
{
/* Bit name
Bit value */
3
normalnie nazywn ˛
a podkre´sleniem
24
2.2
Program rozruchowy
/* P0 (Port 0) */
unsigned int P0_0:1 ; /* port 0, bit 0
80h*/
.
.
.
unsigned int P0_0:1;
/* port 0, bit 7
87h*/
/* TCON (Timer Control) */
unsigned int IT0:1; /*input INT0/transition activated 88h */
.
.
.
}
Doł ˛
aczenie tego pliku nagłówkowego umo˙zliwia w programach w C u˙zywanie nazw zdefinio-
wanych rejestrów i bitów jako zmiennych. Ilustruj ˛
a to przykłady:
#include “c8052sr.h”
near char c1;
main()
{
char c2;
c1=P0;
c2=P1;
P2=c2;
.local c2
.asm
mov .low. _c1,p0
mov _c2,p1
.endasm
}
Powy˙zszy program po kompilacji b˛edzie wygl ˛
adał tak:
;.asm
.chip 8052
;.endams
;char c1;
.internal_uninit_data
_c1: .ds 1
;
.program
_main: .equal $
;
?ASC0: .equal 0
?TSC0: .equal 0
?LSC0: .equal 1
inc sp
;c1=P0
mov a,.low. _P0
mov .low. _c1, a
25
2
Programowanie w C µK rodziny Intel 8051
;c1=P1
mov a,.low. _P1
xch a,r0
mov a,sp
add a,#0-?LSC0-1
xch a,r0
mov @r0,a
;P2=c2
mov .low. _P2,a
;local c2
c2: .var+0-?LSC0+1
;asm
mov .low. _c1,p0
mov _c2,p1
;endasm
Komunikacje z bitami rejestrów specjalnych w programie w C. Program ten deklaruje rejestry
adresowane bitowo jako struktur˛e bitow ˛
a. Program w C:
#include “c8052sr.h”
extern struct special_functions_bits _SFB;
char c1;
main()
{
_SFB.EA=1;
}
po kompilacji:
;_SFB.EA=1
setb .low. __SFB+47
;
2.2.3
Deklaracja rejestrów roboczych
Kompilator C wykorzystuje wszystkie rejestry robocze r0 . . . r7 mikrokontrolera, niezb˛edne
jest wi˛ec ich zdefiniowanie w programie rozruchowym w sposób wła´sciwy dla kompilatora.
Najlepiej zrobi´c to w postaci sekcji rejestrowej. Jej parametry mo˙zna zadeklarowa ´c na poziomie
asemblera, bo nie ulegaj ˛
a one zmianie w trakcie konsolidacji. Realizowane to jest nast˛epuj ˛
aco:
registers:
.section reg, offset 0, ref_only
.global __reg0
.global __reg1
.
.
.
.global __reg7
26
2.2
Program rozruchowy
__reg0:
.ds 1
.
.
.
__reg7:
.ds 1
__oper1_lsb: .equal __reg0
__oper1_msb: .equal __reg2 ;adres operandu 1
.
.
.
__stack_msb: .equal __reg7
2.2.4
Przesuwanie danych
Kompilator u˙zywa czterech rodzajów sekcji wraz z trzema odpowiadaj ˛
acymi im sekcjami
bibliotecznymi. Sekcje te nosz ˛
a ró˙zne nazwy dla trybu wewn˛etrznego i zewn˛etrznego kompila-
tora.
Rodzaj sekcji
Sekcje biblioteczna
Tryb zewn˛etrzny
program
lib_program
const_data
lib_const_data
init_data
lib_init_data
uninit_data
-
Tryb wewn˛etrzny
program
lib_program
internal_const_data
lib_internal_const_data
internal_init_data
lib_internal_init_data
internal_uninit_data
-
Pierwszy rodzaj sekcji zawiera programy u˙zytkownika i programy biblioteczne. Pozostałe
trzy rodzaje sekcji u˙zywane przez kompilator słu˙z ˛
a do lokowanie danych podzielonych na 3 klasy:
dane nieinicjowane, dla których w wyniku deklaracji typu musi by ´c zarezerwowane miej-
sce w pami˛eci, jednak w rezerwowany obszar nie s ˛
a wpisywane ˙zadne warto ´sci
dane inicjowane, którym prócz zadeklarowania typu przypisywana jest warto ´s´c. Obydwa
powy˙zsze typy zwi ˛
azane s ˛
a z deklaracjami zmiennych.
trzeci typ danych zwi ˛
azany jest ze stałymi u˙zywanymi w programie. Stałe nie zmieniaj ˛
a
warto´sci przez cały czas działania programu. Okre´slony symbol mo˙zna zadeklarowa´c jako
stał ˛
a u˙zywaj ˛
ac do tego celu słowa kluczowego
const
.
Przykład:
char c1;
char c2=0;
const char c3=3;
main(){}
27
2
Programowanie w C µK rodziny Intel 8051
po kompilacji:
;char c1
.internal_uninit_data
_c1: ds 1
;char c2=0;
.internal_init_data
_c2: .byte 0
;const char c3=3;
.internal_const_data
_c3: .byte 3
Utworzenie w/w klas sekcji pozwala na umieszczenie modułów bibliotecznych w okre ´slonych
obszarach pami˛eci. S ˛
a one lokowane zgodnie z parametrami podanymi w pliku konsolidacji
(
*.lnk
). Program rozruchowy musi zdefiniowa´c wszystkie niezb˛edne sekcje, nawet je´sli s ˛
a
puste. Przyj˛ecie okre´slonego porz ˛
adku pozwala konsolidatorowi na wyznaczanie rozmiarów
sekcji, co jest niezb˛edne do przemieszczania odpowiednich sekcji przez program rozruchowy
oraz ewentualne zerowanie odpowiednich sekcji.
W funkcjach j˛ezyka C mog ˛
a wyst˛epowa´c dane tymczasowe, które spełniaj ˛
a wewn ˛
atrz funk-
cji zadania pomocnicze. Moduły biblioteczne przechowuj ˛
a ich warto ´sci na stosie. Lokalizacja
ka˙zdej zmiennej wskazywana jest jako przesuni˛ecie w stosunku do zawarto ´sci wska´znika chwi-
lowych zmiennych bibliotecznych:
__ilib_temp_ptr
(dla trybu wewn˛etrznego). Wyznaczanie
lokalizacji dokonywane jest w trakcie kompilacji i wymaga zdefiniowania odpowiednich sek-
cji. Te sekcje nie mog ˛
a by przemieszczane wi˛ec ich parametry s ˛
a definiowane na poziomie
asemblera.
2.2.5
Przygotowanie stosu
Stos wewn˛etrzny umieszczany jest ponad obszarem wewn˛etrznych danych nieinicjowanych.
Niezb˛ednym elementem zwi ˛
azanym z tym obszarem jest wska´znik
__ilib_temp_ptr
słu˙z ˛
acy
do poruszania si˛e po zarezerwowanym obszarze pami˛eci, który programy biblioteczne u˙zywaj ˛
a
do przechowywania wyników. Mo˙zliwe jest wielokrotne wywoływanie podprogramów biblio-
tecznych realizowane w trzech krokach:
1. Lokalizacja kolejnego bloku danych w obszarze stosu o rozmiarze
__lib_temp_constants_size
.
2. Przechowanie warto´sci bie˙z ˛
acego wska´znika w
__ilib_temp_ptr
.
3. Wprowadzenie nowej warto´sci wska´znika i wywołanie programu bibliotecznego.
2.2.6
Wywołanie programu w C
Wywołanie programu w C z poziomu programu rozruchowego realizowane jest rozkazem
LCALL_MAIN
. Mo˙zna te˙z stosowa´c rozkaz skoku gdy nie przewiduje si˛e powrotu po zrealizo-
waniu programu w C. Gdy taki powrót ma miejsce (np. gdy wywołanie nast ˛
apiło z programu
28
2.3
Organizacja danych w C
internal_init_data
internal_lib_init_data
__ilib_temp_ptr
internal_uninit_data
internal_lib_temp_constants
Bank 3
Bank 2
Bank 1
Bank 0
Bity stanu
30h
7Fh
00h
Rysunek 2.2: Struktura wewn˛etrznej pami˛eci RAM po zainicjowaniu stosu
monitora lub systemu operacyjnego) nale˙zy zapewni ´c przywrócenie warto´sci wska´znika stosu
jaka była przed wywołaniem programu w C.
2.3
Organizacja danych w C
2.3.1
Typy danych i ich modyfikatory
Kompilator 2500AD operuje na nast˛epuj ˛
acych typach danych:
Nazwa
Typ
Rozmiar
znakowy
char
8 bitów
całkowity
int
16 bitów
całkowity krótki
short
8 bitów
całkowity długi
long
32 bity
zmiennoprzecinkowy
float
32 bity (IEEE)
zmiennoprzecinkowy podwójnej precyzji
double
64 bity (IEEE)
Stosowane s ˛
a nast˛epuj ˛
ace kwalifikatory:
Kwalifikator
Stosowany do typu
unsigned
char, int, long
const
do wszystkich wł ˛
aczaj ˛
ac struktury
volatile
do wszystkich wł ˛
aczaj ˛
ac struktury
Znaczenie kwalifikatorów:
unsigned
liczba całkowita nieujemna. W stosunku do takich liczb obowi ˛
azuj ˛
a reguły arytme-
29
2
Programowanie w C µK rodziny Intel 8051
tyki binarnej.
const
słu˙zy do wskazywania stałych, które nie podlegaj ˛
a zmianom w czasie realizacji
całego programu. Kompilator generuje kod pozwalaj ˛
acy na przekazywanie tych
danych do procesora. Zmienne wska´znikowe o warto´sciach b˛ed ˛
acych adresami do
tych stałych maj ˛
a długo´s´c 16 bitów.
volatile
wskazuje, ˙ze okre´slone dane musz ˛
a by´c ponownie ładowane przy ka˙zdym ich u˙zy-
ciu poniewa˙z s ˛
a modyfikowane w trakcie realizacji programu. Tego typu kwalifika-
tor jest u˙zyteczny przy obsłudze układów I/O adresowanych jednolicie z pami˛eci ˛
a.
Uwaga:
Standard j˛ezyka C wymaga oby argumenty operacji 2-argumentowej typy char były
najpierw przetworzone na posta´c int. Opisywany kompilator nie przestrzega tego wychodz ˛
ac
z zało˙zenia, ˙ze mikrokontorlery rodziny 8051 znacznie cz˛e´sciej wykonuj ˛
a operacje na liczbach
8-bitowych typu char ni˙z na 16bitowych typu int. Dlatego trzeba kontrolowa ´c efekty stosowa-
nych operacji. Ilustruje to przykład:
char c1,c2;
int i;
i=c1<<8; /* przesu´
n w lewo 8 pozycji */
Rezultat tej operacji wynosi 0 poniewa˙z wszystkie bity zostały przesuni˛ete przed przechowa-
niem wyniku w postaci zmiennej
i
. Aby uzyska ´c poprawny wynik przed przesuni˛eciem nale˙zy
dokona´c konwersji zmiennej
c1
na typ int:
i=(int)c1<<8;
2.3.2
Organizacja ramki stosu
Ka˙zdej funkcji kompilowanej w trybie wewn˛etrznym przydzielany jest fragment pami˛eci
zorganizowany w stos nazywany ramk ˛
a (rys. 2.3). Składa si˛e ona z trzech obszarów:
1. pami˛eci argumentów funkcji,
2. pami˛eci danych tymczasowych,
3. pami˛eci zmiennych lokalnych.
Kompilator dla ka˙zdej funkcji generuje trzy stałe procesu kompilacji, które stanowi ˛
a rozmiary
danych w ramce stosu:
?LSC
rozmiar danych lokalnych
?TSC
rozmiar danych tymczasowych
?ASC
rozmiar argumentów przekazywanych bezpo´srednio na stos
30
2.3
Organizacja danych w C
Dane tymczasowe
Argumenty
Argumenty
Zmienne lokalne
SP po wywołaniu
funkcji
SP przed wywołaniem
funkcji
?ASC - rozmiar obszaru argumentow przekazy-
wanych bezpos´rednio przez stos
SP-?LSC
SP-?LSC+1-TSC
Argumenty przekazywane przez rejestry
?TSC - rozmiar danych tymczasowych
?LSC - rozmiar zmiennych lokalnych
Adres powrotu z funkcji (2 bajty)
Rysunek 2.3: Ramka stosu
Rozmiary te maj ˛
a warto´sci równe liczbie bajtów zarezerwowanych w ramce na dany rodzaj wiel-
ko´sci. Słu˙z ˛
a one do okre´slania wzgl˛ednych adresów bazowych obszarów ramki, które z kolei
stanowi ˛
a podstaw˛e wyznaczania poło˙zenia danych w ramce. Okre´slone s ˛
a nast˛epuj ˛
ace adresy
bazowe:
adres wzgl˛edny pocz ˛
atku obszaru zmiennych lokalnych (
-?LSC+1
) wskazuj ˛
acy poło˙zenie
najstarszego bajtu pierwszej zmiennej lokalnej wzgl˛edem aktualnej zawarto ´sci wska´znika
stosu
adres wzgl˛edny pocz ˛
atku obszaru danych tymczasowych (
-?LSC
)
adres wzgl˛edny ko ´nca obszaru danych tymczasowych (
-?LSC-?TSC
), który słu˙zy jako
adres bazowy obszaru argumentów funkcji
Powy˙zsze adresy bazowe umo˙zliwiaj ˛
a lokalizacj˛e danych w ramce na podstawie ich adresów
wzgl˛ednych b˛ed ˛
acych liczbami wskazuj ˛
acymi odległo´s´c w bajtach najstarszego bajtu danych
od adresu bazowego.
2.3.3
Przekazywanie argumentów do funkcji
Tłumacz ˛
ac funkcj˛e j˛ezyka C kompilator standardowo lokuje ich argumenty typu char i int
w rejestrach roboczych. W momencie gdy kompilator przetłumaczy wywołanie funkcji rozpo-
czyna poszukiwanie miejsca dla przechowania pierwszego argumentu. Je ´sli jest on typu char/int
i jest miejsce w rejestrach to jest on tam umieszczany. W przeciwnym przypadku argument jest
lokowany na stosie. Czynno´s´c ta powtarzana jest do wyczerpania listy argumentów. Kompilator
31
2
Programowanie w C µK rodziny Intel 8051
u˙zywa rejestrów A, R1, R2, R3
4
do przechowywania argumentów typu char, oraz par R2+R0,
R3+R1 dla typu int. Przykłady:
funkcja1(char arg1, char arg2)
– pierwszy argument umieszczony jest w A, drugi w R2
funkcja2(char arg1, int arg2)
– pierwszy argument w A, drugi w R3+R1
funkcja3(int arg1, char arg2)
– pierwszy argument w parze R2+R0, drugi w R1
funkcja4(int arg1, int arg2)
– pierwszy w R2+R0, drugi R3+R1
Po przej´sciu do realizacji funkcji w pierwszym kroku wysyłane s ˛
a na stos argumenty przekazy-
wane w rejestrach. Po ich wysłaniu obszar ramki stosu przeznaczony na argumenty zawiera je
w kolejno´sci odwrotnej do kolejno´sci ich deklaracji. Pokazano to na rys. 2.4 dla przykładowej
funkcji:
f_przykl_1 (char, int, float)
Pamie˛c´ danych
tymczasowych
char
int
int
float
float
float
float
bity 0..7
bity 0..7
bity 8..15
bity 0..7
bity 8..15
bity 16..23
bity 24..31
Ostatni argument
Pierwszy argument
Rysunek 2.4: Kolejno´s´c argumentów funkcji w ramce stosu
Przekazanie argumentów na stos odbywa si˛e dwuetapowo:
1. Przed wywołaniem funkcji – pocz ˛
atkowe argumenty s ˛
a ładowane do rejestrów roboczych,
reszta na stos.
2. Po wywołaniu funkcji – argumenty z rejestrów przenoszone s ˛
a na stos.
Mi˛edzy tymi działaniami ma miejsce operacja zwi ˛
azana z wywołaniem podprogramu realizuj ˛
a-
cego dan ˛
a funkcj˛e. Dlatego obszar stosu wewn˛etrznego przeznaczonego na argumenty zostaje
przedzielony na dwie cz˛e´sci dwubajtowym adresem powrotu z podprogramu.
4
W tej kolejco´sci.
32
2.3
Organizacja danych w C
Przykład:
main()
{
f_przykl_2(1,2,3);
}
f_przykl_2(int x, int y, int z)
{
int a,b,s;
a=4;
b=5;
s=0;
s=s+z;
s=s+y;
return(s);
}
Odwołanie si˛e do funkcji
f_przykl_2
wymaga przekazania do niej trzech argumentów. Argu-
menty pierwszy i drugi lokowane s ˛
a w parach rejestrów R2 i R0 oraz R3 i R1, trzeci argument
lokowany jest na stosie. Po kompilacji odpowiednie instrukcje asemblera maj ˛
a posta ´c:
;f_przykl_2(1,2,3)
mov
r0,#.low. 3
mov
r2,#.high. 3
push
_oper1_msb
push
_oper2_lsb
mov
r1,#.low. 2
mov
r3,#.high. 2
mov
r0,#.low. 1
mov
r0,#.high. 1
lcall _f_przykl_2
dec
sp
dec
sp
?BOF0:
.equal $
ret
_f_przykl_2: .equal $
push
_oper2_msb
push
_oper2_lsb
push
_oper1_msb
push
_oper1_lsb
Po wywołaniu podprogramu funkcji argumenty z rejestrów przenoszone s ˛
a na stos. Po zako ´n-
czeniu tej operacji ramka stosu ma posta´c przedstawian ˛
a na rys. 2.5.
2.3.4
Rozmieszczenie zmiennych lokalnych w ramce stosu
Zmienne lokalne umieszczane s ˛
a na stosie w kolejno´sci ich definiowania zaczynaj ˛
ac od naj-
starszego bajtu. Dla funkcji z przykładu ze strony 33 map˛e pami˛eci zmiennych lokalnych przed-
stawia rysunek 2.6.
33
2
Programowanie w C µK rodziny Intel 8051
.low. 1
.low. 2
tymczasowych
Pamie˛c´ danych
Zmienne lokalne
.high. 1
.high. 2
adres
powrotu
.low. 3
.high. 3
Rysunek 2.5: Ramka stosu dla przykładu ze strony 33
.low. 0
Pamie˛c´ danych
tymczasowych
.high. 4
.high. 5
.low. 4
.low. 5
.high. 0
Rysunek 2.6: Mapa pami˛eci zmiennych lokalnych
34
2.3
Organizacja danych w C
Rozmieszczenie zmiennych lokalnych musi by ´c poprzedzone zarezerwowaniem obszaru
stosu na dane tymczasowe i zmienne lokale. Odpowiedni fragment programu po kompilacji
ma posta´c:
?ASC1: .equal 2
?TSC1: .equal 0
?LSC1: .equal 6
mov a,sp
add a,#?TSC1+?LSC1
mov sp,a
;po tej operacji wska´
znik stosu wskazuje koniec ramki stosu
Mechanizm lokowanie zmiennych ilustruje poni˙zszy kod:
;a=4
mov a,sp
add a#0-?LSC1+1
mov r0,a
mov @r0,#.high. 4
inc r0
mov @r0,#.low. 4
;b=5
mov a,sp
add a,#2-?LSC1+1
mov r0,a
.
.
.
;s=0
.
.
.
Po zako ´nczeniu lokowania zmiennych lokalnych ramka stosu dla przykładu ze strony 33 przed-
stawion ˛
a na rysunku 2.7. W tej formie jest ona wykorzystywana przez cały czas realizacji pod-
programu funkcji.
Obszar zmiennych tymczasowych jest wykorzystywany w taki sam sposób jak obszar zmien-
nych lokalnych w miar˛e pojawiania si˛e danych wykorzystywanych chwilowo dla celów przecho-
wania wyników po´srednich.
Powrót z podprogramu funkcji wymaga ustawienia wska´znika stosu SP. Realizuj ˛
a to instruk-
cje:
;return(s)
?BOF1: .equal $
mov a,sp
add a,#-?LSC1-?TSC1-4
mov sp,a
ret
35
2
Programowanie w C µK rodziny Intel 8051
.low. 0
Pamie˛c´ danych
tymczasowych
.high. 4
.high. 5
.low. 4
.low. 5
.high. 0
.low. 1
.high. 1
.low. 2
.high. 2
adres
powrotu
.low. 3
.high. 3
Rysunek 2.7: Mapa ramki stosu funkcji z przykłady ze strony 33
2.3.5
Przechowywanie warto ´sci zwracanych przez funkcj ˛e
Zmienna zwracana przez funkcj˛e okre´slona jest jako argument instrukcji
return
. Typ zwra-
canej warto´sci musi by´c wskazany przez podanie typu funkcji przed jej nazw ˛
a. Pomini˛ecie tej
deklaracji oznacza funkcj˛e etapu int (czyli zwracaj ˛
ac ˛
a warto´s´c całkowit ˛
a). Sposób zwracania
warto´sci funkcji okre´sla tablica:
Typ zwracanej warto´sci
Zwracana w:
wszystkie funkcje:
char
A
int
R2,R0
funkcje zewn˛etrzne (korzystaj ˛
ace z zewn˛etrznej pami˛eci RAM):
long, float, double
lokacja w pami˛eci tymczasowej:
__FUNCTION_RET_ADDR
wska´znik do lokacji w R2 i R0
funkcje wewn˛etrzne:
long, float, double
lokacja w pami˛eci tymczasowej:
__IFUNCTION_RET_ADDR
wska´znik do lokacji w A
Sposób zwracania warto´sci przez funkcj˛e z przykładu ze strony 33 pokazuje fragment pro-
gramu:
mov a,sp
mov a,#4-?LSC1+1
mov r1,a
mov @r1,__oper1_msb
inc r1
mov @r1,__oper1_lsb
36
2.4
Przekazywanie danych mi˛edzy funkcjami a instrukcjami asemblera
;return(s)
.
.
.
Modyfikacja funkcji z tego przykładu powoduje, ˙ze zwracana jest warto ´s´c 4-bajtowa. Program
w C ma wówczas posta´c:
main()
{
long f_przykl_3(1,2,3);
}
long f_przykl_3(int x, int y, int z)
{
int a,b;
long s;
a=4;
b=5;
s=(long)z;
return(s);
}
Po przetłumaczeniu funkcji return:
;return(s)
mov r1,a
mov a,__ilib_temp_ptr
add a,#-__IFUNCTION_RET_ADDR
lcall __istore_long
2.4
Przekazywanie danych mi ˛edzy funkcjami a instrukcjami
asemblera
2.4.1
Wprowadzanie instrukcji asemblera do programu w C
Współprac˛e fragmentów programów w C i w asemblerze umo˙zliwiaj ˛
a odpowiednie dyrek-
tywy kompilatora. Podstawow ˛
a konstrukcj ˛
a składniow ˛
a umo˙zliwiaj ˛
ac ˛
a wprowadzenie instrukcji
asemblera jest para dyrektyw:
.asm
.
;program w asemblerze
.
.endasm
Tekst mi˛edzy nimi jest przenoszony przez kompilator bezpo´srednio do tłumaczenia przez asem-
bler.
37
2
Programowanie w C µK rodziny Intel 8051
Uwaga:
Kompilator dzieli etykiety na lokalne i globalne:
nazwy lokalne generowane s ˛
a przez kompilator wewn ˛
atrz funkcji i s ˛
a wa˙zne tylko w ob-
r˛ebie danej funkcji,
nazwy globalne musz ˛
a by´c definiowane na zewn ˛
atrz funkcji.
Nazwy lokalne definiowane wewn ˛
atrz funkcji wyró˙zniane s ˛
a przez kompilator znakiem
?
na
pocz ˛
atku lub ko ´ncu nazwy. Poniewa˙z stosowana jest zasada, ˙ze u˙zycie nazwy globalnej ko ´nczy
blok nazw lokalnych we wstawkach asemblerowych nale˙zy u˙zywa ´c nazw z
‘?’
na pocz ˛
atku lub
na ko ´ncu.
2.4.2
Dost ˛ep do zmiennych lokalnych
Zmienne lokalne umieszczane s ˛
a na stosie wewn˛etrznym lub zewn˛etrznym w zale˙zno ´sci od
trybu pracy kompilatora. Kompilator lokalizuje je w sposób wzgl˛edny w odniesieniu do war-
to´sci wska´znika ramki. Dyrektywa
.local
powoduje wygenerowanie na poziomie asemblera
dyrektywy
.var
przyporz ˛
adkowuj ˛
acej zmiennej warto´s´c b˛ed ˛
acej przesuni˛eciem w stosunku do
aktualnej zawarto´sci wska´znika ramki. W trybie wewn˛etrznym rol˛e wska´znika ramki spełnia
SP. Poni˙zszy przykład ilustruje wykorzystanie dyrektywy
.local
do wskazywania z poziomu
asemblera zmiennej lokalnej przez nazw˛e:
main()
{
char c2;
int int2;
.local c2; /* tworzy przesuni˛
ecie w stosunku do zawarto´
sci SP */
.local int2;
/* teraz asembler mo˙
ze odwoływa´
c si˛
e do obu zmiennych przez nazw˛
e */
.asm
;wstawka asmeblerowa
mov a,sp
add a,#c2
mov r0,a
mov @r0,#0
;wyzeruj zmienn ˛
a c2
mov a,sp
add a,#int2
mov r0,a
mov @r0,#.high. 0
;wyzeruj zmienn ˛
a int2
inc r0
mov @r1,#.low. 0
.endasm
}
2.4.3
Dost ˛ep do argumentów funkcji j ˛ezyka C
Dost˛ep do argumentów funkcji j˛ezyka C z poziomu asemblera umo˙zliwia dyrektywa kom-
pilatora
.arg
. Działa ona tak samo jak dyrektywa
.local
z tym, ˙ze argumentem generowanej
38
2.4
Przekazywanie danych mi˛edzy funkcjami a instrukcjami asemblera
dyrektywy asemblera
.var
jest przesuni˛ecie wskazuj ˛
ace zmienn ˛
a w obszarze argumentów funk-
cji. Przykład:
main(char c1, int int1)
{
.arg c1;
.arg int1;
/* dalej ja w przykładzie powy˙
zej */
}
2.4.4
Adresowanie bezpo ´srednie i po ´srednie w programach w C
Adresowanie bezpo´srednie – za nazw ˛
a u˙zywan ˛
a w programie kryje si˛e adres, tzn. u˙zycie
danej nazwy powoduje odwołanie si˛e do komórki pami˛eci (lub rejestru) opatrzonej nazw ˛
a. Do-
tyczy to wszystkich nazw globalnych takich jak:
nazwy zmiennych globalnych
nazwy funkcji
nazwy rejestrów specjalnych (s ˛
a definiowane z zasady jako nazwy globalne)
a tak˙ze (z zało˙zenia) struktur zło˙zony takich jak:
tablice
unie
Przykład:
const char tab[]=”komunikat 1”;
main ()
{
extern const char tab[];
char c1;
c1=tab[0];
}
fragment odpowiedniego programu asemblerowego:
.internal_const_data
_tab:
.byte
”komunikat 1”
.program
_main:
.equal $
?ASC0:
.equal 0
?TSC0:
.equal 0
?LSC0:
.equal 1
39
2
Programowanie w C µK rodziny Intel 8051
;c1=tab[0]
mov
dptr,#_tab+0
clr
a
movc a,@a+dprt
xch
a,r0
mov
a,sp
add
a,#0-?LSC0+1
xch
a,r0
mov
@r0,a
?BOFO:
.equal $
dec
sp
ret
.global _tab
.global _main
.extern _tab
.end
U˙zywaj ˛
ac nazw operuje si˛e na zawarto´sciach komórek lub rejestrów traktowanych jako argu-
menty o danej nazwie. Mo˙zliwe jest te˙z uzyskanie adresu danej nazwy i odwołanie si˛e do
argumentu po´sredniego przez ten adres. Mo˙zliwe s ˛
a równie˙z stosowne operacje na adresach
jako zmiennych całkowitych. Przykład:
char c1=1;
main()
{
extern char c1;
int adr_main;
adr_main=&main;
c1++;
}
po kompilacji:
;char c1=1
.internal_init_data
_c1:
.byte 1
.program
_main: .equal $
?ASC0:
.equal 0
?TSC0:
.equal 0
?LSC0:
.equal 4
mov a,sp
mov a,#?TSC0+?LSC0
mov sp,a
40
2.4
Przekazywanie danych mi˛edzy funkcjami a instrukcjami asemblera
;adr_main=&main
mov r0,#.low. _main
mov r2,#.high. _main
mov a,sp
add a,#2-?LSC0+1
mov r1,a
mov @r1,__oper1_msb
inc r1
mov @r1,__oper1_lsb
;c1++
inc .low. _c1
Adresowanie po´srednie – polega na operowaniu adresem zmiennej zamiast jej nazw ˛
a. Tego ro-
dzaju działanie jest niezb˛edne je´sli chce si˛e mie´c dost˛ep do zmiennej jednej funkcji z poziomu
innej funkcji. Przekazywanie argumentu z pierwszej funkcji do drugiej odbywa si˛e poprzez war-
to´s´c, tzn. przy u˙zyciu stosu przekazywane s ˛
a kopie argumentów funkcji wywołuj ˛
acej. Funkcja
wywołana operuje tylko na tych kopiach. Aby mo˙zna było zmieni ´c oryginały argumentów funk-
cja wywołuj ˛
aca musi przekaza´c ich adresy. Umo˙zliwia to operator
&
, który u˙zyty dla zmiennej
o nazwie ”
a
” w sposób ”
&a
” nakazuje pobranie adresu zmiennej
a
. Chc ˛
ac teraz operowa ´c na
tym adresie mo˙zna utworzy´c now ˛
a zmienn ˛
a, np. ”
prt=&a;
” nazywan ˛
a wska´znikiem (zmienn ˛
a
wska´znikow ˛
a), której warto´s´c stanowi adres zmiennej
a
. Chc ˛
ac zmieni´c warto´s´c zmiennej
a
mo˙zna zastosowa´c ten wska´znik z operatorem ”
*
” nakazuj ˛
acym traktowa ´c swój argument jako
adres, np. ”
*ptr=5;
” powoduje, ˙ze zmienna
a
przyjmuje warto´s´c 5.
41
2
Programowanie w C µK rodziny Intel 8051
42
Indeks
adres bazowy, 10
asembler, 1
biblioteki, 9
bie˙z ˛
acy wska´znik umieszczenia, 5
dyrektywa, 2
.ABSOLUTE, 12
.BSECT, 14
.CODE, 14
.COMMENT, 3
.DATA, 14
.DB, 6
.DS, 7
.DW, 6
.ELSE, 8
.END, 7
.ENDIF, 8
.ENDM, 8
.ENDMOD, 9
.EQU, 6
.EXTERNAL, 13
.GLOBAL, 13
.IF, 8
.INCLUDE, 14
.MACRO, 8
.MOD, 9
.ORG, 5, 12
.RADIX, 4
.RELATIVE, 12
.RSECT, 14
.SECTION, 15
.SET, 6
grupy sekcji, 10
instrukcja, 2
kompilacja, 22
makroasembler, 7
makrodefinicja, 8
parametry
aktualne, 8
formalne, 8
wywołanie, 8
moduł, 9
konsolidacja, 9
posta´c relokowalna, 9
nazwy, 3, 4
absolutna, 12
absolutne, 6
atrybuty, 6, 13
absolutno´sci, 12
globalno´sci, 13
okre´slono´sci, 6
zewn˛etrzno´sci, 13
globalne, 13
relokowalna, 12
wspólne, 13
zewn˛etrzne, 13
pole
argumentów, 3
etykiety, 2
komentarza, 3
operacji, 3
procedura, 9
program
´zródłowy, 1
wynikowy, 1
program rozruchowy, 22
przeł ˛
acznik sekcji, 15
słownik, 5
dopisywanie nazw, 5
segment, 9, 14
43
Indeks
sekcja, 9, 14
bezpo´srednia, 16
bitowa, 15
definiowanie, 15
domy´slna, 14
lokowanie, 16
po´srednia, 16
pusta, 16
refernecyjna, 16
rejestrowa, 15
standardowa, 14
.BSECT, 14
.CODE, 14
.DATA, 14
.RSECT, 14
u˙zytkownika, 14
stałe, 3
liczbowe, 4
znakowe, 4
wyra˙zenia arytmetyczne, 3
operacje porówna ´n, 5
operatory, 4
44