EMAS: Różnice pomiędzy wersjami

Przejdź do nawigacji Przejdź do wyszukiwania
Dodane 11 022 bajty ,  1 gru 2021
Nie podano opisu zmian
 
(Nie pokazano 45 pośrednich wersji utworzonych przez tego samego użytkownika)
Linia 1: Linia 1:
EMAS jest assemblerem skrośnym dla MERRY 400, używającym, w odróżnieniu od [[ASSEM]], składni bliższej współczesnym assemblerom, oraz mnemoników MERY 400 (ale bez przyrostków zależnych od lokalizacji argumentu, patrz: [[Lista rozkazów]]).
EMAS jest assemblerem skrośnym dla komputera MERA 400, używającym (w odróżnieniu od [[ASSEM]] i ASSM) składni bliższej współczesnym assemblerom.
 
Repozytorium źródeł EMAS-a dostępne jest pod adresem: https://github.com/jakubfi/emas


= Wywołanie =
= Wywołanie =
Linia 5: Linia 7:
Wywołanie EMAS z linii poleceń ma postać:
Wywołanie EMAS z linii poleceń ma postać:


emas [opcje] [wejście [wyjście]]
emas [opcje] [wejście]


Gdzie:
Gdzie:


* '''wejście''' - nazwa wejściowego pliku źródłowego. Jeśli nie zostanie podana, EMAS czyta program ze standardowego wejścia, a wyjściem staje się plik ''out.bin''
* '''wejście''' - nazwa wejściowego pliku źródłowego. Jeśli nie zostanie podana, EMAS czyta program ze standardowego wejścia
* '''wyjście''' - nazwa wyjściowego pliku binarnego. Jeśli nie zostanie podana, przyjmowana jest nazwa ''out.bin''
* '''opcje''' - dowolne z:
* '''opcje''' - dowolne z:
** '''-c <cpu>''' - wybierz procesor, dla jakiego assembler produkuje binaria. Możliwe wybory to: ''mera400'', ''mx16''. Ustawienie procesora na MX-16 pozwala na użycie dodatkowych instrukcji oraz poszerza przestrzeń adresową programu z 32 do 64k słów. Domyślnie przyjmowany procesor to ''mera400''.
** '''-O <otype>''' - typ wyniku asemblacji. Możliwe wybory to:
** '''-O <otype>''' - wybierz typ pliku wyjściowego. Możliwe wybory to:
*** ''raw'' - binarny obraz gotowy do umieszczenia w pamięci maszyny i uruchomienia (domyślny wybór)
*** ''raw'' - binarny obraz gotowy do umieszczenia w pamięci i uruchomienia (domyślny wybór)
*** ''emelf'' - konsolidowalny obiekt [[EMELF]]
*** ''debug'' - plik tekstowy opisujący zawartość kolejnych komórek pamięci (przydatny w przypadku programowania komputera z pulpitu technicznego)
*** ''debug'' - tekstowy opis zawartości kolejnych komórek pamięci
*** ''emelf'' - obiekt dla konsolidatora (opcja nie zaimplementowana)
*** ''keys'' - tekstowy opis zawartości kolejnych komórek pamięci w formacie łatwym do wprowadzenia z pulpitu technicznego maszyny
** '''-o <wyjście>''' - nazwa pliku wyjściowego. Jeśli nie zostanie podana, domyślny wygór zależy od typu wyniku asemblacji:
*** ''raw'' - nazwa pliku wejściowego z pominiętym rozszerzeniem. Jeśli wejście nie jest plikiem, to wyjściem jest plik 'a.out'
*** ''emelf'' - nazwa pliku wejściowego z rozszerzeniem zamienionym na '.o'. Jeśli wejście nie jest plikiem, to wyjściem jest plik 'a.out'
*** ''debug'' i ''keys'' - standardowe wyjście
** '''-c <cpu>''' - wybierz procesor, dla jakiego assembler produkuje binaria. Możliwe wybory to: ''mera400'', ''mx16''. Ustawienie procesora na MX-16 pozwala na użycie dodatkowych instrukcji oraz poszerza przestrzeń adresową programu z 32 do 64k słów. Domyślnie przyjmowany procesor to ''mera400''. Opcja nadpisuje wybór dokonany w źródłe dyrektywą '''.cpu'''.
** '''-I <katalog>''' - dodaj katalog do listy katalogów, w których poszukiwane będą pliki dołączane dyrektywą .include
** '''-I <katalog>''' - dodaj katalog do listy katalogów, w których poszukiwane będą pliki dołączane dyrektywą .include
** '''-D <stała>[=wartość]''' - zdefiniuj stałą i opcjonalnie nadaj jej wartość
** '''-v''' - wyświetl informacje o wersji i zakończ działanie
** '''-v''' - wyświetl informacje o wersji i zakończ działanie
** '''-h''' - wyświetl pomoc i zakończ działanie
** '''-h''' - wyświetl pomoc i zakończ działanie
** '''-d''' - drukuj informacje przydatne w śledzeniu błędów działania asemblera (dla deweloperów)
Oprócz katalogów podanych jako argumenty opcji '-I' EMAS używa następujących domyślnych katalogów, w których poszukuje plików dołączanych dyrektywą '''.include'''" (w kolejności):
* bieżący katalog
* /usr/share/emas/include
* /usr/local/share/emas/include


= Opis języka =
= Opis języka =
Linia 41: Linia 54:
=== Liczby całkowite ===
=== Liczby całkowite ===


Liczby całkowite można zapisywać w systemie binarnym, ósemkowym, dziesiętnym lub szesnastkowym, np:
Liczby całkowite można zapisywać w systemie binarnym, ósemkowym, dziesiętnym lub szesnastkowym. Dozwolone jest też rozdzielanie cyfr znakiem podkreślenia.


  0b1101110000
  0b1101110000
0b_1111_0000_1100_0011
  0177
  0177
  -931
  -931
  0xffa9
  0xffa9


Istnieje jeszcze jeden sposób zapisu stałych całkowitoliczbowych, wynikający z ułożenia [[Rejestry i wskaźniki|wskaźników w rejestrze R0]], gdzie poszczególnym bitom przypisany jest jednoliterowy symbol ze zbioru (Z, M, V, C, L, E, G, Y, X). Można dzięki niemu zapisać liczbę szesnastobitową z ustawionymi na 1 bitami, które odpowiadają danym wskaźnikom. Przykłady takiego zapisu stałych:
Istnieje jeszcze jeden sposób zapisu stałych całkowitoliczbowych, wynikający z ułożenia [[Rejestry i wskaźniki|wskaźników w rejestrze R0]], gdzie poszczególnym bitom przypisany jest jednoznakowy symbol ze zbioru (Z, M, V, C, L, E, G, Y, X, 1, 2, 3, 4, 5, 6, 7). Można dzięki niemu zapisać liczbę szesnastobitową z ustawionymi na 1 bitami, które odpowiadają danym wskaźnikom. Przykłady takiego zapisu stałych:


  ?ZM
  ?ZM125
  ?GVZ
  ?GVZ


EMAS przechowuje liczby całkowite jako 32-bit liczby w kodzie U2 i na takich liczbach operuje. W trakcie umieszczania liczb w obiekcie wynikowym są one obcinane do 16 najmłodszych bitów. Wyjątkiem jest argument dyrektywy '''.dword''', który jest 32-bit liczbą w kodzie U2.
Wewnętrznie EMAS operuje na 32-bit liczbach ze znakiem. Kiedy ostateczna wartość będąca wynikiem operacji ma zostać umieszczona w obiekcie wynikowym, jej zakres jest sprawdzany i użytkownik jest informowany o ewentualnym jego przekroczeniu. Wyjątkiem jest argument dyrektywy '''.dword''', który jest 32-bit liczbą w kodzie U2.
 
=== Znaki ===
 
EMAS pozwala na zapisywanie stałych całkowitoliczbowych również przy pomocy znaków, dwuznaków lub trójznaków. Znaki pojedyncze oraz dwuznaki obejmują cały zakres znaków ASCII i można je podawać również używając sekwencji unikowych. Trójznaki pozwalają kodować jedynie znaki poprawne dla [[CROOK-5 - Interpretator zleceń użytkownika - XOSL#Kod R40|kodu R40]].
 
Znaki w pojedynczych cudzysłowach:
 
'a', '\n', '\xa1', '\0177'
 
kodowane są jako ich wartość w kodzie ASCII na młodszym bajcie słowa. Dwuznaki:
 
'ab', '\r\n', '\xaa\0001'
 
kodowane są jako wartości podanych znaków w kodzie ASCII odpowiednio na starszym i młodszym bajcie słowa.


=== Liczby zmiennoprzecinkowe ===
=== Liczby zmiennoprzecinkowe ===
Linia 69: Linia 97:
=== Łańcuchy ===
=== Łańcuchy ===


Łańcuchy znaków są ciągami 8-bit znaków ujętymi w podwójne cudzysłowy. Poszczególne znaki można zapisywać dosłownie, lub używając jednej z sekwencji unikowych:
Łańcuchy znaków są ciągami znaków ujętymi w podwójne cudzysłowy. Poszczególne znaki można zapisywać dosłownie, lub (w przypadku dyrektyw '''.ascii''' i '''.asciiz''') używając jednej z sekwencji unikowych:
 
* \0'''yyy''' - gdzie '''yyy''' jest ósemkowym kodem znaku
* \0'''yyy''' - gdzie '''yyy''' jest ósemkowym kodem znaku
* \x'''yy''' - gdzie '''yy''' jest szesnastkowym kodem znaku
* \x'''yy''' - gdzie '''yy''' jest szesnastkowym kodem znaku
Linia 86: Linia 115:
  "\"napis\""
  "\"napis\""


Umieszczając łańcuchy w programie wynikowym EMAS lokuje każde dwa kolejne sąsiadujące ze sobą znaki kolejno w starszej i młodszej połówce 16-bit słowa. Jeśli łańcuch zawiera nieparzystą liczbę znaków, to w ostatnim słowie na pozycji młodszego bajtu znajdzie się wartość 0.
To, w jaki sposób znaki umieszczane są w programie wynikowym zależy od dyrektywy, której łańcuch jest argumentem.
 
=== Bieżąca lokalizacja ===
 
Specjalną stałą jest "." (kropka), która w danym miejscu programu zawsze zwraca przesunięcie względem początku assemblowanego obiektu. Jej wartość jest zawsze >= 0.


== Symbole ==
== Symbole ==
Linia 121: Linia 154:
=== Zasięg symboli ===
=== Zasięg symboli ===


Wszystkie symbole definiowane są jako lokalne. Jeśli symbol ma być widoczny dla konsolidatora, należy go zadeklarować jako globalny dyrektywą '''.global'''. Zmiana zasięgu może nastąpić przed, lub po definicji:
EMAS pozwala na zawężenie zasięgu symbolu przez poprzedzenie go kropką. Tak zdefiniowany symbol dostępny jest w zakresie od poprzedniego do następnego symbolu globalnego. Dzięki temu możliwe jest używanie takich samych nazw etykiet lokalnych w różnych kontekstach. Na przykład:
 
globalny1:
...
.lokalny:
...
ujs lokalny
globalny2:
.lokalny:
...
ujs lokalny
 
Skok 'ujs' wykonany zostanie każdorazowo do adresu opisanego symbolem ".lokalny", różnego dla zasięgów "globalny1" i "globalny2". Symbol lokalny nie może być zdefiniowany, jeśli uprzednio nie wystąpił żaden symbol globalny.
 
Można również odwołać się do lokalnego symbolu spoza jego zasięgu poprzedzając jego nazwę nazwą symbolu globalnego, w kontekście którego został zdefiniowany:
 
globalny1.lokalny
globalny2.lokalny
 
Lokalnych symboli można używać również definiując stałe i zmienne:
 
zmienna:
.equ a 1
.equ b 2
 
i odwoływać się do nich:
 
lw r1, zmienna.a
lw r2, zmienna.b
 
=== Widoczność symboli dla konsolidatora ===
 
Wszystkie symbole definiowane są jako widoczne wyłącznie w ramach asemblowanego obiektu. Jeśli symbol ma być widoczny dla konsolidatora, należy go zadeklarować jako zewnętrzny dyrektywą '''.global'''. Zmiana zasięgu może nastąpić przed, lub po definicji:


  .global printf
  .global printf
  .global snprintf
  .global snprintf
  .global strdup
  .global strdup
 
  printf:
  printf:
  ...
  ...
Linia 132: Linia 198:
  ...
  ...
  strdup:
  strdup:
 
  procedura:
  procedura:
  .global procedura
  .global procedura


== Wyrażenia ==
== Wyrażenia ==
=== Operatory ===
Poniższa tabela przedstawia operatory arytmetyczne i bitowe, w kolejności malejących priorytetów
{| class="wikitable"
! Operatory !! Działanie
|-
| ~ || negacja bitowa
|-
| \ || skalowanie
|-
| *, /, % || mnożenie, dzielenie, reszta z dzielenia
|-
| +, - || dodawanie, odejmowanie
|-
| <<, >> || przesunięcie bitowe w lewo i w prawo
|-
| &, <nowiki>|</nowiki>, ^ || logiczny iloczyn, suma i suma wykluczająca
|}
Operator skalowania realizuje funkcję dokładnie taką samą, jak przesunięcie bitowe, jest tylko innym sposobem jego zapisu. Poniższe zapisy są równoznaczne:
3\7  =  3 << (15-7)
Skalowanie można rozumieć jako: "umieść liczbę 3 od 7 pozycji bitowej w górę. Bity dla tego zapisu numerowane są od 0 (bit najstarszy) do 15 (bit najmłodszy). Wynikiem będzie więc liczba:
0000001100000000


== Dyrektywy assemblera ==
== Dyrektywy assemblera ==


.cpu
=== .cpu ===
.file
 
.line
'''Składnia:''' .cpu <mera400|mx16>
.include
 
.equ
Odpowiednik przełącznika ''-c'' linii poleceń EMAS-a. Pozwala określić typ procesora, dla którego ma być generowany kod wynikowy. Użycie ''mx16'' sprawia, że:
.const
* mnemoniki '''CRON''', '''SINT''', '''SIND''' są rozpoznawane i poprawnie assemblowane
.lbyte
* maksymalny rozmiar wynikowego pliku binarnego wynosi 64k słowa (32k dla ''mera400'')
.rbyte
 
.word
=== .file ===
.dword
 
.float
'''Składnia:''' .file ''nazwa_pliku''
.ascii
 
.asciiz
Ustala nazwę assemblowanego pliku. Jeśli assembler będzie chciał użyć w komunikatach nazwy pliku, to domyślna nazwa (zgodna z nazwą assemblowanego pliku) zostanie od momentu wydania dyrektywy zastąpiona podaną.
.res
 
.org
=== .line ===
.entry
 
.global
'''Składnia:''' .line ''numer_linii''
 
Ustala numer bieżącej linii assemblacji (poczynając od linii następującej po dyrektywie). Dalsze linie będą numerowane kolejno od podanej wartości.
 
=== .include ===
 
'''Składnia:''' .include ''nazwa_pliku''
 
Powoduje dołączenie do assemblacji pliku o podanej nazwie.
 
=== .equ ===
 
'''Składnia:''' .equ ''nazwa_zmiennej'' ''wartość''
 
Ustala wartość zmiennej assemblacji. Może być ona w dalszej części programu zmieniana.
 
=== .const ===
 
'''Składnia:''' .const ''nazwa_zmiennej'' ''wartość''
 
Ustala wartość stałej assemblacji. Wartość ta nie może ulec zmianie.
 
Zapisuje w programie wynikowym na prawych pozycjach (LSB) kolejnych słów podane wartośći 8-bit.
 
=== .word ===
 
'''Składnia:''' .word ''liczba_16_bit'' [, ...]
 
Zapisuje w programie kolejne słowa 16-bit o podanej wartości.
 
=== .dword ===
 
'''Składnia:''' .dword ''liczba_32_bit'' [, ...]
 
Zapisuje w programie wynikowym pary słów 16-bit tworzące podaną liczbę 32-bit.
 
=== .float ===
 
'''Składnia:''' .float ''liczba_zmiennoprzecinkowa'' [, ...]
 
Zapisuje w programie wynikowym trójki słów 16-bit tworzące podaną 48-bit liczbę zmiennoprzecinkową w notacji używanej przez arytmometr wielokrotnej precyzji MERY-400.
 
=== .ascii ===
 
'''Składnia:''' .ascii ''łańcuch''
 
Zapisuje w programie wynikowym podany łańcuch, kodując go po dwa znaki ASCII na słowo maszynowe.
 
=== .asciiz ===
 
'''Składnia:''' .asciiz ''łańcuch''
 
Zapisuje w programie wynikowym podany łańcuch, kodując go po dwa znaki ASCII na słowo maszynowe. Łańcuch terminowany jest 8-bit wartością '0'.
 
=== .res ===
 
'''Składnia:''' .res ''rozmiar'' [,''liczba_16_bit'']
 
Rezerwuje w programie wynikowym obszar o podanym rozmiarze (w słowach), wypełniając go zerami. Jeśli podany jest drugi argument, jego wartość używana jest do wypełnienia zamiast zera.
 
=== .org ===
 
'''Składnia:''' .org ''adres''
 
Ustala nową bieżącą pozycję assemblacji. Następne wygenerowane słowo zostanie umieszczone już pod podanym, nowym adresem.
 
=== .entry ===
 
'''Składnia:''' .entry ''adres''
 
Dyrektywa ma efekt wyłącznie w przypadku generowania pliku wynikowego jako obiektu EMELF. Określa adres wejścia do programu.
 
=== .global ===
 
'''Składnia:''' .global ''nazwa_etykiety''
 
Dyrektywa ma efekt wyłącznie w przypadku generowania pliku wynikowego jako obiektu EMELF. Wskazuje, że symbol będzie widoczny dla linkera.
 
=== .ifdef, .ifndef ===
 
Dyrektywa pozwala na asemblację warunkową podejmowaną istnieniem (bądź nie) zdefiniowanego symbolu.
 
.ifdef SYMBOL
... kod asemblowany, jeśl SYMBOL jest zdefiniowany ...
.else
... kod asemblowany, jeśli SYMBOL nie jest zdefiniowany ...
.endif
 
.ifndef SYMBOL
... kod asemblowany, jeśli SYMBOL nie jest zdefiniwoany
.endif
 
Symbol określający warunek może być zarówno etykietą, stałą lub zmienną zdefiniowaną w pliku źródłowym, jak również stałą zdefiniowaną podczas wywołania emas-a z opcją '-D'
 
=== .struct ===
 
Dyrektywa ta pozwala na stworzenie opisu struktury danych w celu uczynienia kodu źródłowego bardziej czytelnym. Nie formalizuje ona struktury, a jedynie ułatwia pracę z danymi. Przykład opisu struktury 'struktura':
 
.struct struktura:
    adres .res 1
    dluga_liczba .res 2
    tekst .res 64
.endstruct
 
Kolejne pozycje nazywają kolejne pola struktury i określają ich długość w słowach. Po asemblacji symbolom o tych nazwach przypisany zostanie offset w strukturze, a nazwie struktury - jej długość.
 
Użycie struktury w programie może wyglądać następująco:
 
moja_str: .res struktura
lw r3, moja_str
ld r3 + dluga_liczba
lw r7, moja_str + tekst
 
Definicja struktury z powyższego przykładu równoważna jest de facto następującemu ciągowi dyrektyw:
 
.const adres 0        ; offset pola 'adres'
.const dluga_liczba 1  ; offset pola 'dluga_liczba'
.const tekst 3        ; offset pola 'tekst'
.const struktura 67    ; rozmiar struktury 'struktura'
 
W strukturach można również zawęzić zakres nazewnictwa pól:
 
.struct struktura:
    .adres .res 1
    .dluga_liczba .res 2
    .tekst .res 64
.endstruct
 
Wtedy nazwy pól będą dostępne wyłącznie w kontekście danej struktury, a jej użycie wyglądać będzie następująco:
 
moja_str: .res struktura
lw r3, moja_str
ld r3 + struktura.dluga_liczba
lw r7, moja_str + struktura.tekst


== Rozkazy ==
== Rozkazy ==
EMAS używa mnemoników z [[Lista rozkazów|oryginalnej listy rozkazów]] MERY-400, ale wprowadza zmiany składniowe wynikające z innego zapisu argumentu normalnego. Nie używa przyrostków zależnych od lokalizacji argumentu. Czyli np. rozkaz ```LWn`` z listy rozkazów, gdzie ```n``` zmienia się w zależności od typu argumentu normalnego, ma zawsze mnemonik ```LW```. Lokalizację argumentu określa składnia dla rejestrów rB i rC. Poniższe przykłady ładowania wartości do rejestru r1 przedstawiają wszystkie możliwe postacie argumentu normalnego:
* LW r1, r2 - ładowana jest wartość z rejestru r2
* LW r1, r2+r3 - ładowana jest wartość z rejestru r2 B-modyfikowana (sumowana z) rejestrem r3
* LW r1, [r2] - ładowana jest wartość z komórki pamięci (D-modyfikacja) wskazanej zawartością rejestru r2
* LW r1, [r2+r3] - ładowana jest wartość z komórki pamięci (D-modyfikacja) wskazanej zawartością rejestru r2 B-modyfikowanego (sumowanego z) rejestrem r3
* LW r1, 0x1000 - ładowana jest wartość 0x1000
* LW r1, 0x1000+r2 - ładowana jest wartość 0x1000 B-modyfikowana zawartością (sumowana z) rejestru r2
* LW r1, [0x1000] - ładowana jest wartość z komórki pamięci (D-modyfikacja) o adresie 0x1000
* LW r1, [x1000+r2] - ładowana jest wartość z komórki pamięci (D-modyfikacja) o adresie 0x1000 B-modyfikowanym zawartością rejestru r2
= Pliki nagłówkowe =
Z assemblerem EMAS dostarczany jest [https://github.com/jakubfi/emas/tree/master/asminc zestaw plików nagłówkowych] definiujących stałe przydatne przy programowaniu w obszarze systemu operacyjnego i dla urządzeń wejścia-wyjścia:
* cpu.inc - stałe wynikające z architektury systemu ([[Mapa pamięci|zdefiniowane lokalizacje pamięci]], [[Przerwania|przerwania, maski przerwań]]),
* io.inc - podstawowe stałe przydatne przy konfigurowaniu pamięci, stałe dla systemu wejścia-wyjścia, komendy dla kanału znakowego i wspólne komendy dla urządzeń w nim pracujących,
* mega.inc - komendy dla [[Pamięć MEGA|pamięci mega]] Amepolu,
* multix.inc - stałe i komendy przydatne przy programowaniu procesora peryferyjnego [[MULTIX]].
Znaczenie poszczególnych stałych opisane jest w plikach nagłówkowych, ich rolę opisuje [[DTR|Dokumentacha Techniczno-Ruchowa]] minikomputera.

Menu nawigacyjne