MAD-ASSEMBLER 2.1.0

Tebe/Madteam (11.11.2019)

`WPROWADZENIE Wstęp Kompilacja Różnice i podobieństwa pomiędzy XASM i MADS Podobieństwa Różnice i nowe możliwości SPOSÓB UŻYCIA Przełączniki assemblera Kody wyjścia Struktura pliku .LST Struktura pliku .LAB Struktura pliku .H SPARTA DOS X Budowa plików Sparta DOS X, Atari DOS Programowanie Sparta DOS X MNEMONIKI 6502 6502 nielegalne 65816 DETEKCJA CPU BANKI PAMIĘCI Wirtualne Sprzętowe KOD RELOKOWALNY Blok relokowalny Symbole zewnętrzne Symbole publiczne Linkowanie TYPY Strukturalne Deklaracja typu strukturalnego Definiowanie danych strukturalnych Wyliczeniowe Deklaracja typu wyliczeniowego Definiowanie danych wyliczeniowych HISTORIA` | `SKŁADNIA Komentarze Łączenie wielu wierszy w jeden wiersz Łączenie wielu mnemoników Wyrażenia Liczby Operatory Etykiety Anonimowe Lokalne Globalne Tymczasowe Lokalne w stylu MAE Kontrola asemblacji Zmiana opcji asemblacji Asemblacja warunkowa Przerwanie asemblacji Asemblacja na stronie zerowej Makro rozkazy Pseudo rozkazy Definiowanie bloku SDX Definiowanie symbolu SDX Definiowanie danych Dyrektywy Definiowanie powtórzeń (.REPT) Definiowanie symbolu SDX (.SYMBOL) Definiowanie tablic (.ARRAY) Definiowanie segmentów (.SEGDEF) Dyrektywy generujące kod 6502 Definiowanie iteracji (#WHILE) Definiowanie decyzji (#IF) #CYCLE Tablice Deklaracja tablicy Makra Deklaracja makra Wywołanie makra Definiowanie makra Procedury Deklaracja procedury Wywołanie procedury Parametry procedury Obszar lokalny Deklaracja obszaru lokalnego`

`

WPROWADZENIE

`

## Wstęp

`

`Mad-Assembler (MADS)` jest aplikacją `32` bitową, napisaną w `Delphi`. Większość asemblerów napisano w `C`, więc żeby się nie powtarzać użyłem `Delphi 7.0 ;)`.

W założeniu `MADS` skierowany jest do użytkowników `QA`, `XASM`, `FA`. Z `QA` zapożyczona została składnia, z `XASM` niektóre makro rozkazy i zmiany składni, z `FA` obsługa składni `Sparta DOS X (SDX)`. Umożliwione zostało użycie dodatkowych znaków w nazwach etykiet. Poza tym dodana została obsługa `CPU 65816`, makr, procedur, podziału pamięci na wirtualne banki, wielowymiarowych nazw etykiet.

Maksymalna liczba etykiet i makr ograniczona jest ilością pamięci komputera `PC`. Konkretnie można dokonać `2147483647` `(INTEGER)` wpisów do tablic dynamicznych. Jestem pewien że taka ilość jest wystarczająca :)

Operacje arytmetyczne dokonywane są na wartościach typu `INT64` (signed 64 bit), wynik reprezentowany jest na wartościach typu `CARDINAL` (unsigned 32 bit).

Jeden wiersz może mieć długość `65535` bajtów, takiej długości może być też nazwa etykiety. Nie miałem jednak okazji sprawdzić tak długich etykiet i wierszy :)

Dzięki darmowemu kompilatorowi `Free Pascal Compiler` możliwa jest kompilacja `MADS-a` dla innych platform systemowych, np. `Linux, Mac, OS/2` itp. Więcej informacji na temat kompilacji w rodziale Kompilacja.

Jeśli dla Twojego systemu istnieje odpowiednia wersja `Free Pascala`, tzn. że możesz używać `MADS-a.`

- Strona domowa `XASM-a`: http://atariarea.krap.pl/x-asm/
- Wątki dotyczące `MADS-a`:
  - http://www.atari.org.pl/
  - http://atariage.com/
  - Kolorowanie składni MADS, XASM

  `

  ## Kompilacja

  `

  Aby skompilować źródło `MADS-a`, można użyć kompilatora z `Delphi`, jeśli ktoś ma akurat zainstalowane środowisko `Delphi 7.0` lub nowsze.

  Innym sposobem, bardziej multi platformowym jest użycie kompilatora z pakietu `Free Pascal Compiler (FPC)`, który można pobrać ze strony http://www.freepascal.org/

  Uruchamiamy instalator, wybieramy katalog w którym zostanie zainstalowany `FP`. Ważne jest aby nie używać w nazwie katalogu znaku wykrzyknika `'!'` czy innych nie standardowych znaków. Jeśli nie uda nam się skompilować żadnego pliku, najpewniej winna jest nie standardowa nazwa ścieżki. Linia komend uruchamiająca kompilację może wyglądać następująco (wielkość liter w nazwach parametrów ma znaczenie):

      fpc -Mdelphi -v mads.pas

- -Mdelphi pozwala kompilować plik w formacie `Delphi`
- -v wyświetla wszystkie komunikaty błędów i ostrzeżeń
- -O3 dokonuje optymalizacji kodu W porównaniu z kompilatorem `Delphi`, kod wygenerowany przez `FPC` jest dłuższy, za to prędkość działania skompilowanego nim `MADS-a` znacznie większa, nawet o kilka sekund. Załączony plik `MADS.EXE` jest kompilowany przy użyciu `FPC`.

  RÓŻNICE I PODOBIEŃSTWA POMIĘDZY XASM I MADS

  `

  ## Podobieństwa

  `
- ta sama składnia
- te same kody wyjścia
- te same makro rozkazy

  `

  ## Różnice i nowe możliwości

  `
- mała różnica w `ORG`, np. `'ORG [[expression]]adres[,adres2]'`
- `XASM` nie lubi "białych spacji", `MADS` toleruje je i akceptuje dla wyrażeń logicznych, arytmetycznych, definicji stałych i zmiennych
- `MADS` pozwala na umieszczanie wyrażeń pomiędzy nawiasami `(), []`, `XASM` tylko pomiędzy `[]`
- `MADS` udostępnia definicje stałych i zmiennych lokalne, globalne, tymczasowe, `XASM` tylko globalne
- `MADS` nie akceptuje `ORG a:adres` i `ORG f:adres`
- `MADS` udostępnia zapis liczb rzeczywistych poprzez dyrektywę .FL .FL real, XASM poprzez pseudo rozkaz DTA R `DTA R(real)`
- `MADS` oferuje bardziej rozbudowaną obsługę pseudo rozkazu `INS`
- `MADS` nie akceptuje składni typu 'lda (203),0'
- `MADS` umożliwia pisanie programów dla Sparta DOS X
- `MADS` umożliwia generowanie kodu relokowalnego w swoim własnym formacie
- jeśli użyjemy podczas adresowania wartości znakowej, np.

        lda #' '
        lda #" "

  `MADS` będzie rozróżniał apostrof pojedyńczy (kod `ATASCII`) i apostrof podwójny (kod `INTERNAL`), `XASM` oba rodzaje apostrofów potraktuje jednakowo (kod `ATASCII`). Oczywiście dla danych `DTA` apostrofy nie są rozróżniane przez `MADS`.

- w trybach indeksowych znak `'+'` lub `'-'` zwiększa lub zmniejsza rejestr, np.

       lda $2000,x+    ->    lda $2000,x
                             inx

- jeśli jednak umieścimy wartość za znakiem `'+'` lub `'-'` wówczas zmienimy o tą wartość główny argument (działa tylko w trybie absolutnym indeksowym), np.:

       lda $2000,x+2   ->    lda $2002,x

  SPOSÓB UŻYCIA

  `

  ## Przełączniki assemblera

  `

      Syntax: mads source [switches]

      -b:address      Generate binary file at specific address
      -c              Label case sensitivity
      -d:label=value  Define a label
      -f              CPU command at first column
      -fv:value       Set raw binary fill byte to [value]
      -hc[:filename]  Header file for CC65
      -hm[:filename]  Header file for MADS
      -i:path         Additional include directories
      -l[:filename]   Generate listing
      -m:filename     File with macro definition
      -ml:value       margin-left property
      -o:filename     Set object file name
      -p              Print fully qualified file names in listing and error messages
      -s              Silent mode
      -t[:filename]   List label table
      -u              Warn of unused labels
      -vu             Verify code inside unreferenced procedures
      -x              Exclude unreferenced procedures

  Domyślne nazwy plików to:

  ``
- source.lst
- source.obx
- source.lab
- source.h
- source.hea
- source.mac
`

Jeśli nie podamy rozszerzenia dla pliku `source`, wówczas `MADS` domyślnie przyjmie rozszerzenie `.ASM`.

Parametry możemy podawać w dowolnej kolejności uprzednio poprzedzając je znakiem `'/'` lub `'-'`, wielkość liter nie ma znaczenia. Parametry możemy łączyć ze sobą, np.:

    mads -lptd:label=value -d:label2=value source.asm
    mads -l  -p  -t  source
    mads source.asm  -lpt
    mads.exe "%1" -ltpi:"d:\!atari\macro\"
    mads -i:"c:\atari\macros\" -c source.asm  -lpt

Domyślnie `MADS` po asemblacji zapisze plik z rozszerzeniem '.OBX', możemy to zmienić z poziomu BAT-a:

    mads "%1" -o:%~n1.xex

Więcej na temat operatorów możemy dowiedzieć się wykonując "CALL /?" z poziomu Microsoft DOS-a.

-b:address
Użycie przełącznika `-b` pozwala nadać nowy adres asemblacji dla pliku w którym nie określono adresu asemblacji (adres asemblacji określamy przy pomocy pseudo rozkazu ORG).

-c
Użycie przełącznika `-c` spowoduje rozróżnianie wielkości liter w nazwach etykiet, zmiennych, stałych. Dyrektywy assemblera i rozkazy `CPU 6502, 65816` są zawsze rozpoznawane bez względu na wielkość liter.

-d:label=value
Użycie przełącznika `-d` pozwala na wprowadzenie nowej etykiety do pamięci `MADS-a` z poziomu linii poleceń. Przełącznika można użyć wielokrotnie podczas jednego wywołania `MADS-a`, może być przydatny gdy asemblujemy z użyciem plików wsadowych (`BAT`).

-f
Użycie przełącznika `-f` umożliwia umieszczanie rozkazów CPU od pierwszej kolumny wiersza i ich poprawne rozpoznawanie przez asembler jako rozkazy a nie tylko jako etykiety.

-f
Użycie przełącznika `-fv:value` pozwala ustalić wartość wypełnienia pamięci gdy użyjemy 'OPT F+'

-hc[:filename]
Przełącznik `-hc` włącza zapis pliku z nagłówkami dla kompilatora `CC65`. Pozwala także określić nową nazwę dla takiego pliku. Domyślna nazwa pliku nagłówkowego dla `CC65` to `*.H`

-hm[:filename]
Przełącznik `-hm` włącza zapis pliku z nagłówkami dla `MADS-a`. Pozwala także określić nową nazwę dla takiego pliku. Domyślna nazwa pliku nagłówkowego dla `MADS-a` to `*.HEA`. Plik taki zawiera informacje o bankach przypisanych etykietom i ich wartości. Dodatkowo etykiety posortowane zostają wg typu `CONSTANS, VARIABLES, PROCEDURES`.

-i:path
Przełącznik `-i` służy do określenia ścieżek poszukiwań dla operacji `ICL` oraz `INS`. Przełącznika można użyć wielokrotnie podczas jednego wywołania `MADS-a`, np.:

     -i:"c:\program files" -i:c:\temp -i:"d:\atari project"

-l:filename
Przełącznik `-l` włącza zapis pliku z listingiem. Pozwala także określić nową nazwę dla takiego pliku.

-m:filename
Przełącznik `-m` służy do określenia pliku z deklaracjami makr. W przypadku jego użycia `MADS` asembluje taki plik przed głównym plikiem `.ASM`

-o:filename
Przełącznik `-o` pozwala określić nową nazwę pliku wykonywalnego `Atari DOS` lub `Atari Sparta DOS X`, który powstanie po procesie asemblacji.

-p
Przełącznik `-p` pomocny jest w połączeniu z Code Genie. Gdy wystąpi błąd podczas asemblacji, w oknie Output Bar edytora Code Genie pojawi się stosowny komunikat wygenerowany przez `MADS`, np.:

    D:\!Delphi\Masm\test.asm (29) ERROR: Missing .PROC

Teraz wystarczy kliknąć dwukrotnie linię z tym komunikatem, a kursor edytora ustawi się w linii z błędem.

-s
Użycie przełącznika `-s` spowoduje uaktywnienie tzw. trybu pracy `'Silent mode'`, czyli żadne komunikaty nie zostaną wyświetlone, co najwyżej komunikaty błędów `(ERROR)` i ostrzeżenia `(WARNING)`.

-t[:filename]
Przełącznik `-t` włącza zapis pliku z użytymi definicjami etykiet. Pozwala także określić nową nazwę dla takiego pliku.

-x
Przełącznik `-x` pozwala na pominięcie w procesie asemblacji procedur zadeklarowanych dyrektywą .PROC, do których nie nastąpiło odwołanie w programie.

-vu
Przełącznik `-vu` wymusza dodatkowy test kodu w blokach .PROC mimo tego że taki blok .PROC nie zostanie zapisany do pliku wynikowego, najczęściej przydaje się gdy używamy przełącznika -x

-u
Przełącznik `-u` wyświetli etykiety które nie zostały użyte w programie.
`

## Kody wyjścia

`

    3 = bad parameters, assembling not started
    2 = error occured
    0 = no errors

Komunikaty ostrzeżenia nie powodują zmiany wartości kodu wyjścia.

`

## Struktura pliku LST

`

Format listingu nie odbiega od tego znanego z `XASM`, jedyną zmianą jest dodanie przed adresem, numeru wirtualnego banku pamięci (pod warunkiem że numer banku <>0). Więcej o wirtualnych bankach w rozdziale Banki pamięci.

         3
         4 = 01,9033		obraz equ $9033
         5 = 01,00A0		scr1 equ $a0
         6
         7
         8 01,2000 EA		main nop

`

## Struktura pliku LAB

`

Podobnie jak w przypadku `XASM`, w pliku `*.LAB` przechowywane są informacje na temat etykiet które wystąpiły w programie.

W sumie są to trzy kolumny:

- Pierwsza kolumna to numer wirtualnego banku przypisany do etykiety (jeśli bank <>0)
- Druga kolumna to wartość etykiety.
- Trzecia kolumna to nazwa etykiety. Numery wirtualnych banków przypisane do etykiety o wartościach >= $FFF9 mają specjalne znaczenie:

       $FFF9   etykieta parametru procedury zdefiniowanej przez dyrektywę .PROC
       $FFFA   etykieta tablicy zdefiniowanej przez dyrektywę .ARRAY
       $FFFB   etykieta danych strukturalnych zdefiniowanej przez pseudo rozkaz DTA STRUCT_LABEL
       $FFFC   etykieta symbolu Sparta DOS X - SMB
       $FFFD   etykieta makra zdefiniowanego przez dyrektywę .MACRO
       $FFFE   etykieta struktury zdefiniowanej przez dyrektywę .STRUCT
       $FFFF   etykieta procedury zdefiniowanej przez dyrektywę .PROC

  Specjalne znaczenie w nazwach etykiet mają znaki:

- etykieta zdefiniowana w makrze (dwa dwukropki) `::`
- znak kropki `'.'` rozdziela nazwę struktury (`.MACRO, .PROC, .LOCAL, .STRUCT`) od nazwy pola w strukturze

  Wartość liczbowa, która występuje po `::` oznacza numer wywołania makra.

      Mad-Assembler v1.4.2beta by TeBe/Madteam
      Label table:
      00	0400	@STACK_ADDRESS
      00	00FF	@STACK_POINTER
      00	2000	MAIN
      00	2019	LOOP
      00	201C	LOOP::1
      00	201C	LHEX
      00	0080	LHEX.HLP
      00	204C	LHEX.THEX
      00	205C	HEX
      00	205C	HEX.@GETPAR0.LOOP
      00	2079	HEX.@GETPAR1.LOOP

  `

  ## Struktura pliku H

  `

  Nie jestem pewien czy wszystko z tym plikiem jest OK, ale Eru chciał żeby coś takiego było więc jest :) Ma on być pomocny przy łączeniu `ASM-a` z `CC65`, czyli portem `C` dla małego Atari. Jego zawartość może wyglądać tak (przykładowy plik `TEST.ASM`):

      #ifndef _TEST_ASM_H_
      #define _TEST_ASM_H_

      #define TEST_CPU65816 0x200F
      #define TEST_CPU6502 0x2017
      #define TEST_TEXT6502 0x201F
      #define TEST_TEXT65816 0x2024

      #endif

  MAKRO ROZKAZY

       REQ, RNE, RPL, RMI, RCC, RCS, RVC, RVS

       SEQ, SNE, SPL, SMI, SCC, SCS, SVC, SVS

       JEQ, JNE, JPL, JMI, JCC, JCS, JVC, JVS

       ADD, SUB

       ADB, SBB

       ADW, SBW

       PHR, PLR

       INW, INL, IND, DEW, DEL, DED

       MVA, MVX, MVY

       MWA, MWX, MWY

       CPB, CPW, CPL, CPD

  Zadaniem makro rozkazów jest skrócenie czasu pisania programu i samego listingu. Makro rozkazy zastępują grupy często powtarzających się mnemoników.

  ``

  ### REQ, RNE, RPL, RMI, RCC, RCS, RVC, RVS

  W/w makro rozkazy swoimi nazwami nawiązują do odpowiednich mnemoników `6502`, odpowiednio `BEQ, BNE, BPL, BMI, BCC, BCS, BVC, BVS`. Posiadają dodatkową właściwość jaką jest skok do poprzednio asemblowanej instrukcji, np.:

         lda:cmp:req 20           ->      lda 20
                                  -> wait cmp 20
                                  ->      beq wait

         ldx #0                   ->      ldx #0
         mva:rne $500,x $600,x+   -> loop lda $500,x
                                  ->      sta $600,x
                                  ->      inx
                                  ->      bne loop

  ``

  ### SEQ, SNE, SPL, SMI, SCC, SCS, SVC, SVS

  W/w makro rozkazy swoimi nazwami nawiązują do odpowiednich mnemoników `6502`, odpowiednio `BEQ, BNE, BPL, BMI, BCC, BCS, BVC, BVS`. Posiadają dodatkową właściwość jaką jest skok do następnej asemblowanej instrukcji, np.:

         lda #40         ->       lda #40
         add:sta  $80    ->       clc
         scc:inc  $81    ->       adc $80
                         ->       sta $80
                         ->       bcc skip
                         ->       inc $81
                         ->  skip

  ``

  ### JEQ, JNE, JPL, JMI, JCC, JCS, JVC, JVS

  W/w makro rozkazy swoimi nazwami nawiązują do odpowiednich mnemoników `6502`, odpowiednio `BEQ, BNE, BPL, BMI, BCC, BCS, BVC, BVS`. Posiadają dodatkową właściwość jaką jest skok warunkowy pod wskazany adres, z ich pomocą możemy skakać nie tylko w zakresie -128..+127 bajtów ale w całym zakresie 64kB np.:

       jne dest   ->  beq *+4
                  ->  jmp dest

  Jeśli skok jest krótki (zakres -128..+127) wówczas MADS użyje krótkiego skoku, odpowiednio BEQ, BNE, BPL, BMI, BCC, BCS, BVC, BVS.

  ``

  ### ADD, SUB

  W/w makro rozkazy realizują odpowiednio zwiększenie/zmniejszenie bajtu pamięci bez zapisywania wyniku (wynik w akumulatorze CPU).

        ADD -> CLC         SUB -> SEC
            -> ADC ...         -> SBC ...

  ``

  ### ADB, SBB

  W/w makro rozkazy realizują odpowiednio zwiększenie/zmniejszenie bajtu pamięci z zapisaniem wyniku.

        ADB SRC #$40 -> LDA SRC       ADB A B C  -> LDA A
                     -> CLC                      -> CLC
                     -> ADC #$40                 -> ADC B
                     -> STA SRC                  -> STA C

        SBB SRC #$80 -> LDA SRC       SBB A B C  -> LDA A
                     -> SEC                      -> SEC
                     -> SBC #$80                 -> SBC B
                     -> STA SRC                  -> STA C

  ``

  ### ADW, SBW

  W/w makro rozkazy realizują odpowiednio zwiększenie/zmniejszenie słowa pamięci z zapisaniem wyniku.

        ADW SRC #$40 -> CLC             ADW A B C  -> CLC
                     -> LDA SRC                    -> LDA A
                     -> ADC #$40                   -> ADC B
                     -> STA SRC                    -> STA C
                     -> SCC                        -> LDA A+1
                     -> INC SRC+1                  -> ADC B+1
                                                   -> STA C+1

        ADW SRC #$40 SRC -> CLC
                         -> LDA SRC
                         -> ADC #$40
                         -> STA SRC
                         -> LDA SRC+1
                         -> ADC #$00
                         -> STA SRC+1

        SBW SRC #$4080 -> SEC           SBW A B C  -> SEC
                       -> LDA SRC                  -> LDA A
                       -> SBC <$4080               -> SBC B
                       -> STA SRC                  -> STA C
                       -> LDA SRC+1                -> LDA A+1
                       -> SBC >$4080               -> SBC B+1
                       -> STA SRC+1                -> STA C+1

  ``

  ### PHR, PLR

  W/w makro rozkazy swoimi nazwami nawiązują do odpowiednich mnemoników `6502`, odpowiednio `PHA, PLA`, realizują odkładanie na stosie i zdejmowanie ze stosu rejestrów A,X,Y.

        PHR  -> PHA         PLR  -> PLA
             -> TXA              -> TAY
             -> PHA              -> PLA
             -> TYA              -> TAX
             -> PHA              -> PLA

  ``

  ### INW, INL, IND, DEW, DEL, DED

  Makro rozkazy INW, INL, IND realizują zwiększenie odpowiednio słowa pamięci (.WORD), długiego słowa pamięci (.LONG), podwójnego słowa pamięci (.DWORD).

  Makro rozkazy DEW, DEL, DED realizują zmniejszenie odpowiednio słowa pamięci (.WORD), długiego słowa pamięci (.LONG), podwójnego słowa pamięci (.DWORD) i wykorzystują w tym celu akumulator CPU (zawartość akumulatora ulega zmianie po wykonaniu makro rozkazów DEW, DEL, DED).

          inw dest  ->       inc dest    ->   inc dest
                    ->       bne skip    ->   sne
                    ->       inc dest+1  ->   inc dest+1
                    ->  skip             ->

          dew dest  ->       lda dest    ->   lda dest
                    ->       bne skip    ->   sne
                    ->       dec dest+1  ->   dec dest+1
                    ->  skip dec dest    ->   dec dest

  ``

  ### MVA, MVX, MVY

  Makro rozkazy MVA, MVX, MVY służą do przenoszenia bajtów (.BYTE) pamięci przy pomocy rejestrów CPU odpowiednio A, X, Y. Użycie opcji OPT R+ pozwala na potencjalne skrócenie kodu wynikowego dla następujących po sobie makro rozkazów MVA, MVX, MVY.

          lda src    ->  mva src dst
          sta dst    ->

          ldy $10,x  ->  mvy $10,x $a0,x
          sty $a0,x  ->

          ldx #$10   ->  mvx #$10 dst
          stx dst    ->

  ``

  ### MWA, MWX, MWY

  Makro rozkazy MWA, MWX, MWY służą do przenoszenia słów (.WORD) pamięci przy pomocy rejestrów CPU odpowiednio A, X, Y. Użycie opcji OPT R+ pozwala na potencjalne skrócenie kodu wynikowego dla następujących po sobie makro rozkazów MWA, MWX, MWY.

          ldx <adr    ->  mwx #adr dst
          stx dst     ->
          ldx >adr    ->
          stx dst+1   ->

          mwa #0 $80  ->  lda #0           mwy #$3040 $80  ->  ldy <$3040
                      ->  sta $80                          ->  sty $80
                      ->  sta $81                          ->  ldy >$3040
                                                           ->  sty $81

          mwa ($80),y $a000,x  ->  lda ($80),y
                               ->  sta $a000,x
                               ->  iny
                               ->  lda ($80),y
                               ->  sta $a001,x

  ``

  ### CPB, CPW, CPL, CPD

  Makro rozkazy CPB, CPW, CPL, CPD realizują porównanie wartości odpowiednich typów, odpowiednio .BYTE, .WORD, .LONG, .DWORD.

       cpw temp #$4080
       bcc skip

       cpd v0 v1
       beq skip

  PSEUDO ROZKAZY

       IFT [.IF] expression
       ELS [.ELSE]
       ELI [.ELSEIF] expression
       EIF [.ENDIF]

       ERT ERT 'string'["string"] | ERT expression

       label EQU expression
       label  =  expression

       label SET expression

       label EXT type

       OPT [bcfhlmorst][+-]
       ORG [[expression]]address[,address2]
       INS 'filename'["filename"][*][+-value][,+-ofset[,length]]
       ICL 'filename'["filename"]
       DTA [abfghltvmer](value1,value2...)[(value1,value2...)]

       DTA [cd]'string'["string"]
       RUN expression
       INI expression
       END [.EN]

       SIN (centre,amp,size[,first,last])
       COS (centre,amp,size[,first,last])

       RND (min,max,length)

       :repeat

       BLK N[one] X
       BLK D[os] X
       BLK S[parta] X
       BLK R[eloc] M[ain]|E[xtended]
       BLK E[mpty] X M[ain]|E[xtended]
       BLK U[pdate] S[ymbols]
       BLK U[pdate] E[xternal]
       BLK U[pdate] A[dress]
       BLK U[pdate] N[ew] X 'string'

       label SMB 'string'

       NMB
       RMB
       LMB #expression

  Czyli w większości po staremu, chociaż parę zmian zaszło. W przypadku cudzysłowów można używać `' '` lub `" "`. Oba rodzaje cudzysłowów traktowane są jednakowo z wyjątkiem adresowania (dla `''` zostanie wyliczona wartość ATASCII znaku, dla `""` zostanie wyliczona wartość INTERNAL znaku).

  ``

  ### BLK

       BLK N[one] X                    - blok bez nagłówków, licznik programu ustawiany na X

       BLK D[os] X                     - blok DOS-a z nagłówkiem $FFFF lub bez nagłówka gdy
                                         poprzedni taki sam, licznik programu ustawiany na X

       BLK S[parta] X                  - blok o stałych adresach ładowania z nagłówkiem $FFFA,
                                         licznik programu ustawiany na X

       BLK R[eloc] M[ain]|E[xtended]   - blok relokowalny umieszczany w pamięci MAIN lub EXTENDED

       BLK E[mpty] X M[ain]|E[xtended] - blok relokowalny rezerwujący X bajtów w pamięci MAIN lub EXTENDED
                                         UWAGA: licznik programu jest natychmiastowo zwiększany o X bajtów

       BLK U[pdate] S[ymbols]          - blok aktualizujący w poprzednich blokach SPARTA lub
                                         RELOC adresy symboli SDX

       BLK U[pdate] E[xternal]         - blok aktualizujący adresy etykiet external (nagłówek $FFEE)
                                         UWAGA: nie dotyczy Sparta DOS X, jest to rozszerzenie MADS-a

       BLK U[pdate] A[dress]           - blok aktualizacji adresów w blokach RELOC

       BLK U[pdate] N[ew] X 'string'   - blok deklarujący nowy symbol 'string' w bloku RELOC
                                         o adresie X. Gdy nazwa symbolu poprzedzona jest znakiem @,
                                         a adres jest z pamięci podstawowej to taki symbol może być
                                         wywoływany z command.com

  Więcej informacji na temat bloków w plikach `Sparta DOS X` w rozdziale Budowa plików SPARTA DOS X oraz Programowanie SPARTA DOS X.

  `

  ### label SET expression

  `

  Pseudorozkaz SET pozwala redefiniować etykietę, ma podobne działanie jak etykiety tymczasowe zaczynające się znakiem '?', np.:

      temp set 12

           lda #temp

      temp set 23

           lda #temp

  `

  ### label SMB 'string'

  `

  Deklaracja etykiety jako symbolu `SDX`. Symbol może mieć maksymalnie długość 8-iu znaków. Dzięki temu po użyciu `BLK UPDATE SYMBOLS` asembler wygeneruje poprawny blok aktualizacji symboli. Np:

             pf  smb 'PRINTF'
                 jsr pf
                 ...

  sprawi że po instrukcji `JSR` system `SDX` wstawi adres symbolu. `Uwaga:` deklaracja ta nie jest przechodnia, to znaczy że poniższy przykład spowoduje błędy w czasie kompilacji:

             cm  smb 'COMTAB'
             wp  equ cm-1       (błąd !)

                 sta wp

  Zamiast tego należy użyć:

             cm  smb 'COMTAB'

                 sta cm-1       (ok !)

  `Uwaga:` wszystkie deklaracje symboli należy użyć przed deklaracjami etykiet, jak i programem właściwym !

  ``

  ### :repeat

      Example:
                 :4 asl @
                 :2 dta a(*)
                 :256 dta #/8

      ladr :4 dta l(line:1)
      hadr :4 dta h(line:1)

  Znak `':'` określa liczbę powtórzeń linii (w przypadku makr określa numer parametru pod warunkiem że wartość liczbowa zapisana została w systemie decymalnym). Liczba powtórzeń powinna być z zakresu `<0..2147483647>`. W powtarzanej linii ':repeat' możliwe jest skorzystanie z licznika pętli - znaku hash '#' lub z parametru :1. Jeśli użyjemy znaku `':'` w makrze w znaczeniu liczby powtórzeń linii, np.:

      .macro test
       :2 lsr @
      .endm

  Wówczas dla w/w przykładu znak `':'` zostanie zinterpretowany jako drugi parametr makra. Aby zapobiec takiej interpretacji przez `MADS`, należy po znaku dwukropka `':'` umieścić znak który nic nie robi, np. znak plusa `'+'`.

      .macro test
       :+2 lsr @
      .endm

  Teraz znak dwukropka `':'` zostanie prawidłowo zinterpretowany jako :repeat

  `

  ### OPT

  ` Pseudo rozkaz `OPT` pozwala włączać/wyłączać dodatkowe opcje podczas asemblacji.

       b+  bank sensitive on
       b-  bank sensitive off                                               (default)
       c+  włącza obsługę CPU 65816 (16bit)
       c-  włącza obsługę CPU 6502 (8bit)                                   (default)
       f+  plik wynikowy w postaci jednego bloku (przydatne dla carta)
       f-  plik wynikowy w postaci blokowej                                 (default)
       h+  zapisuje nagłówek pliku dla DOS                                  (default)
       h-  nie zapisuje nagłówka pliku dla DOS
       l+  zapisuje listing do pliku (LST)
       l-  nie zapisuje listingu (LST)                                      (default)
       m+  zapisuje całe makra w listingu
       m-  zapisuje w listingu tylko tą część makra która zostaje wykonana  (default)
       o+  zapisuje wynik asemblacji do pliku wynikowego (OBX)              (default)
       o-  nie zapisuje wyniku asemblacji do pliku wynikowego (OBX)
       r+  optymalizacja długości kodu dla MVA, MVX, MVY, MWA, MWX, MWY
       r-  bez optymalizacji długości kodu dla MVA, MVX, MVY, MWA, MWX, MWY (default)
       s+  drukuje listing na ekranie
       s-  nie drukuje listingu na ekranie                                  (default)
       t+  track SEP REP on (CPU 65816)
       t-  track SEP REP off (CPU 65816)                                    (default)
       ?+  etykiety ze znakiem '?' na początku są lokalne (styl MAE)
       ?-  etykiety ze znakiem '?' na początku są tymczasowe                (default)

      Example:

       OPT c+ c  - l  + s +
       OPT h-
       OPT o +

  Wszystkie opcje `OPT` możemy używać w dowolnym miejscu listingu, czyli np. możemy włączyć zapis listingu w linii 12, a w linii 20 wyłączyć itd., wówczas plik z listingiem będzie zawierał tylko linie 12..20.

  Jeśli chcemy użyć trybów adresowania `65816`, musimy o tym poinformować asembler przez `'OPT C+'`.

  Jeśli używamy CodeGenie możemy użyć `'OPT S+'`, dzięki temu nie musimy przechodzić do pliku z listingiem, bo listing wydrukowany został w dolnym okienku (Output Bar).

  `

  ### ORG

  ` Pseudo rozkaz `ORG` ustawia nowy adres asemblacji, a więc i lokalizację zasemblowanych danych w pamięci `RAM`.

       adr                 asembluj od adresu ADR, ustaw adres w nagłówku pliku na ADR
       adr,adr2            asembluj od adresu ADR, ustaw adres w nagłówku pliku na ADR2
       [b($ff,$fe)]        zmień nagłówek na $FFFE (zostaną wygenerowane 2 bajty)
       [$ff,$fe],adr       zmień nagłówek na $FFFE, ustaw adres w nagłówku pliku na ADR
       [$d0,$fe],adr,adr2  zmień nagłówek na $D0FE, asembluj od adresu ADR, ustaw adres w nagłówku pliku na ADR2
       [a($FFFA)],adr      nagłówek SpartaDOS $FAFF, ustaw adres w nagłówku pliku na ADR

      Example:

       opt h-
       ORG [a($ffff),d'atari',c'ble',20,30,40],adr,adr2

  Nawiasy kwadratowe `[ ]` służą określeniu nowego nagłówka, który może być dowolnej długości. Pozostałe wartości za zamykającym nawiasem kwadratowym `']'`, rozdzielone znakiem przecinka `','` oznaczają odpowiednio: adres asemblacji, adres w nagłówku pliku.

  Przykład nagłówka dla pliku w postaci jednego bloku, asemblowanego od adresu $2000, w nagłówku podany adres początkowy i adres końcowy bloku.

      Example:

       opt h-f+
       ORG [a(start), a(over-1)],$2000

      start
       nop
       .ds 128
       nop
      over

  `

  ### INS 'filename'["filename"][*][+-value][,+-ofset[,length]]

  `

  Pseudo rozkaz `INS` pozwala na dołączenie dodatkowego pliku binarnego. Dołączany plik nie musi znajdować się w tym samym katalogu co główny asemblowany plik. Wystarczy, że odpowiednio wskazaliśmy `MADS-owi` ścieżki poszukiwań za pomocą przełącznika `/i` (patrz Przełączniki assemblera).

  Dodatkowo można przeprowadzić na dołączanym pliku binarnym operacje:

      *          invers bajtów pliku binarnego
      +-VALUE    zwiększenie/zmniejszenie wartości bajtów pliku binarnego o wartość wyrażenia VALUE

      +OFSET     ominięcie OFSET bajtów z początku pliku binarnego (SEEK OFSET)
      -OFSET     odczyt pliku binarnego od jego końca              (SEEK FileLength-OFSET)

      LENGTH     odczyt LENGTH bajtów pliku binarnego

  Jeśli wartość `LENGTH` nie została określona, domyślnie plik binarny zostanie odczytany aż do końca.

  `

  ### ICL 'filename'["filename"]

  `

  Pseudo rozkaz `ICL` pozwala na dołączenie dodatkowego pliku źródłowego i jego asemblację. Dołączany plik nie musi znajdować się w tym samym katalogu co główny asemblowany plik. Wystarczy, że odpowiednio wskazaliśmy `MADS-owi` ścieżki poszukiwań za pomocą przełącznika `/i` (patrz Przełączniki assemblera).

  `

  ### DTA

  ` Pseudo rozkaz `DTA` służy do definicji danych określonego typu. Jeśli typ nie został określony wówczas domyślnie zostanie ustawiony typ BYTE (b).

         b   wartość typu BYTE
         a   wartość typu WORD
         v   wartość typu WORD, relokowalna
         l   młodszy bajt wartości (BYTE)
         h   starszy bajt wartości (BYTE)
         m   najstarszy bajt wartości LONG (24bit)
         g   najstarszy bajt wartości DWORD (32bit)
         t   wartość typu LONG (24bit)
         e   wartość typu LONG (24bit)
         f   wartość typu DWORD (32bit)
         r   wartość typu DWORD w odróconej kolejności (32 bit)
         c   ciąg znaków ATASCII ograniczony apostrofami '' lub "", znak * na końcu spowoduje
             invers wartości ciągu, np. dta c'abecadlo'*
         d   ciąg znaków INTERNAL ograniczony apostrofami '' lub "", znak * na końcu spowoduje
             invers wartości ciągu, np. dta d'abecadlo'*

      Example:

        dta 1 , 2, 4
        dta a ($2320 ,$4444)
        dta d'sasasa', 4,a ( 200 ), h($4000)
        dta  c  'file' , $9b
        dta c'invers'*

  `

  ### SIN(centre,amp,size[,first,last])

  `

      where:

      centre     is a number which is added to every sine value
      amp        is the sine amplitude
      size       is the sine period
      first,last define range of values in the table. They are optional.
                 Default are 0,size-1.

      Example: dta a(sin(0,1000,256,0,63))
               defines table of 64 words representing a quarter of sine with
               amplitude of 1000.

  `

  ### COS(centre,amp,size[,first,last])

  `

      where:

      centre     is a number which is added to every cosine value
      amp        is the cosine amplitude
      size       is the cosine period
      first,last define range of values in the table. They are optional.
                 Default are 0,size-1.

      Example: dta a(cos(0,1000,256,0,63))
               defines table of 64 words representing a quarter of cosine with
               amplitude of 1000.

  ``

  ### RND(min,max,length)

  Ten pseudo rozkaz umożliwia wygenerowanie `LENGTH` losowych wartości z przedziału `<MIN..MAX>`.

      Example: dta b(rnd(0,33,256))

  `

  ### IFT, ELS, ELI, EIF

  `

       IFT [.IF] expression
       ELS [.ELSE]
       ELI [.ELSEIF] expression
       EIF [.ENDIF]

  W/w pseudo rozkazy i dyrektywy wpływają na przebieg asemblacji (można ich używać zamiennie).

  DYREKTYWY

       .A8, .A16, .AI8, .AI16
       .I8, .I16, .IA8, .IA16

       .ASIZE
       .ISIZE

       .ALIGN N[,fill]

       .ARRAY label [elements0][elements1][...] .type [= init_value]
       .ENDA, [.AEND]

       .DEF label [= expression]

       .DEFINE macro_name expression
       .UNDEF macro_name

       .ENUM label
       .ENDE, [.EEND]

       .ERROR [ERT] 'string'["string"] lub .ERROR [ERT] expression

       .EXTRN label [,label2,...] type

       .IF [IFT] expression
       .ELSE [ELS]
       .ELSEIF [ELI] expression
       .ENDIF [EIF]

       .IFDEF label
       .IFNDEF label

       .LOCAL label
       .ENDL, [.LEND]

       .LONGA ON|OFF
       .LONGI ON|OFF

       .LINK 'filename'

       .MACRO label
       .ENDM, [.MEND]
       :[%%]parameter
       .EXITM [.EXIT]

       .NOWARN

       .PRINT [.ECHO] 'string1','string2'...,value1,value2,...

       .PAGES [expression]
       .ENDPG, [.PGEND]

       .PUBLIC, [.GLOBAL], [.GLOBL] label [,label2,...]

       .PROC label
       .ENDP, [.PEND]
       .REG, .VAR

       .REPT expression [,parameter1, parameter2, ...]
       .ENDR, [.REND]
       .R

       .RELOC [.BYTE|.WORD]

       .STRUCT label
       .ENDS, [.SEND]

       .SYMBOL label

       .SEGDEF label address length [bank]
       .SEGMENT label
       .ENDSEG

       .USING, [.USE] proc_name, local_name

       .VAR var1[=value],var2[=value]... (.BYTE|.WORD|.LONG|.DWORD)
       .ZPVAR var1, var2... (.BYTE|.WORD|.LONG|.DWORD)

       .END

       .EN

       .BYTE
       .WORD
       .LONG
       .DWORD

       .OR
       .AND
       .XOR
       .NOT

       .LO (expression)
       .HI (expression)

       .DBYTE words
       .DS expression

       .BY [+byte] bytes and/or ASCII
       .WO words
       .HE hex bytes
       .SB [+byte] bytes and/or ASCII
       .CB [+byte] bytes and/or ASCII
       .FL floating point numbers

       .ADR label
       .LEN label ['filename']

       .SIZEOF label
       .FILESIZE 'filename'
       .FILEEXISTS 'filename'

       .GET [index] 'filename'["filename"][*][+-value][,+-ofset[,length]]
       .WGET [index]
       .LGET [index]
       .DGET [index]
       .PUT [index] = value
       .SAV [index] ['filename',] length

  `

  ### .SYMBOL label

  `

  Dyrektywa .SYMBOL to odpowiednik pseudo rozkazu SMB z tą różnicą że nie trzeba podawać symbolu, symbolem jest etykieta label. Dyrektywę .SYMBOL można umieszczać w dowolnym miejscu bloku relokowalnego SDX (BLK RELOC) w przeciwieństwie do SMB.

  Jeśli wystąpiła dyrektywa .SYMBOL zostanie wygenerowany odpowiedni blok aktualizacji:

      BLK UPDATE NEW LABEL 'LABEL'

  Więcej na temat deklaracji symboli SDX w rozdziale Definiowanie symbolu SMB.

  ``

  ### .ALIGN N [,fill]

  Dyrektywa .ALIGN pozwala wyrównać adres asemblacji do zadanej wartości N, oraz potencjalnie wypełnić pamięć zadaną wartością FILL. Możliwe jest wyrównanie adresu asemblacji dla kodu relokowalnego pod warunkiem że podamy wartość wypełnienia pamięci FILL.

  Domyślne wartości to: N=$0100, FILL=0.

      Example:

       .align

       .align $400

       .align $100,$ff

  ``

  ### .REPT expression [,parameter1, parameter2, ...]

  Dyrektywa `REPT` jest rozwinięciem :repeat z tą różnicą, że nie jest powtarzana jedna linia, tylko zaznaczony blok programu. Początek bloku definiowany jest dyrektywą `.REPT`, po niej musi wystąpić wartość lub wyrażenie arytmetyczne określające liczbę powtórzeń z zakresu `<0..2147483647>`, po liczbie powtórzeń opcjonalnie mogą wystąpić parametry. W przeciwieństwie do makr parametry dla .REPT zawsze są najpierw obliczane i dopiero ich wynik jest podstawiany (tą właściwość można wykorzystać do definiowania nowych etykiet). Z parametrów w bloku .REPT korzystamy podobnie jak z parametrów w bloku .MACRO. Koniec bloku .REPT definiuje dyrektywa `.ENDR`, przed którą nie powinna znajdować się żadna etykieta. Dodatkowo w obszarze bloku oznaczonego przez .REPT i .ENDR mamy możliwość skorzystania ze znaku hash '#' (lub dyrektywy .R), który zwraca aktualną wartość licznika pętli `.REPT` (podobnie jak dla :repeat).

      Example:

       .rept 12, #*2, #*3        ; bloki .REPT możemy łączyć z :rept
       :+4 dta :1                ; :+4 aby odróżnić licznik powtórzeń od parametru :4
       :+4 dta :2
       .endr

       .rept 9, #                ; definiujemy 9 etykiet label0..label8
      label:1 mva #0 $d012+#
       .endr

  ``

  ### .PAGES [expression]

  Dyrektywa `.PAGES` pozwala określić liczbę stron pamięci w których powinien zmieścić się nasz fragment kodu ograniczony przez <.PAGES .. .ENDPG> (domyślnie jest to wartość 1). Jeśli kod programu przekroczy zadeklarowaną liczbę stron pamięci wówczas zostanie wygenerowany komunikat błędu `Page error at ????`.

  Dyrektywy te mogą nam pomóc gdy zależy nam aby fragment programu mieścił się w granicach jednej strony pamięci albo gdy piszemy program mieszczący się w dodatkowym banku pamięci (64 strony pamięci), np.:

      Example:

       org $4000

       .pages $40
        ...
        ...
       .endpg

  `

  ### .SEGDEF label address length [attrib] [bank]
  .SEGMENT label
  .ENDSEG

  `

  Dyrektywa .SEGDEF definiuje nowy segment LABEL o adresie początkowym ADDRESS i długości LENGTH, dodatkowo możliwe jest określenie atrybutu dla segmentu (R-read, W-rite, RW-ReadWrite - domyślnie) oraz przypisanie numeru wirtualnego banku BANK (domyślnie BANK=0).

  Dyrektywa .SEGMENT aktywuje zapis kodu wynikowego segmentu LABEL. W przypadku przekroczenia zadanej długości segmentu zostanie wygenerowany komunikat błędu `Segment LABEL error at ADDRESS`.

  Dyrektywa .ENDSEG kończy zapis do aktualnego segmentu, przywraca zapis do głównego bloku programu.

      Example:

      	.segdef sdata adr0 $100
      	.segdef test  adr1 $40

      	org $2000

      	nop

      	.cb 'ALA'

      	.segment sdata

      	nop

      	.endseg

      	lda #0

      	.segment test
      	ldx #0
      	clc

      	dta c'ATARI'

      	.endseg

      adr0	.ds $100
      adr1	.ds $40

  ``

  ### .END

  Dyrektywa `.END` może być zamiennie używana z dyrektywami `.ENDP`, `.ENDM`, `.ENDS`, `.ENDA`, `.ENDL`, `.ENDR`, `.ENDPG`, `.ENDW`, `.ENDT`

  ``

  ### .VAR var1[=value1],var2[=value2]... (.BYTE|.WORD|.LONG|.DWORD) [=address]

  Dyrektywa `.VAR` służy do deklaracji i inicjacji zmiennych w głównym bloku programu oraz w blokach .PROC i .LOCAL. MADS nie wykorzystuje informacji na temat takich zmiennych w dalszych operacjach z udziałem pseudo i makro rozkazów. Dopuszczalne typy zmiennych to .BYTE, .WORD, .LONG, .DWORD i ich wielokrotności, a także typy zadeklarowane przez .STRUCT i .ENUM np.:

      Example:

       .var a,b , c,d   .word          ; 4 zmienne typu .WORD
       .var a,b,f  :256 .byte          ; 3 zmienne każda o wielkości 256 bajtów
       .var c=5,d=2,f=$123344 .dword   ; 3 zmienne .DWORD o wartościach 5, 2, $123344

       .var .byte i=1, j=3             ; 2 zmienne typu .BYTE o wartościach 1, 3

       .var a,b,c,d .byte = $a000      ; 4 zmienne typu .BYTE o adresach kolejno $A000, $A001, $A002, $A003

       .var .byte a,b,c,d = $a0        ; 4 zmienne typu bajt, ostatnia zmiennna 'D' o wartości $A0
                                       ; !!! dla takiego zapisu nie ma możliwości określenia adresu alokacji zmiennych

        .proc name
        .var .word p1,p2,p3            ; deklaracja trzech zmiennych typu .WORD
        .endp

       .local
        .var a,b,c .byte
        lda a
        ldx b
        ldy c
       .endl

       .struct Point                   ; nowy typ danych strukturalnych POINT
       x .byte
       y .byte
       .ends

        .var a,b Point                 ; deklaracja zmiennych strukturalnych
        .var Point c,d                 ; odpowiednik składni 'label DTA POINT'

  Tak zadeklarowane zmienne zostaną fizycznie alokowane dopiero na końcu bloku w którym zostały zadeklarowane, po dyrektywie .ENDP, .ENDL (.END). Wyjątek stanowi blok .PROC gdzie zmienne zadeklarowane przez .VAR zawsze alokowane są przed dyrektywą .ENDP niezależnie czy w bloku procedury wystąpiły jakiekolwiek dodatkowe bloki .LOCAL ze zmiennymi deklarowanymi przez .VAR

  ``

  ### .ZPVAR var1, var2... (.BYTE|.WORD|.LONG|.DWORD) [=address]

  Dyrektywa `.ZPVAR` służy do deklaracji zmiennych strony zerowej w głównym bloku programu oraz w blokach .PROC i .LOCAL. Próba przypisania wartości (zaincjowania) takiej zmiennej spowoduje wygenerowanie komunikatu ostrzeżenia Uninitialized variable. MADS nie wykorzystuje informacji na temat takich zmiennych w dalszych operacjach z udziałem pseudo i makro rozkazów. Dopuszczalne typy zmiennych to .BYTE, .WORD, .LONG, .DWORD i ich wielokrotności, a także typy zadeklarowane przez .STRUCT i .ENUM np.:

      Example:

       .zpvar a b c d  .word = $80    ; 4 zmienne typu .WORD o adresie początkowym $0080
       .zpvar i j .byte               ; dwie kolejne zmienne od adresu $0080+8

       .zpvar .word a,b               ; 2 zmienne typu .WORD
                                      ; !!! dla takiej składni nie ma możliwości określenia adresu zmiennych

       .struct Point                  ; nowy typ danych strukturalnych POINT
       x .byte
       y .byte
       .ends

        .zpvar a,b Point              ; deklaracja zmiennych strukturalnych
        .zpvar Point c,d              ; odpowiednik składni 'label DTA POINT'

  Tak zadeklarowanym zmiennym strony zerowej zostaną przypisane adresy dopiero na końcu bloku w którym zostały zadeklarowane, po dyrektywie .ENDP, .ENDL (.END). Wyjątek stanowi blok .PROC gdzie zmiennym zadeklarowanym przez .ZPVAR adresy przypisywane są przed dyrektywą .ENDP niezależnie czy w bloku procedury wystąpiły jakiekolwiek dodatkowe bloki .LOCAL ze zmiennymi deklarowanymi przez .ZPVAR.

  Przy pierwszym użyciu dyrektywy .ZPVAR należy zaincjować adres jaki będzie przypisywany kolejnym zmiennym (domyślnym adresem jest $0080).

      Example:

       .zpvar = $40

  Z każdą kolejną zmienną adres ten jest automatycznie zwiększany przez MADS-a, w przypadku gdy adresy zmiennych powtórzą się zostanie wygenerowany komunikat ostrzeżenia Access violations at address $xxxx. W przypadku przekroczenia zakresu strony zerowej zostaje wygenerowany komunikat błędu Value out of range.

  ``

  ### .PRINT [.ECHO]

  Powoduje wypisanie na ekranie podanej jako parametr wartości wyrażenia lub ciągu znakowego ograniczonego apostrofami `' '` lub `" "`, np.:

      Example:

       .print "End: ",*,'..',$8000-*
       .echo "End: ",*,'..',$8000-*

  `

  ### .ERROR

  ` [ERT] 'string'["string"] | .ERROR [ERT] expression Dyrektywa `.ERROR` i pseudo rozkaz `ERT` mają to samo znaczenie. Zatrzymują asemblację programu oraz wyświetlają komunikat podany jako parametr, ograniczony apostrofami `' '` lub `" "`. Jeśli parametrem jest wyrażenie logiczne, wówczas asemblacja zostanie zatrzymana gdy wartość wyrażenia logicznego jest prawdą (komunikat `User error`), np.:

      Example:

       ert "halt"            ; ERROR: halt
       .error "halt"

       ert *>$7fff           ; ERROR: User error
       .error *>$7fff

  `

  ### .BYTE, .WORD, .LONG, .DWORD

  ` W/w dyrektywy służą do oznaczenia dopuszczalnych typów parametrów w deklaracji parametrów procedury `(.BYTE, .WORD, .LONG, .DWORD)`. Możliwe jest także ich użycie w celu definicji danych, w zastępstwie pseudo rozkazu `DTA`.

      Example:

      .proc test (.word tmp,a,b .byte value)

       .byte "atari",5,22
       .word 12,$FFFF
       .long $34518F
       .dword $11223344

  ``

  ### .DBYTE

  Definicja danych typu `WORD` w odwrotnej kolejności tzn. najpierw starszy bajt, następnie młodszy bajt.

      Example:

      .DBYTE $1234,-1,1     ; 12 34 FF FF 00 01

  ``

  ### [label] .DS expression | label .DS [elements0][elements1][...] .type

  Ta dyrektywa zapożyczona została z `MAC'65`, pozwala zarezerwować pamięć bez jej uprzedniej inicjalizacji. Jest to odpowiednik pseudo rozkazu `ORG *+expression`. Dyrektywy .DS nie można używać w kodzie relokowalnym podobnie jak ORG-a.

  Użycie nawiasów kwadratowych w wyrażeniu umożliwia rezerwowanie pamięci jako tablicy, podobnie jak .ARRAY, wymagane jest wówczas podanie etykiety. Użycie dyrektywy .DS w bloku relokowalnym Sparta DOS X wymusi utworzenie bloku pustego 'blk empty'.

      purpose: reserves space for data without initializing then space to any particular value(s).

      usage: [label] .DS expression
             label .DS [elements0][elements1][...] .TYPE

      Using ".DS expression" is exactly equivalent of using "ORG *+expression". That is, the label
      (if it is given) is set equal to the current value of the location counter. Then then value
      of the expression is added to then location counter.

      Example: BUFFERLEN .DS 1     ;reserve a single byte
               BUFFER   .DS [256]  ;reserve 256 bytes as array [0..255]

  ``

  ### .BY [+byte] bytes and/or ASCII

  Store byte values in memory. ASCII strings can be specified by enclosing the string in either single or double quotes.

  If the first character of the operand field is a '+', then the following byte will be used as a constant and added to all remaining bytes of the instruction.

      Example:
            .BY +$80 1 10 $10 'Hello' $9B

      will generate:
              81 8A 90 C8 E5 EC EC EF 1B

  Values in .BY statements may also be separated with commas for compatibility with other assemblers. Spaces are allowed since they are easier to type.

  ``

  ### .WO words

  Stores words in memory. Multiple words can be entered.
  Values in .WO statements may also be separated with commas for compatibility with other assemblers. Spaces are allowed since they are easier to type.

  ``

  ### .HE hex bytes

  Store hex bytes in memory. This is a convenient method to enter strings of hex bytes, since it does not require the use of the '$' character. The bytes are still separated by spaces however, which I feel makes a much more readable layout than the 'all run together' form of hex statement that some other assemblers use.

  Example: .HE 0 55 AA FF

  Values in .HE statements may also be separated with commas for compatibility with other assemblers. Spaces are allowed since they are easier to type.

  ``

  ### .SB [+byte] bytes and/or ASCII

  This is in the same format as the .BY pseudo-op, except that it will convert all bytes into ATASCII screen codes before storing them. The ATASCII conversion is done before any constant is added with the '+' modifier.
  Values in .SB statements may also be separated with commas for compatibility with other assemblers. Spaces are allowed since they are easier to type.

  ``

  ### .CB [+byte] bytes and/or ASCII

  This is in the same format as the .BY pseudo-op, except that the last character on the line will be EOR'ed with $80.
  Values in .CB statements may also be separated with commas for compatibility with other assemblers. Spaces are allowed since they are easier to type.

  ``

  ### .FL floating point numbers

  Stores 6-byte BCD floating point numbers for use with the OS FP ROM routines.
  Values in .FL statements may also be separated with commas for compatibility with other assemblers. Spaces are allowed since they are easier to type.

  ``

  ### .EN

  Dyrektywa .EN jest odpowiednikiem pseudo rozkazu END, oznacza koniec asemblowanego bloku programu.

  This is an optional pseudo-op to mark the end of assembly. It can be placed before the end of your source file to prevent a portion of it from being assembled.

  ``

  ### .ADR label

  Dyrektywa .ADR zwraca wartość etykiety LABEL przed zmianą adresu asemblacji (możliwe jest umieszczenie nazwy etykiety LABEL pomiędzy nawiasami okrągłymi lub kwadratowymi), np.:

       org $2000

      .proc tb,$1000
      tmp lda #0
      .endp

       lda .adr tb.tmp  ; = $2000
       lda tb.tmp       ; = $1000

  ``

  ### .LEN label ['filename'], .SIZEOF label, .FILESIZE 'filename'

  Dyrektywa .LEN zwraca długość (wyrażoną w bajtach) bloku .PROC, .ARRAY, .LOCAL, .STRUCT lub długość pliku o nazwie 'filename'. Etykieta LABEL to nazwa bloku .PROC, .ARRAY, .LOCAL lub .STRUCT (możliwe jest umieszczenie nazwy etykiety LABEL pomiędzy nawiasami okrągłymi lub kwadratowymi), np.:

      label .array [255] .dword
            .enda

            dta a(.len label)   ; = $400

      .proc wait
       lda:cmp:req 20
       rts
      .endp

       dta .sizeof wait    ; = 7

  Dyrektywy .SIZEOF i .FILESIZE to alternatywne nazwy dla .LEN, można używać ich zamiennie zależnie od upodobań programującego.

  ``

  ### .FILEEXISTS 'filename'

  Dyrektywa .FILEEXISTS zwraca '1' gdy plik 'filename' istnieje w przeciwnym wypadku zwraca wartość '0' np.:

       ift .fileexists 'filename'
       .print 'true'
       els
       .print 'false'
       eif

  `

  ### .DEFINE macro_name expression

  ` Dyrektywa .DEFINE pozwala zdefiniować jedno-liniowe makro MACRO_NAME. Dopuszczalnych jest dziewięć parametrów %%1.%%9 (:1..:9) reprezentowanych w ten sam sposób jak dla makr .MACRO, poprzez znaki '%%' lub znak ':'. Nazwy literowe parametrów nie są akceptowane, nie ma możliwości użycia znaku podziału linii '\'.

       .define poke mva #%%2 %%1

       poke(712, 100)

  Makro jedno-liniowe .DEFINE można wielokrotnie definiować w trakcie jednego przebiegu asemblacji.

       .define pisz %%1+%%2

       .print pisz(712, 100)

       .define pisz %%1-%%2

       .print pisz(712, 100)

  `

  ### .UNDEF macro_name

  ` Dyrektywa .UNDEF usuwa definicję jedno-liniowego makra MACRO_NAME.

       .define poke mva #%%2 %%1

       .undef poke

  `

  ### .DEF label [= expression]

  ` Dyrektywa .DEF pozwala sprawdzić obecność definicji etykiety `LABEL` lub ją zdefiniować. Jeśli etykieta została zdefiniowana zwraca wartość `1` czyli `TRUE`, w przeciwnym wypadku zwraca `0` czyli `FALSE`. Możliwe jest umieszczenie nazwy etykiety LABEL pomiędzy nawiasami okrągłymi lub kwadratowymi, np.:

       ift .not(.def label)
       .def label
       eif

  Definiowane etykiety są zasięgu aktualnego obszaru lokalnego, jeśli chcemy zdefiniować etykiety globalne stawiamy przed etykietą znak ':', np.

      .local test
       :10 .def :label%%1
      .endl

  This unary operator tests whether the following label has been defined yet, returning TRUE or FALSE as appropriate.

  CAUTION: Defining a label AFTER the use of a .DEF which references it can be dangerous, particularly if the .DEF is used in a .IF directive.

  `

  ### .IFDEF label

  ` Dyrektywa .IFDEF jest krótszym odpowiednikiem warunku .IF .DEF LABEL

      Example:

      .ifdef label
             jsr proc1
      .else
             jsr proc2
      .endif

  `

  ### .IFNDEF label

  ` Dyrektywa .IFNDEF jest krótszym odpowiednikiem warunku .IF .NOT .DEF LABEL

      Example:

      .ifndef label
            clc
      .else
            sec
      .endif

  Dla n/w przykładu asemblacja bloku .IFNDEF (.IF) będzie miała miejsce tylko w pierwszym przebiegu, jeśli umieścimy w takim bloku jakikolwiek kod programu na pewno nie zostanie on wygenerowany do pliku, definicje etykiet zostaną przeprowadzone tylko w pierwszym przebiegu, jeśli wystąpiły jakiekolwiek błędy związane z ich definiowaniem dowiemy się o nich dopiero w momencie próby odwołania do takich etykiet, będzie to komunikat błędu Undeclared label LABEL_NAME

       .ifndef label
       .def label
       lda #0               ; ten rozkaz nie zostanie zasemblowany, tylko ostatni przebieg asemblacji generuje kod
       temp = 100           ; etykieta TEMP zostanie zdefiniowana tylko w 1 przebiegu asemblacji
       .endif

  `

  ### .NOWARN

  ` Dyrektywa .NOWARN wyłącza komunikat ostrzeżenia dla aktualnie asemblowanego wiersza programu.

      Example:

      .nowarn .proc temp       ; nie zostanie wygenerowane ostrzeżenie 'Unreferenced procedure TEMP'
              .endp

  ``

  ### .USING, [.USE]

  Dyrektywa .USING (.USE) pozwala określić dodatkową ścieżkę poszukiwań dla nazw etykiet. Działanie .USING (.USE) obowiązuje w aktualnej przestrzeni nazw jak i kolejnych zawierających się w tej przestrzeni.

      Example:

      .local move

      tmp    lda #0
      hlp    sta $a000

      .local move2

      tmp2   ldx #0
      hlp2   stx $b000

      .endl

      .endl

      .local main

      .use move.move2

             lda tmp2

      .use move

             lda tmp

      .endl

  ``

  ### .GET [index] 'filename'... [.BYTE, .WORD, .LONG, .DWORD]

  `

  ### .WGET [index] | .LGET [index] | .DGET [index]

  ` `.GET` jest odpowiednikiem pseudo rozkazu `INS` (podobna składnia), z tą różnicą że plik nie jest dołączany do asemblowanego pliku tylko ładowany do pamięci `MADS-a`. Ta dyrektywa pozwala wczytać określony plik do pamięci `MADS-a` i odwoływać się do bajtów tego pliku jak do tablicy jednowymiarowej.

      Example:

       .get 'file'                    ; wczytanie pliku do tablicy MADS-a
       .get [5] 'file'                ; wczytanie pliku do tablicy MADS-a od indeksu = 5

       .get 'file',0,3                ; wczytanie do tablicy MADS-a 3-ech wartości

       lda #.get[7]                   ; odczytanie 7 bajtu z tablicy MADS-a
       adres = .get[2]+.get[3]<<8     ; 2 i 3 bajt w nagłówku pliku DOS zawiera informacje o adresie ładowania

       adres = .wget[2]              ; word
       tmp = .lget[5]                ; long
       ?x = .dget[11]                ; dword

  Przy pomocy dyrektyw `.GET, .PUT` można odczytać np moduł `Theta Music Composer (TMC)` i dokonać jego relokacji. Realizuje to załączone do `MADS-a` makro z katalogu `../EXAMPLES/MSX/TMC_PLAYER/tmc_relocator.mac`.

  Dopuszczalny zakres wartości dla `INDEX = <0..65535>`. Wartości odczytywane przez `.GET` są typu `BYTE`. Wartości odczytywane przez `.WGET` są typu `WORD`. Wartości odczytywane przez `.LGET` są typu `LONG`. Wartości odczytywane przez `.DGET` są typu `DWORD`.

  ``

  ### .PUT [index] = value

  Dyrektywa `.PUT` pozwala odwołać się do tablicy jednowymiarowej w pamięci `MADS-a` i zapisać w niej wartość typu `BYTE`. Jest to ta sama tablica do której dyrektywa `.GET` zapisuje plik.

  Dopuszczalny zakres wartości dla `INDEX = <0..65535>`.

      Example:

       .put [5] = 12       ; zapisanie wartosci 12 w talicy MADS-a na pozycji 5-ej

  ``

  ### .SAV [index] ['filename',] length

  Dyrektywa `.SAV` pozwala zapisać bufor używany przez dyrektywy `.GET`, `.PUT` do pliku zewnętrznego lub dołączenie do aktualnie asemblowanego.

      Example:

       .sav ?length            ; dołączenie do asemblowanego pliku zawartości bufora [0..?length-1]
       .sav [200] 256          ; dołączenie do asemblowanego pliku zawartości bufora [200..200+256-1]
       .sav [6] 'filename',32  ; zapisanie do pliku FILENAME zawartości bufora [6..6+32-1]

  Dopuszczalny zakres wartości dla `INDEX = <0..65535>`.

  ``

  ### .OR, .AND, .XOR, .NOT

  W/w dyrektywy to odpowiedniki operatorów logicznych `||` `(.OR)`, `&&` `(.AND)`, `^` `(.XOR)`, `!` `(.NOT)`.

  ``

  ### .LO (expression), .HI (expression)

  W/w dyrektywy to odpowiedniki operatorów odpowiednio '<' (młodszy bajt) i '>' (starszy bajt).
  `

  ### .IF, .ELSE, .ELSEIF, .ENDIF

  `

       .IF     [IFT] expression
       .ELSE   [ELS]
       .ELSEIF [ELI] expression
       .ENDIF  [EIF]

  W/w dyrektywy i pseudo rozkazy wpływają na przebieg asemblacji (można ich używać zamiennie), np.:

      Example:

       .IF .NOT .DEF label_name
         label_name = 1
       .ENDIF

       .IF [.NOT .DEF label_name] .AND [.NOT .DEF label_name2]
         label_name = 1
         label_name2 = 2
       .ENDIF

  W w/w przykładzie nawiasy (kwadratowe lub okrągłe) są koniecznością, ich brak spowodowałby że dla pierwszej dyrektywy `.DEF` parametrem byłaby nazwa etykiety `label_name.AND.NOT.DEFlabel_name2` (spacje są pomijane, a znak kropki akceptowany w nazwie etykiety).

  DYREKTYWY GENERUJĄCE KOD 6502

       #IF type expression [.OR type expression] [.AND type expression]
       #ELSE
       #END

       #WHILE type expression [.OR type expression] [.AND type expression]
       #END

       #CYCLE #N

  ``

  ### #IF type expression [.OR type expression] [.AND type expression]

  Dyrektywa #IF to skromniejszy odpowiednik instrukcji IF z języków wyższego poziomu (C, Pascal).

  Dyrektywy #IF, #ELSE i #END pozwalają na wygenerowanie kodu maszynowego CPU 6502 instrukcji warunkowej IF dla wyznaczonego bloku programu, możliwe jest ich zagnieżdżanie. Dopuszczalne są wszystkie typy .BYTE, .WORD, .LONG, .DWORD, możliwe jest łączenie większej ilości warunków przy pomocy dyrektyw .OR i .AND, nie ma możliwości określenia kolejności wartościowania poprzez nawiasy.

  Wykonanie dyrektywy #IF zaczyna się od obliczenia wartości wyrażenia prostego tzn. takiego które składa się z dwóch argumentów i jednego operatora (wyrażenia możemy łączyć dyrektywami .OR lub .AND).

  Jeżeli wyrażenie ma wartość różną od zera (TRUE), to zostanie wykonywany blok programu występujący po dyrektywie #IF. Blok takiego programu automatycznie kończony jest instrukcją 'JMP' realizującą skok do następnej instrukcji programu za dyrektywą #END w przypadku występowania bloku #ELSE.

  Jeżeli wyrażenie ma wartość zero (FALSE), to wykonywany jest kod programu występujący po dyrektywie #ELSE, jeśli dyrektywa #ELSE nie występuje sterowanie przekazywane jest do następnej instrukcji programu za dyrektywą #END, np.:

      #if .byte label>#10 .or .byte label<#5
      #end

      #if .byte label>#100

      #else

       #if .byte label<#200
       #end

      #end

      #if .byte label>#100 .and .byte label<#200 .or .word lab=temp
      #end

      #if .byte @
      #end

  ``

  ### #WHILE type expression [.OR type expression] [.AND type expression]

  Dyrektywa #WHILE jest odpowiednikiem instrukcji WHILE z języków wyższego poziomu (C, Pascal).

  Dyrektywy #WHILE i #END pozwalają na wygenerowanie kodu maszynowego CPU 6502 pętli dla wyznaczonego bloku programu, możliwe jest ich zagnieżdżanie. Dopuszczalne są wszystkie typy .BYTE, .WORD, .LONG, .DWORD, możliwe jest łączenie większej ilości warunków przy pomocy dyrektyw .OR i .AND, nie ma możliwości określenia kolejności wartościowania poprzez nawiasy.

  Sekwencja działań przy wykonywaniu dyrektywy #WHILE jest następująca:

  - 1. Oblicz wartość wyrażenia i sprawdź, czy jest równe zeru (FALSE).
    - jeżeli tak, to pomiń krok 2;
    - jeżeli nie (TRUE), przejdź do kroku 2.
  - 2. Wykonaj blok programu ograniczonego dyrektywami #WHILE i #END, następnie przejdź do kroku 1.

  Jeżeli pierwsze wartościowanie wyrażenia wykaże, że ma ono wartość zero, to blok programu nigdy nie zostanie wykonany i sterowanie przejdzie do następnej instrukcji programu za dyrektywą #END

      #while .byte label>#10 .or .byte label<#5
      #end

      #while .byte label>#100
       #while .byte label2<#200
       #end
      #end

      #while .byte label>#100 .and .byte label<#200 .or .word lab=temp
      #end

  Wersja krótka pętli #WHILE, trwa dopóki LABEL<>0

      #while .word label
      #end

  ``

  ### #CYCLE #N

  Dyrektywa #CYCLE pozwala wygenerować kod 6502 o zadanej liczbie cykli. Wygenerowany kod nie modyfikuje żadnej komórki pamięci, ani rejestru CPU, co najwyżej znaczniki.

      #cycle #17  ; pha      3 cycle
                  ; pla      4 cycle
                  ; pha      3 cycle
                  ; pla      4 cycle
                  ; cmp $00  3 cycle
                            ---------
                            17 cycle

  `

  ## Asemblacja na stronie zerowej

  `

  W przeciwieństwie do dwu-przebiegowych asemblerów takich jak `QA` i `XASM`, `MADS` jest wielo-przebiegowy. Co to daje ?

  Weźmy sobie taki przykład:

       org $00

       lda tmp+1

      tmp lda #$00

  Dwu-przebiegowy assembler nie znając wartości etykiety `TMP` przyjmie domyślnie, że jej wartość będzie dwu-bajtowa, czyli typu `WORD` i wygeneruje rozkaz `LDA W`.

  Natomiast `MADS` uprzejmie wygeneruje rozkaz strony zerowej `LDA Z`. I to właściwie główna i najprostsza do wytłumaczenia właściwość większej liczby przebiegów.

  Teraz ktoś powie, że woli gdy rozkaz odwołujący się do strony zerowej ma postać `LDA W`. Nie ma sprawy, wystarczy że rozszerzy mnemonik:

       org $00

       lda.w tmp+1

      tmp lda #$00

  Są dopuszczalne trzy rozszerzenia mnemonika

       .b[.z]
       .w[.a][.q]
       .l[.t]

  czyli odpowiednio `BYTE`, `WORD`, `LONG` `(TRIPLE)`. Z czego ostatni generuje 24bitową wartość i odnosi się do `65816` i pamięci o ciągłym obszarze (wątpię czy kiedykolwiek użyjecie taki rozkaz). Więcej informacji na temat mnemoników `CPU 6502, 65816` oraz ich dopuszczalnych rozszerzeń w rodziale Mnemoniki.

  Innym sposobem na wymuszenie rozkazu strony zerowej jest użycie nawiasów klamrowych `{ }` np.

       dta {lda $00},$80    ; lda $80

  W `MADS` możemy robić tak samo, ale po co, ostatni przebieg załatwi sprawę za nas :) Problem stanowi teraz umieszczenie takiego fragmentu kodu w pamięci komputera. Możemy spróbować załadować taki program bezpośrednio na stronę zerową i jeśli obszar docelowy mieści się w granicy `$80..$FF` to pewnie `OS` przeżyje, poniżej tego obszaru będzie trudniej.

  Dlatego `MADS` umożliwia takie coś:

       org $20,$3080

       lda tmp+1

      tmp lda #$00

  Czyli asembluj od adresu `$0020`, ale załaduj pod adres `$3080`. Oczywiście późniejsze przeniesienie kodu pod właściwy adres (w naszym przykładzie `$0020`) należy już do zadań programisty.

  Podsumowując:

       org adres1,adres2

  Asembluj od adresu `adres1`, umieść w pamięci od adresu `adres2`. Taki `ORG` zawsze spowoduje stworzenie nowego bloku w pliku, czyli zostaną zapisane dodatkowe cztery bajty nagłówka nowego bloku.

  Jeśli nie zależy nam na nowym adresie umiejscowienia danych w pamięci, adresem umiejscowienia danych ma być aktualny adres wówczas możemy skorzystać z właściwości bloków .LOCAL i .PROC, bajty nagłówka nie będą w takim przypadku zapisywane, np.:

           1
           2 					org $2000
           3
           4 FFFF> 2000-200D> A9 00		lda #0
           5 2002 EA				nop
           6
           7 0060			.local	temp, $60
           8
           9 0060 BD FF FF			lda $ffff,x
          10 0063 BE FF FF			ldx $ffff,y
          11
          12 				.endl
          13
          14 2009 A5 60			lda temp
          15 200B AD 03 20			lda .adr temp
          16

  Dla w/w przykładu blok programu TEMP zostanie zasemblowany z nowym adresem = $60 i umiejscowiony w pamięci pod adresem $2003. Po dyrektywie kończącej blok (.ENDL, .ENDP, .END) przywracamy jest adres asemblacji sprzed bloku plus jeszcze długość tak zasemblowanego bloku, w naszym przykładzie adresem od którego będzie kontynuowana asemblacja po zakończeniu bloku .LOCAL będzie adres $2009.

  Następnie wykorzystując dyrektywy .ADR i .LEN można dokonać skopiowania takiego bloku pod właściwy adres, np.:

            ldy #0
      copy  mva .adr(temp),y temp,y+
            cpy #.len temp
            bne copy

  Więcej informacji na temat działania dyrektyw .ADR i .LEN.

  TYPY

  MADS udostępnia możliwość deklaracji dwóch typów danych: strukturalne .STRUCT i wyliczeniowe .ENUM

  TYP STRUKTURALNY, STRUKTURY

  Jeśli programowaliście w `C`, to pewnie spotkaliście się już ze strukturami. Ogólnie w `MADS` struktura definiuje tablicę wirtualną, jednowymiarową o polach różnego typu `.BYTE`, `.WORD`, `.LONG`, `.DWORD` i ich wielokrotności. Wirtualna ponieważ istnieje ona jak na razie tylko w pamięci assemblera.

  Pola takiej struktury zawierają informację o ofsecie do początku struktury.

  `

  ## Deklaracja struktury (.STRUCT)

  `

  Struktur dotyczą n/w dyrektywy:

      name .STRUCT
           .STRUCT name
           .ENDS [.SEND] [.END]

  `

  ### name .STRUCT

  ` Deklaracja struktury `name` przy użyciu dyrektywy `.STRUCT`. Nazwa struktury jest wymagana i konieczna, jej brak wygeneruje błąd. Do nazw struktur nie można używać nazw mnemoników i pseudo rozkazów. Jeśli nazwa jest zarezerwowana wystąpi błąd z komunikatem `Reserved word`.

  Przykład deklaracji struktury:

      .STRUCT name

        x .word      ; lda #name.x = 0
        y .word      ; lda #name.y = 2
        z .long      ; lda #name.z = 4
        v .dword     ; lda #name.v = 7

        q :3 .byte   ; lda #name.q = 11

      .ENDS          ; lda #name   = 14 (length)

  Pola struktury definiujemy przez podanie nazwy i typu pola (.BYTE, .WORD, .LONG, .DWORD). Nazwa pola może być poprzedzona "białymi spacjami". W obszarze ograniczonym dyrektywami .STRUCT i .ENDS nie ma możliwości używania mnemoników CPU, jeśli je użyjemy lub użyjemy innych niedozwolonych znaków wystąpi błąd z komunikatem Improper syntax lub Illegal instruction.

  Podsumowując, etykieta `name` zawiera informację o całkowitej długości struktury (w bajtach). Pozostałe etykiety opisujące pola zawierają informację o ofsecie do początku struktury.

  Deklaracji struktur nie można zagnieżdżać, można zagnieżdżać wcześniej zadeklarowane struktury (kolejność wystąpienia w programie nie ma znaczenia), np.:

      .STRUCT temp

      x .word
      y .word
      v .byte
      z .word

      .ENDS

      .STRUCT test

      tmp  temp

      .ENDS

       lda #temp.v
       lda #test.tmp.x
       lda #test.tmp.z

  Do czego może przydać się struktura ?

  Przypuśćmy, że mamy jakąś tablicę z polami różnego typu, możemy odczytywać pola takiej tablicy przy pomocy z góry określonych wartości offsetów. Jednak gdy dodamy dodatkowe pole do tablicy, czy też zmodyfikujemy ją w inny sposób, będziemy zmuszeni poprawiać kod programu który posługiwał się z góry określonymi wartościami offsetów. Gdy zdefiniujemy taką tablicę przy pomocy struktury będziemy mogli odczytywać jej pola posługując się offsetami zapisanymi w deklaracji struktury, czyli zawsze odczytamy właściwe pole niezależnie od zmian jakie zaszły w tablicy.

  Inny przykład zastosowania struktur został opisany w rozdziale Symbole zewnętrzne, przykład zastosowania symboli external i struktur .STRUCT.

  `

  ## Definiowanie danych strukturalnych, odwołania

  `

  Definiowanie danych strukturalnych polega na przypisaniu nowej etykiecie konkretnej struktury z użyciem pseudo rozkazu `DTA` lub bez tego pseudo rozkazu. Wynikiem takiego przypisania jest zarezerwowana pamięć, nie jest to już twór wirtualny.

      label DTA struct_name [count] (data1,data2,data3...) (data1,data2,data3...) ...

      label struct_name

  `COUNT` określa liczbę z przedziału `<0..COUNT>`, która definiuje maksymalną wartość indeksu tablicy jednowymiarowej, a przez to także liczbę odłożonych w pamięci danych typu strukturalnego.

  Przykład deklaracji struktury i definicji danych strukturalnych:

      ;----------------------;
      ; deklaracja struktury ;
      ;----------------------;
      .STRUCT temp

      x .word
      y .word
      v .byte
      z .word

      .ENDS

      ;---------------------;
      ; definiowanie danych ;
      ;---------------------;

      data dta temp [12] (1,20,200,32000) (19,2,122,42700)

      data2 dta temp [0]

      data3 temp          // krótszy odpowiednik DATA2

  Po nazwie struktury w nawiasie kwadratowym musi znajdować się wartość z przedziału `<0..2147483647>`, która definiuje maksymalną wartość indeksu tablicy jednowymiarowej, a jednocześnie liczbę odłożonych w pamięci danych typu strukturalnego.

  Po nawiasie kwadratowym może wystąpić opcjonalnie lista wartości początkowych (ograniczona nawiasami okrągłymi), jeśli nie wystąpi wówczas domyślnymi wartościami pól struktury są zera. Z kolei jeśli lista wartości początkowych jest mniejsza od liczby pól zadeklarowanych, wówczas pozostałe pola inicjowane są ostatnimi wartościami jakie zostały podane, np.

      data dta temp [12] (1,20,200,32000)

  Taka deklaracja spowoduje, że wszystkie pola zostaną zaincjowane wartościami `1,20,200,32000`, a nie tylko pierwsze pole `data[0]`.

  Jeśli lista wartości początkowych będzie większa lub mniejsza od liczby pól struktury, wówczas wystąpi błąd z komunikatem `Constant expression violates subrange bounds`.

  Aby odwołać się do pól tak nowo powstałych danych należy podać ich nazwę, koniecznie indeks w nawiasie kwadratowym i nazwę pola po kropce, np.:

       lda data[4].y
       ldx #data[0].v

  Brak nawiasu kwadratowego z indeksem label[index] zakończy się komunikatem błędu `Undeclared label`.

  TYP WYLICZENIOWY, WYLICZENIA

  Wyliczeń dotyczą n/w dyrektywy:

      name .ENUM
           .ENDE [.EEND] [.END]

      Example:

      .enum portb
       rom_off = $fe
       rom_on = $ff
      .ende

      .enum test
       a             ; a=0
       b             ; b=1
       c = 5         ; c=5
       d             ; d=6
      .ende

  Deklaracja wyliczenia odbywa się przy użyciu dyrektyw .ENUM i .ENDE. Nazwa wyliczenia jest wymagana i konieczna, jej brak wygeneruje błąd. Do nazw wyliczeń nie można używać nazw mnemoników i pseudo rozkazów. Jeśli nazwa jest zarezerwowana wystąpi błąd z komunikatem Reserved word.

  Wartości kolejnych etykiet są zwiększane automatycznie o 1 zaczynając od domyślnej wartości 0, wartości etykiet można definiować samodzielnie albo pozostawić to automatowi.

  Do etykiet wyliczeniowych odwołujemy się przy pomocy składni:

       enum_name (field)

  lub bezpośrednio podobnie jak w przypadku odwołań do bloków .LOCAL, .PROC, czyli po nazwie typu oddzielone znakiem kropki występują kolejne pola, np.:

       lda #portb(rom_off)

       dta portb.rom_on, portb.rom_off

  Wyliczeń możemy użyć do deklaracji pól struktury .STRUCT, do alokacji zmiennych dyrektywą .VAR, np.:

      bank portb           // alokacja zmiennej BANK o rozmiarze 1 bajtu
      .var bank portb      // alokacja zmiennej BANK o rozmiarze 1 bajtu

      .struct test
       a portb
       b portb
      .ends

  Rozmiar zmiennej typu wyliczeniowego zależny jest od maksymalnej wartości jakie przyjmują kolejne etykiety wyliczenia, np.:

          .enum EState
              DONE, DIRECTORY_SEARCH=$ff, INIT_LOADING, LOADING
          .ende

  Dla w/w przykładu alokacja zmiennej typu "EState" będzie miała rozmiar dwóch bajtów (WORD).

  Rozmiar możemy sprawdzić przy pomocy dyrektywy .LEN (.SIZEOF), wynikiem będą wartości 1..4 (1-BYTE, 2=WORD, 3-LONG, 4-DWORD) np.:

       .print .len EState

  TABLICE

  `

  ## Deklaracja tablicy wielowymiarowej (.ARRAY)

  ` Tablic dotyczą n/w dyrektywy:

      label .ARRAY [elements0][elements1][...] [.type] [= init_value]
            .ARRAY label [elements0][elements1][...] [.type] [= init_value]
            .ENDA [.AEND] [.END]

  Dostępne typy danych to `.BYTE`, `.WORD`, `.LONG`, `.DWORD`. W przypadku braku podania typu domyślnie przyjmowany jest typ .BYTE. Definicja tablicy lokalizuje ją in-place (w miejscu definicji).

  `ELEMENTS` określa liczbę elementów tablicy, które będą indeksowane od <0..ELEMENTS-1>. Wartość ELEMENTS może być stałą lub wyrażeniem, powinna być z przedziału `<0..65535>`. W przypadku braku podania liczby elementów zostanie ona ustalona na podstawie liczby wprowadzonych danych.

  W obszarze ograniczonym dyrektywami .ARRAY i .ENDA nie ma możliwości używania mnemoników CPU, jeśli je użyjemy lub użyjemy innych niedozwolonych znaków wówczas wystąpi błąd z komunikatem Improper syntax.

  Dopuszczalne jest określenie indeksu od jakiego będziemy wpisywali wartości dla kolejnych pól tablicy. Nową wartość takiego indeksu określamy umieszczając na początku nowego wiersza w nawiasach kwadratowych wyrażenie [expression]. Możliwe jest określenie większej ilości indeksów, w tym celu rodzielamy kolejne indeksy znakiem dwukropka ':'. Następnie wprowadzamy wartości dla pól tablicy po znaku równości '=', np.:

      .array tab .word      ; tablica TAB o nieokreślonej z góry liczbie pól typu .WORD
       1,3                  ; [0]=1, [1]=3
       5                    ; [2]=5
       [12] = 1             ; [12]=1
       [3]:[7]:[11] = 9,11  ; [3]=9, [4]=11, [7]=9, [8]=11, [11]=9, [12]=11
      .enda

      .array scr [24][40]   ; tablica dwuwymiarowa SCR typu .BYTE
        [11][15] = "ATARI"
      .enda

  Przykład tablicy tłumaczącej kod naciśniętego klawisza na kod `INTERNAL`.

      .array TAB [255] .byte = $ff   ; alokowanie 256 bajtów [0..255] o wartości początkowej $FF

       [63]:[127] = "A"              ; przypisanie nowej wartości TAB[63]="A", TAB[127]="A"
       [21]:[85]  = "B"
       [18]:[82]  = "C"
       [58]:[122] = "D"
       [42]:[106] = "E"
       [56]:[120] = "F"
       [61]:[125] = "G"
       [57]:[121] = "H"
       [13]:[77]  = "I"
       [1] :[65]  = "J"
       [5] :[69]  = "K"
       [0] :[64]  = "L"
       [37]:[101] = "M"
       [35]:[99]  = "N"
       [8] :[72]  = "O"
       [10]:[74]  = "P"
       [47]:[111] = "Q"
       [40]:[104] = "R"
       [62]:[126] = "S"
       [45]:[109] = "T"
       [11]:[75]  = "U"
       [16]:[80]  = "V"
       [46]:[110] = "W"
       [22]:[86]  = "X"
       [43]:[107] = "Y"
       [23]:[87]  = "Z"
       [33]:[97]  = " "

       [52]:[180] = $7e
       [12]:[76]  = $9b

      .enda

  W w/w przykładzie stworzyliśmy tablicę `TAB` o rozmiarze 256 bajtów `[0..255]`, typie danych `.BYTE` i wypełniliśmy pola wartością = `$FF`, dodatkowo zapisaliśmy wartości kodów literowych `INTERNAL` na pozycjach (indeksach tablicy) równych kodowi naciśnięcia klawisza (bez `SHIFT-a` i z `SHIFT-em`, czyli duże i małe litery).

  Znak dwukropka `':'` rozdziela poszczególne indeksy tablicy.

  Przykład procedury detekcji ruchu joysticka, np.:

      .local HERO

        .pages

        lda $d300
        and #$0f
        tay
        lda joy,y
        sta _jmp

        jmp null
      _jmp equ *-2

      left
      right
      up
      down

      null

        rts

        .endpg

        _none     = 15
        _up       = 14
        _down     = 13
        _left     = 11
        _left_up  = 10
        _left_dw  = 9
        _right    = 7
        _right_up = 6
        _right_dw = 5

      .array joy [16] .byte = .lo(null)

      	[_left]     = .lo(left)
      	[_left_up]  = .lo(left)
      	[_left_dw]  = .lo(left)

      	[_right     = .lo(right)
      	[_right_up] = .lo(right)
      	[_right_dw] = .lo(right)

      	[_up]       = .lo(up)
      	[_dw]       = .lo(down)
      .enda

      .endl

  Innym przykładem może być umieszczenie wycentrowanego napisu, np.:

       org $bc40

      .array txt 39 .byte
       [17] = "ATARI"
      .enda

  Do tak stworzonej tablicy odwołujemy się następująco:

       lda tab,y
       lda tab[23],x
       ldx tab[200]

  Jeśli w nawiasie kwadratowym podamy wartość indeksu przekraczającą zadeklarowaną dla danej tablicy, zostanie wygenerowany komunikat błędu `Constant expression violates subrange bounds`.

  MAKRA

  Makra ułatwiają nam wykonywanie powtarzających się czynności, automatyzują je. Istnieją tylko w pamięci assemblera, dopiero w momencie wywołania są asemblowane. Przy ich pomocy `MADS` może odkładać i zdejmować z programowego stosu parametry dla procedur zadeklarowanych dyrektywą `.PROC` oraz przełączać banki rozszerzonej pamięci w trybie `BANK SENSITIVE (OPT B+)`.

  `

  ## Deklaracja makra

  `

  Makr dotyczą n/w pseudo rozkazy i dyrektywy:

      name .MACRO [arg1, arg2 ...] ['separator'] ["separator"]
           .MACRO name [(arg1, arg2 ...)] ['separator'] ["separator"]
           .EXITM [.EXIT]
           .ENDM [.MEND]
           :[%%]parameter
           :[%%]label

  `

  ### name .MACRO [(arg1, arg2 ...)] ['separator'] ["separator"]

  ` Deklaracja makra o nazwie `name` za pomocą dyrektywy `.MACRO`. Nazwa makra jest wymagana i konieczna, jej brak wygeneruje błąd. Do nazw makr nie można używać nazw mnemoników i pseudo rozkazów (błąd `Reserved word`).

  Dopuszczalna jest lista z etykietami nazw argumentów jakie będą przekazywane do makra, taka lista może być ograniczona dodatkowo nawiasem okrągłym (). Przedstawianie argumentów w postaci nazw etykiet ma na celu poprawienie przejrzystości kodu makra. W samym ciele makra można używać zamiennie nazw etykiet argumentów lub ich numerycznych odpowiedników.

      .macro SetColor val,reg
       lda :val
       sta :reg
      .endm

  Na końcu deklaracji makra może wystąpić deklaracja separatora i zarazem trybu przekazywania parametrów do makra (pojedyńczy apostrof bez zmian, podwójny apostrof z rozbijaniem parametrów na tryb adresacji i argument).

  Domyślnym separatorem, rozdzielającym parametry przekazywane do makra jest znak przecinka `','` oraz spacji ' '.

- name .MACRO 'separator' Pomiędzy pojedyńczymi apostrofami `''` możemy umieścić znak separatora, który będzie używany do oddzielenia parametrów przy wywołaniu makra (tylko do tego mogą służyć pojedyńcze apostrofy).

- name .MACRO "separator" Pomiędzy podwójnymi apostrofami `""` możemy także umieścić znak separatora, który będzie używany do oddzielenia parametrów przy wywołaniu makra. Dodatkowo użycie podwójnego apostrofu sygnalizuje `MADS-owi` aby rozkładał przekazywane parametry na dwa elementy: tryb adresacji i argument, np.:

       test #12 200 <30

      test .macro " "
      .endm

  Makro `TEST` ma zadeklarowany separator-spację przy użyciu apostrofu `"`, czyli po wywołaniu makra parametry zostaną rozłożone na dwa elementy: tryb adresacji i argument.

       #12   ->  tryb adresacji '#' argument 12
       200   ->  tryb adresacji ' ' argument 200
       <30   ->  tryb adresacji '#' argument 0   (obliczona wartość wyrażenia "<30")

       test '#' 12 ' ' 200 '#' 0

  UAWAGA #1: Parametry ze znakiem operatora `'<', '>'` zostają obliczone i dopiero ich wynik jest przekazywany do makra (podstawiany pod parametr).

  UAWAGA #2: Jeśli parametrem makra jest licznik pętli '#', '.R' (!!! pojedyńczy znak '#' lub dyrektywa '.R' a nie wyrażenie z udziałem tego znaku, tej dyrektywy !!!) wówczas do makra przekazywana jest wartość licznika pętli (podstawiana pod parametr).

  Tą właściwość możemy wykorzystać do stworzenia "samopiszącego" się kodu, kiedy potrzebujemy tworzyć nowe etykiety typu "label0", "label1", "label2", "label3" ... itd. , np.:

       :32 find #

      find .macro
            ift .def label:1
            dta a(label:1)
            eif
           .endm

  W/w przykład zapisuje adres etykiety pod warunkiem że taka etykiety istnieje (została zdefiniowana).

  ``

  ### .EXITM [.EXIT]

  Zakończenie działania makra. Powoduje bezwzględne zakończenie działania makra.

  ``

  ### .ENDM [.MEND]

  Przy pomocy dyrektywy .ENDM lub .MEND kończymy deklarację aktualnego makra. Nie ma możliwości użycia dyrektywy .END jak ma to miejsce dla innych obszarów deklarowanych przez dyrektywy .LOCAL, .PROC, .ARRAY, .STRUCT, .REPT `

  ### :[%%]parameter

  ` Parametr jest liczbą decymalną dodatnią `(>=0)`, poprzedzoną znakiem dwukropka `':'` lub dwoma znakami procentu `'%%'`. Jeśli w makrze chcemy aby znak `':'` określał liczbę powtórzeń a nie numer parametru wystarczy że następny znak po dwukropku nie będzie z przedziału `'0'..'9'`, tylko np:

       :$2 nop
       :+2 nop
       :%10 nop

  Parametr `:0 (%%0)` ma specjalne znaczenie, zawiera liczbę przekazanych parametrów. Z jego pomocą możemy sprawdzić czy wymagana liczba parametrów została przekazana do makra, np.:

        .IF :0<2 || :0>5
          .ERROR "Wrong number of arguments"
        .ENDIF

        IFT %%0<2 .or :0>5
          ERT "Wrong number of arguments"
        EIF

  Przykład makra:

      .macro load_word

         lda <:1
         sta :2
         lda >:1
         sta :2+1
       .endm

       test ne
       test eq

      .macro test
        b%%1 skip
      .endm

  `

  ## Wywołanie makra

  `

  Makro wywołujemy poprzez jego nazwę, po niej mogą wystąpić parametry makra, rozdzielone separatorem którym jest domyślnie znak przecinka `','` lub spacji ' '. Liczba parametrów uzależniona jest od wolnej pamięci komputera PC. Jeśli przekazana liczba parametrów jest mniejsza od liczby parametrów używanych w danym makrze, wówczas pod brakujące parametry zostanie podstawiona wartość `-1 ($FFFFFFFF)`. Tą właściwość można wykorzystać do sprawdzenia czy został przekazany parametr czy też nie, łatwiej jednak tego dokonać za pomocą parametru zerowego %%0.

       macro_name [Par1, Par2, Par3, 'Par4', "string1", "string2" ...]

  Parametrem może być wartość, wyrażenie lub ciąg znaków ograniczony apostrofem pojedyńczym `''` lub podwójnym `""`.

- apostrofy pojedyńcze `' '` zostaną przekazane do makra razem ze znakami znajdującymi się pomiędzy nimi
- apostrofy podwójne `" "` oznaczają ciąg znaków i tylko ciąg znaków znajdujący się pomiędzy apostrofami zostanie przekazany do makra

  Wszelkie definicje etykiet w obrębie makra mają zasięg lokalny.

  Jeśli poszukiwana przez assembler etykieta nie wystąpiła w obszarze makra, wówczas nastąpi jej szukanie w obszarze lokalnym (jeśli wystąpiła dyrektywa `.LOCAL`), następnie w procedurze (jeśli procedura jest aktualnie przetwarzana), na końcu w głównym programie.

  Przykład wywołania makra:

       macro_name 'a',a,>$a000,cmp    ; dla domyślnego separatora ','
       macro_name 'a'_a_>$a000_cmp    ; dla zadeklarowanego separatora '_'
       macro_name 'a' a >$a000 cmp    ; dla domyślnego separatora ' '

  Możliwe jest wywoływanie makr z poziomu makra, oraz rekurencyjne wywoływanie makr. W tym ostatnim przypadku należy być ostrożnym bo może dojść do przepełnienia stosu `MADS-a`. `MADS` zabezpiecza się przez rekurencją makr bez końca i zatrzymuje asemblacje gdy liczba wywołań makra przekroczy `4095` (błąd `Infinite recursion`).

  Przykład makra, które spowoduje przepełnienie stosu `MADS-a`:

      jump .macro

            jump

           .endm

  Przykład programu, który przekazuje parametry do pseudo procedur `..\EXAMPLES\MACRO.ASM`:

       org $2000

       proc PutChar,'a'-64    ; wywołanie makra PROC, jako parametr
       proc PutChar,'a'-64    ; nazwa procedury która będzie wywołana przez JSR
       proc PutChar,'r'-64    ; oraz jeden argument (kod znaku INTERNAL)
       proc PutChar,'e'-64
       proc PutChar,'a'-64

       proc Kolor,$23         ; wywołanie innej procedurki zmieniającej kolor tła

      ;---

      loop jmp loop           ; pętla bez końca, aby zobaczyć efekt działania

      ;---

      proc .macro             ; deklaracja makra PROC
       push =:1,:2,:3,:4      ; wywołanie makra PUSH odkładającego na stos argumenty
                              ; =:1 wylicza bank pamieci

       jsr :1                 ; skok do procedury (nazwa procedury w pierwszym parametrze)

       lmb #0                 ; Load Memory Bank, ustawia bank na wartosc 0
       .endm                  ; koniec makra PROC

      ;---

      push .macro             ; deklaracja makra PUSH

        lmb #:1               ; ustawia wirtualny bank pamięci

       .if :2<=$FFFF          ; jeśli przekazany argument jest mniejszy równy $FFFF to
        lda <:2               ; odłóż go na stosie
        sta stack
        lda >:2
        sta stack+1
       .endif

       .if :3<=$FFFF
        lda <:3
        sta stack+2
        lda >:3
        sta stack+3
       .endif

       .if :4<=$FFFF
        lda <:4
        sta stack+4
        lda >:4
        sta stack+5
       .endif

       .endm

      * ------------ *            ; procedura KOLOR
      *  PROC Kolor  *
      * ------------ *
       lmb #1                     ; ustawienie numeru wirtualnego banku na 1
                                  ; wszystkie definicje etykiet będą teraz należeć do tego banku
      stack org *+256             ; stos dla procedury KOLOR
      color equ stack

      Kolor                       ; kod procedury KOLOR
       lda color
       sta 712
       rts

      * -------------- *          ; procedura PUTCHAR
      *  PROC PutChar  *
      * -------------- *
       lmb #2                     ; ustawienie numeru wirtualnego banku na 2
                                  ; wszystkie definicje etykiet będą teraz należeć do tego banku
      stack org *+256             ; stos dla procedury PUTCHAR
      char  equ stack

      PutChar                     ; kod procedury PUTCHAR
       lda char
       sta $bc40
      scr equ *-2

       inc scr
       rts

  Oczywiście stos w tym przykładowym programie jest programowy. W przypadku `65816` można byłoby użyć stosu sprzętowego. Dzięki temu, że zdefiniowane zmienne przypisywane są do konkretnego numeru banku, można stworzyć strukturę wywołania procedury czy funkcji podobną do tych z języków wyższego poziomu.

  Prościej i efektywniej jednak skorzystać z deklaracji procedury `.PROC` jaką umożliwia `MADS`. Więcej o deklaracji procedury i operacjach jej dotyczących w rozdziale Procedury.

  PROCEDURY .PROC

  `MADS` wprowadza nowe możliwości w obsłudze procedur z parametrami. Nowe możliwości upodabniają ten mechanizm do tych znanych z języków wysokiego poziomu i są tak samo łatwe w użyciu dla programisty.

  Aktualnie dołączone do `MADS-a` deklaracje makr (`@CALL.MAC, @PULL.MAC, @EXIT.MAC`) umożliwiają obsługę stosu programowego o wielkości 256 bajtów, czyli tej samej wielkości jak stos sprzętowy, udostępniają mechanizm zdejmowania ze stosu programowego i odkładania na stos programowy parametrów potrzebnych podczas wywoływania procedur, jak i wychodzenia z takich procedur. `MADS` uwzględnia możliwość rekurencji takich procedur.

  Programista nie jest zaangażowany w ten mechanizm, może skupić uwagę na swoim programie. Musi tylko pamiętać o potrzebie zdefiniowania odpowiednich etykiet i dołączeniu odpowiednich makr podczas asemblacji programu.

  Dodatkowo istnieje możliwość pominięcia "mechanizmu" stosu programowego MADS-a i skorzystanie z klasycznego sposobu ich przekazywania, za pomocą rejestrów CPU (dyrektywa .REG) lub przez zmienne (dyrektywa .VAR).

  Inną właściwością procedur .PROC jest możliwość pominięcia ich podczas asemblacji jeśli nie wystąpiło żadne odwołanie do nich, czyli zostały zdefiniowane ale nie są wykorzystane. Wystąpi wówczas komunikat ostrzeżenia Unreferenced procedure ????. Pominięcie takiej procedury podczas asemblacji możliwe jest poprzez podanie parametru do MADS-a w linii poleceń -x 'Exclude unreferenced procedures'.

  Wszelkie etykiety zdefiniowane w obszarze procedury `.PROC` są zasięgu lokalnego, można je też określić jako etykiety globalne zdefiniowane lokalnie o dostępie swobodnym, ponieważ można się do nich odwoływać co nie jest normalne w innych językach programowania.

  W obszarze procedury `.PROC` istnieje możliwość zdefiniowania etykiet o zasięgu globalnym (patrz rozdział Etykiety globalne).

  Jeśli chcemy dostać się do etykiet zdefiniowanych w procedurze spoza obszaru procedury, wówczas adresujemy z użyciem znaku kropki '.', np.:

       lda test.pole

      .proc test

      pole nop

      .endp

  Jeśli poszukiwana przez assembler etykieta nie wystąpiła w obszarze procedury `.PROC`, wówczas `MADS` będzie poszukiwał ją w obszarze niższym aż dojdzie do obszaru globalnego. Aby odczytać natychmiastowo wartość etykiety globalnej z poziomu procedury `.PROC` (czy też innego obszaru lokalnego) poprzedzamy nazwę etykiety znakiem dwukropka ':'.

  `MADS` wymaga dla procedur wykorzystujących stos programowy, trzech globalnych definicji etykiet o konkretnych nazwach (adres stosu, wskaźnik stosu, adres parametrów procedury):

- @PROC_VARS_ADR
- @STACK_ADDRESS
- @STACK_POINTER

  Brak definicji w/w etykiet i próba użycia bloku `.PROC` wykorzystującego stos programowy spowoduje że MADS przyjmie swoje domyślne wartości tych etykiet: @PROC_VARS_ADR = $0500, @STACK_ADDRESS = $0600, @STACK_POINTER = $FE

  `MADS` dla procedur wykorzystujących stos programowy wymaga także deklaracji makr o konkretnych nazwach. Dołączone do `MADS-a` deklaracje tych makr znajdują się w plikach:

- @CALL ..\EXAMPLES\MACROS\@CALL.MAC
- @PUSH ..\EXAMPLES\MACROS\@CALL.MAC
- @PULL ..\EXAMPLES\MACROS\@PULL.MAC
- @EXIT ..\EXAMPLES\MACROS\@EXIT.MAC W/w makra realizują przekazywanie i odkładanie na programowy stos parametrów, oraz zdejmowanie i odkładanie parametrów dla procedur wykorzystujących stos programowy i wywoływanych z poziomu innych procedur wykorzystujących stos programowy.

  `

  ## Deklaracja procedury .PROC

  `

  Procedur dotyczą n/w dyrektywy:

       name .PROC [(.TYPE PAR1 .TYPE PAR2 ...)] [.REG] [.VAR]
       .PROC name [,address] [(.TYPE PAR1 .TYPE PAR2 ...)] [.REG] [.VAR]
       .ENDP [.PEND] [.END]

  `

  ### name .PROC [(.TYPE Par1,Par2 .TYPE Par3 ...)] [.REG] [.VAR]

  ` Deklaracja procedury name przy użyciu dyrektywy `.PROC`. Nazwa procedury jest wymagana i konieczna, jej brak wygeneruje błąd. Do nazw procedur nie można używać nazw mnemoników i pseudo rozkazów. Jeśli nazwa jest zarezerwowana wystąpi błąd z komunikatem `Reserved word`.

  Jeśli chcemy wykorzystać jeden z mechanizmów `MADS-a` do przekazywania parametrów do procedur, musimy je wcześniej zadeklarować. Deklaracja parametrów procedury mieści się pomiędzy nawiasami okrągłymi `( )`. Dostępne są cztery typy parametrów:

- `.BYTE` (8-bit) relokowalne
- `.WORD` (16-bit) relokowalne
- `.LONG` (24-bit) nierelokowalne
- `.DWORD` (32-bit) nierelokowalne `W obecnej wersji `MADS-a` nie ma możliwości przekazywania parametrów za pomocą struktur `.STRUCT.``

  Bezpośrednio po deklaracji typu, oddzielona minimum jedną spacją, następuje nazwa parametru. Jeśli deklarujemy więcej parametrów tego samego typu możemy rozdzielić ich nazwy znakiem przecinka `','`.

  Przykład deklaracji procedury wykorzystującej stos programowy:

      name .PROC ( .WORD par1 .BYTE par2 )
      name .PROC ( .BYTE par1,par2 .LONG par3 )
      name .PROC ( .DWORD p1,p2,p3,p4,p5,p6,p7,p8 )

  Dodatkowo używając dyrektyw .REG lub .VAR mamy możliwość określenia sposobu i metody przekazywania parametrów do procedur MADS-a. Przez rejestry CPU (.REG) lub przez zmienne (.VAR). Dyrektywy określające sposób przekazywania parametrów umieszczamy na końcu naszej deklaracji procedury .PROC

  Przykład deklaracji procedury wykorzystującej rejestry CPU:

      name .PROC ( .BYTE x,y,a ) .REG
      name .PROC ( .WORD xa .BYTE y ) .REG
      name .PROC ( .LONG axy ) .REG

  Dyrektywa .REG wymaga aby nazwy parametrów składały się z liter 'A', 'X', 'Y' lub ich kombinacji. Litery te odpowiadają nazwom rejestrów CPU i wpływają na kolejność użycia rejestrów. Ograniczeniem w liczbie przekazywanych parametrów jest ilość rejestrów CPU, przez co możemy przekazać do procedury w sumie maksimum 3 bajty. Zaletą takiego sposobu jes natomiast szybkość i małe zużycie pamięci RAM.

  Przykład deklaracji procedury wykorzystującej zmienne:

      name .PROC ( .BYTE x1,x2,y1,y2 ) .VAR
      name .PROC ( .WORD inputPointer, outputPointer ) .VAR
      name .PROC ( .WORD src+1, dst+1 ) .VAR

  Dla .VAR nazwy parametrów wskazują nazwy zmiennych do których będą ładowane przekazywane parametry. Metoda ta jest wolniejsza od .REG jednak nadal szybsza od metody ze stosem programowym.

  Procedurę opuszczamy w standardowy sposób, czyli przy pomocy rozkazu RTS. Dodanie rozkazu `RTS` w ciele procedury przy wyjściu z każdej ścieżki jest obowiązkiem programującego, a nie assemblera.

  Podobnie jak w przypadku bloku .LOCAL mamy możliwość określenia nowego adresu asemblacji dla bloku .PROC, np.:

      .PROC label,$8000
      .ENDP

      .PROC label2,$a000 (.word ax) .reg
      .ENDP

  W przypadku procedur wykorzystujących stos programowy po zakończeniu procedury przez .ENDP MADS wywołuje makro `@EXIT`, którego zadaniem jest modyfikacja wskaźnika stosu programowego `@STACK_POINTER`, jest to konieczne dla prawidłowego działania stosu programowego. Użytkownik może sam zaprojektować swoje makro `@EXIT`, albo skorzystać z dołączonego do MADS-a (plik `..\EXAMPLES\MACROS\@EXIT.MAC`), ma ono obecnie następującą postać:

      .macro @EXIT

       ift :1<>0

        ift :1=1
         dec @stack_pointer

        eli :1=2
         dec @stack_pointer
         dec @stack_pointer

        els
         pha
         lda @stack_pointer
         sub #:1
         sta @stack_pointer
         pla

        eif

       eif

      .endm

  Makro `@EXIT` nie powinno zmieniać zawartości rejestrów `CPU` jeśli chcemy zachować możliwość zwrócenie wyniku działania procedury .PROC poprzez rejestry CPU.

  `

  ### .ENDP

  ` Dyrektywa `.ENDP` kończy deklarację bloku procedury.

  `

  ## Wywołanie procedury

  `

  Procedurę wywołujemy poprzez jej nazwę (identycznie jak makro), po niej mogą wystąpić parametry, rozdzielone separatorem w postaci znaku przecinka `','` lub spacji ' ' (nie ma możliwości zadeklarowania innych separatorów).

  Jeśli typ parametru nie będzie zgadzał się z typem zadeklarowanym w deklaracji procedury wystąpi komunikat błędu `Incompatible types`.

  Jeśli przekazana liczba parametrów różni się od liczby zadeklarowanych parametrów w deklaracji procedury to wystąpi komunikat błędu `Improper number of actual parameters`. Wyjątkiem jest procedura do której parametry przekazywane są przez rejestry CPU (.REG) lub zmienne (.VAR), w takich przypadkach możemy pominąć parametry, w domyśle są one już załadowane do odpowiednich rejestrów czy też zmiennych.

  Możliwe są trzy sposoby przekazania parametru:

- '#' przez wartość
- ' ' przez wartość spod adresu (bez znaku poprzedzającego)
- '@' przez akumulator (parametry typu .BYTE)
- "string" przez ciąg znakowy, np. "label,x"

  Przykład wywołania procedury:

       name @ , #$166 , $A400  ; dla stosu programowego
       name , @ , #$3f         ; dla .REG lub .VAR
       name "(hlp),y" "tab,y"	 ; dla .VAR lub dla stosu programowego (stos programowy korzysta z regX)

  `MADS` po napotkaniu wywołania procedury, która korzysta ze stosu programowego wymusza wykonanie makra `@CALL`. Jeśli jednak procedura nie korzysta ze stosu programowego, zamiast makra `@CALL` zostanie wynegerowany zwykły rozkaz `JSR PROCEDURE`.

  Do makra `@CALL` `MADS` przekazuje parametry wyliczone na podstawie deklaracji procedury (rozbija każdy parametr na trzy składowe: tryb adresacji, typ parametru, wartość parametru).

      @CALL_INIT 3\ @PUSH_INIT 3\ @CALL '@','B',0\ @CALL '#','W',358\ @CALL ' ',W,"$A400"\ @CALL_END PROC_NAME

  Makro `@CALL` odłoży na stos zawartość akumulatora, następnie wartość `$166 (358 dec)`, następnie wartość spod adresu `$A400`. Więcej informacji na temat sposobu przekazywania parametrów do makr (znaczenia apostrofów '' i "") w rozdziale Wywołanie makra.

  Parametr przekazywany przez akumulator `'@'` powinien być zawsze pierwszym parametrem przekazywanym do procedury, jeśli wystąpi w innym miejscu zawartość akumulatora zostanie zmodyfikowana (domyślne makro `@CALL` nakłada takie ograniczenie). Oczywiście użytkownik może to zmienić pisząc swoją wersję makra `@CALL`. W przypadku procedur .REG lub .VAR kolejność wystąpienia parametru '@' nie ma znaczenia.

  Wyjście z procedury `.PROC` następuje poprzez rozkaz RTS. Po powrocie z procedury MADS wywołuje makro @EXIT które zawiera program modyfikujący wartość wskaźnika stosu `@STACK_POINTER`, jest to niezbędne w celu prawidłowego działania stosu programowego. Od wskaźnika stosu odejmowana jest liczba bajtów które zostały przekazane do procedury, liczba bajtów przekazywana jest do makra jako parametr.

  Dodanie rozkazu `RTS` w ciele procedury przy wyjściu z każdej ścieżki jest obowiązkiem programującego, a nie assemblera.

  `

  ## Parametry procedury, odwołania

  ` Odwołania do parametrów procedury z poziomu procedury nie wymagają dodatkowych operacji ze strony programisty, np.:

      @stack_address equ $400
      @stack_pointer equ $ff
      @proc_vars_adr equ $80

      name .PROC (.WORD par1,par2)

       lda par1
       clc
       adc par2
       sta par1

       lda par1+1
       adc par2+1
       sta par1+1

      .endp

       icl '@call.mac'
       icl '@pull.mac'
       icl '@exit.mac'

  MADS w momencie napotkania deklaracji .PROC z parametrami, dokonuje automatycznej definicji tych parametrów przypisując im wartości na podstawie @PROC_VARS_ADR. W w/w przykładzie MADS dokona automatycznej definicji parametrów PAR1 = @PROC_VARS_ADR, PAR2 = @PROC_VARS_ADR + 2.

  Programista odwołuje się do tych parametrów po nazwie jaka została im nadana w deklaracji procedury, czyli podobnie jak ma to miejsce w językach wyższego poziomu. W MADS istnieje możliwość dostępu do parametrów procedury spoza procedury co nie jest już normalne w językach wyższego poziomu. Możemy odczytać z w/w przykładu zawartość PAR1, np.:

       lda name.par1
       sta $a000
       lda name.par1+1
       sta $a000+1

  Wartość PAR1 została przepisane pod adres $A000, wartość PAR1+1 pod adres $A000+1. Oczywiście możemy tego dokonać tylko bezpośrednio po zakończeniu tej konkretnej procedury. Trzeba pamiętać że parametry takich procedur odkładane są pod wspólnym adresem @PROC_VARS_ADR, więc z każdym nowym wywołaniem procedury wykorzystującej stos programowowy zawartość obszaru <@PROC_VARS_ADR .. @PROC_VARS_ADR + $FF> ulega zmianom.

  Jeśli procedura ma zadeklarowane parametry typu .REG programista powinien zatroszczyć się o to aby je zapamiętać czy też właściwie wykorzystać zanim zostaną zmodyfikowane przez kod procedury. W przypadku parametrów typu .VAR nie trzeba się o nic martwić ponieważ parametry zostały zapisane do konkretnych komórek pamięci skąd zawsze możemy je odczytać.

  OBSZAR LOKALNY

  Głównym zadaniem obszaru lokalnego w `MADS` jest stworzenie nowej przestrzeni nazw dla etykiet.

  Wszelkie etykiety zdefiniowane w obszarze lokalnym `.LOCAL` są zasięgu lokalnego, można je też określić jako etykiety globalne zdefiniowane lokalnie o dostępie swobodnym, ponieważ można się do nich odwoływać co nie jest normalne w innych językach programowania.

  Obszary lokalne są addytywne tzn. że może być wiele bloków .LOCAL o tej samej nazwie, nie zostanie wygenerowany komunikat błędu Label ... declared twice.

  W obszarze lokalnym `.LOCAL` istnieje możliwość zdefiniowania etykiet o zasięgu globalnym (patrz rozdział Etykiety globalne).

  Jeśli poszukiwana przez assembler etykieta nie wystąpiła w obszarze lokalnym `.LOCAL`, wówczas `MADS` będzie poszukiwał ją w obszarze niższym aż dojdzie do obszaru globalnego. Aby odczytać natychmiastowo wartość etykiety globalnej z poziomu obszaru lokalnego `.LOCAL` (czy też innego obszaru lokalnego) poprzedzamy nazwę etykiety znakiem dwukropka ':'.

  `

  ## Deklaracja obszaru lokalnego .LOCAL

  `

  Obszarów lokalnych dotyczą n/w dyrektywy:

       [name] .LOCAL [,address]
       .LOCAL [name] [,address]
       .ENDL [.LEND] [.END]

  `

  ### [name] .LOCAL [,address]

  `

  Deklaracja obszaru lokalnego o nazwie name za pomocą dyrektywy `.LOCAL`. Nazwa obszaru nie jest wymagana i nie jest konieczna. Do nazw obszarów lokalnych nie można używać nazw mnemoników i pseudo rozkazów. Jeśli nazwa jest zarezerwowana wystąpi błąd z komunikatem `Reserved word`.

  Po nazwie obszaru lokalnego (lub po dyrektywie .LOCAL) możemy podać nowy adres asemblacji bloku lokalnego. Po zakończeniu takiego bloku (.ENDL) przywracany jest poprzedni adres asemblacji zwiększony o długość bloku lokalnego.

      label .local,$4000
      .endl

      .local label2,$8000
      .endl

      .local
      .endl

      .local label3
      .endl

  Wszelkie definicje etykiet w obszarze `.LOCAL` są typu lokalnego. Aby odwołać się do etykiety globalnej o tej samej nazwie co etykieta lokalna należy poprzedzić ją znakiem dwukropka `':'`, np.:

      lab equ 1

      .local

      lab equ 2

       lda #lab
       ldx #:lab

      .endl

  W w/w przykładzie do rejestru A zostanie załadowana wartość 2, natomiast do rejestru X wartość 1.

  Jeśli poszukiwana przez assembler etykieta nie wystąpiła w obszarze `.LOCAL`, wówczas nastąpi jej szukanie w obszarze makra (jeśli jest aktualnie przetwarzane), potem w procedurze (jeśli procedura jest aktualnie przetwarzana), na końcu w głównym programie.

  W zadeklarowanym obszarze lokalnym wszystkie definicje etykiet rozróżniane są na podstawie nazwy obszaru lokalnego. Aby dotrzeć do zdefiniowanej etykiety w obszarze lokalnym spoza obszaru lokalnego musimy znać nazwę obszaru i etykiety w nim występującej, np.:

       lda #name.lab1
       ldx #name.lab2

      .local name

      lab1 = 1
      lab2 = 2

      .endl

  W adresowaniu takiej struktury `.LOCAL` używamy znaku kropki `'.'`.

  Obszary lokalne możemy zagnieżdżać, możemy je umieszczać w ciele procedur zadeklarowanych przez dyrektywę `.PROC`. Obszary lokalne są addytywne, tzn. może istnieć wiele obszarów lokalnych o tej samej nazwie, wszystkie symbole występujące w tych obszarach należeć będą do wspólnej przestrzeni nazw.

  Długość wygenerowanego kodu w bloku LOCAL można sprawdzić przy pomocy dyrektywy .LEN (.SIZEOF).

  `

  ### .ENDL

  `

  Dyrektywa .ENDL kończy deklarację obszaru lokalnego.

  Przykład deklaracji obszaru lokalnego:

       org $2000

      tmp ldx #0   <-------------   etykieta w obszarze globalnym
                                |
       lda obszar.pole  <---    |   odwolanie do obszaru lokalnego
                           |    |
      .local obszar        |    |   deklaracja obszaru lokalnego
                           |    |
       lda tmp   <---      |    |
                    |      |    |
       lda :tmp     |      | <---   odwolanie do obszaru globalnego
                    |      |
      tmp nop    <---      |        definicja w obszarze lokalnym
                           |
      pole lda #0       <---   <--- definicja w obszarze lokalnym
                                  |
       lda pole  <----------------- odwolanie w obszarze lokalnym

      .endl                        koniec deklaracji obszaru lokalnego

  SKŁADNIA

  `MADS` akceptuje podobną składnię jak `QA, XASM`. Jest jednak mniej tolerancyjny w kwestii komentarzy umieszczanych na końcu linii (komentarze powinny być poprzedzone odpowiednim znakiem) lub bardziej tolerancyjny w przypadku białych spacji i w przypadkach braku argumentu dla mnemonika rozkazu `CPU`, np.:

         asl            ->  asl @
         lda #          ->  lda #0

  `MADS` akceptuje brak białych spacji rozdzielających mnemonik i argument, pod warunkiem że znaki argumentu nie zaczynają się znakiem `'@'` używanym w nazwach etykiet lub znakami `'%', ':'` używanymi do oznaczenia numeru parametru w makrach (`%%numer, :numer`), np.:

         lda$44
         lda#
         lda(80),y

  `

  ## Komentarze

  ` Znaki komentarza jednoliniowego powinniśmy poprzedzać znakiem `';'` lub `'*'`. Do oznaczania komentarza jednoliniowego najbezpieczniej jest jednak używać średnika `';'` ponieważ znak `'*'` ma też inne znaczenia, może oznaczać operację mnożenia, czy też aktualny adres podczas asemblacji. Średnik natomiast dedykowany jest tylko i wyłącznie do oznaczania komentarzy.

  Do oznaczenia komentarza jednoliniowego możliwe jest też użycie znaków `'//'`, a dla wieloliniowego znaków `'/* */'`.

       * to jest komentarz
                       ; to jest komentarz
       lda #0      ; to jest komentarz
       dta  1 , 3     * BŁĘDNY KOMENTARZ, ZOSTANIE ŹLE ZINTERPRETOWANY

       org $2000 + 1      BŁĘDNY KOMENTARZ, ZOSTANIE ŹLE ZINTERPRETOWANY

       nop // to jest komentarz

       // to jest komentarz

       dta 1,2, /* komentarz */ 3,4

       lda /* komentarz */ #0

      /*
        ...
        to jest komentarz wieloliniowy
        ...
      */

      /*************************************
        to tez jest komentarz wieloliniowy
      **************************************/

  Znaki oznaczające komentarz wieloliniowy `'/* */'` i znaki oznaczające komentarz jednoliniowy `'//'` można stosować bez ograniczeń.

  `

  ## Łączenie/Dzielenie wielu wierszy listingu w jeden wiersz

  `

  Dowolną ilość wierszy listingu możemy połączyć (rozdzielić) w jeden wiersz używając znaku `'\'`, np.:

       lda 20\ cmp 20\ beq *-2

          lda 20   \ cmp  20   \   beq *-2

        lda #0  \lop  sta $a000,y  \ iny  \ bne lop     ; komentarz tylko na końcu takiego wiersza

  Jeśli po znaku `'\'` nie umieścimy znaku spacji, wówczas mnemonik czy inny ciąg znakowy może zostać zinterpretowany jako etykieta, należy pamiętać że znak `'\'` oznacza początek nowej linii.

  `MADS` kończy przetwarzać taki wiersz, aż do napotkania komentarza lub napotkania końca ciągu znakowego, dlatego komentarze możemy umieszczać tylko na końcu takiego wielo-wiersza.

  UWAGA!!! Umieszczenie znaku '\' na końcu wiersza oznacza dla MADS-a chęć kontynuowania aktualnego wiersza od następnego wiersza, np.:

       lda\
       #\
       12

  Dla w/w przykładu otrzymamy rozkaz 'LDA #12'.

  `

  ## Łączenie wielu mnemoników

  `

  Możliwość łączenia dwóch mnemoników za pomocą znaku dwukropka `':'` znana jest już z `XASM-a`. W `MADS` ta możliwość została rozszerzona o łączenie dowolnej liczby znanych `MADS-owi` mnemoników, np.:

       lda:cmp:req 20

       lda:iny:sta:iny $600,y

  WYRAŻENIA

  Termin wyrażenie oznacza sekwencję operatorów i operandów (argumentów), która określa operacje, tj. rodzaj i kolejność obliczeń. Wyrażeniem złożonym nazywa się takie wyrażenie, w którym występuje dwa lub więcej operatorów. Operatory, które oddziaływują tylko na jeden operand, nazywa się jednoargumentowymi (unarnymi). Operatory dwuargumentowe nazywa się binarnymi.

  Wartościowanie wyrażenia przebiega w porządku, określonym pierwszeństwem operatorów i w kierunku, określonym przez kierunek wiązania operatorów.

  `

  ## Liczby

  `

  `MADS` akceptuje zapis liczb w formacie decymalnym, hexadecymalnym, binarnym oraz w kodach ATASCII i INTERNAL.

- zapis decymalny:

       -100
       -2437325
       1743

- zapis hexadecymalny:

       $100
       $e430
       $000001

       0x12
       0xa000
       0xaabbccdd

- zapis binarny:

       %0001001010
       %000000001
       %001000

- zapis kodami ATASCII:

       'a'
       'fds'
       'W'*

- zapis kodami INTERNAL:

       "B"
       "FDSFSD"
       "."*

  Tylko pierwszy znak ciągu ATASCII, INTERNAL jest znaczący. Znak `'*'` za apostrofem zamykającym powoduje invers znaku.

  Dodatkowo możliwe są jeszcze dwie operacje '+' i '-' dla ciągów znakowych, które powodują zwiększenie/zmniejszenie kodów znaków ograniczonych apostrofami.

       "FDttrteSFSD"-12
       'FDSFdsldksla'+2

  `

  ## Operatory

  `

      Binary operators:

      +   Addition
      -   Subtraction
      *   Multiplication
      /   Division
      %   Remainder
      &   Bitwise and
      |   Bitwise or
      ^   Bitwise xor
      <<  Arithmetic shift left
      >>  Arithmetic shift right
      =   Equal
      ==  Equal (same as =)
      <>  Not equal
      !=  Not equal (same as <>)
      <   Less than
      >   Greater than
      <=  Less or equal
      >=  Greater or equal
      &&  Logical and
      ||  Logical or

      Unary operators:

      +  Plus (does nothing)
      -  Minus (changes sign)
      ~  Bitwise not (complements all bits)
      !  Logical not (changes true to false and vice versa)
      <  Low (extracts low byte)
      >  High (extracts high byte)
      ^  High 24bit (extracts high byte)
      =  Extracts memory bank
      :  Extracts global variable value

      Operator precedence:

      first []              (brackets)
       + - ~ < >            (unary)
       * / % & << >>        (binary)
       + - | ^              (binary)
       = == <> != < > <= >= (binary)
       !                    (unary)
       &&                   (binary)
      last  ||              (binary)

  ETYKIETY

  Etykiety zdefiniowane w programie mogą posiadać zasięg lokalny lub globalny, w zależności od miejsca w jakim zostały zdefiniowane. Oprócz tego można zdefiniować etykiety tymczasowe, które także mogą posiadać zasięg lokalny lub globalny.

- `Zasięg globalny etykiety` oznacza, że jest ona widoczna z każdego miejsca w programie, niezależnie czy jest to makro `.MACRO`, procedura `.PROC` czy obszar lokalny `.LOCAL`.

- `Zasięg lokalny etykiety` oznacza, że jest ona widoczna tylko w konkretnie zdefiniowanym obszarze, np. przez dyrektywy: `.MACRO`, `.PROC`, `.LOCAL`.
- etykiety muszą zaczynać się znakiem `['A'..'Z','a'..'z','_','?','@']`
- pozostałe dopuszczalne znaki etykiety to `['A'..'Z','a'..'z','0'..'9','_','?','@']`
- etykiety występują zawsze na początku wiersza
- etykiety poprzedzone "białymi znakami" powinny kończyć się znakiem `':'` aby uniknąć błędnej interpretacji takiej etykiety jako makra
- w adresowaniu etykieta może być poprzedzona znakiem ':' informuje to asembler że odwołujemy się do etykiety w bloku głównym programu (odwołujemy się do etykiety globalnej)

  Przykład definicji etykiet:

      ?nazwa   EQU  $A000      ; definicja etykiety tymczasowej globalnej
      nazwa     =   *          ; definicja etykiety globalnej
      nazwa2=12                ; definicja etykiety globalnej
      @?nazwa  EQU  'a'+32     ; definicja etykiety globalnej
        name: equ 12           ; definicja etykiety globalnej nie zaczynającej się od pierwszego znaku wiersza
               nazwa: = 'v'    ; definicja etykiety globalnej nie zaczynającej się od pierwszego znaku wiersza

  W porównaniu do QA/XASM doszła możliwość użycia znaku zapytania `'?'` i "małpki" `'@'` w nazwach etykiet.

  Użycie znaku kropki `'.'` w nazwie etykiety jest dopuszczalne, jednak nie zalecane. Znak kropki zarezerwowany jest do oznaczania rozszerzenia mnemonika, do oznaczenia dyrektyw assemblera, w adresowaniu nowych struktur `MADS-a`.

  Znak kropki `'.'` na początku nazwy etykiety sugeruje że jest to dyrektywa assemblera, natomiast znak zapytania `'?'` na początku etykiety oznacza etykietę tymczasową, taką której wartość może się zmieniać wielokrotnie w trakcie asemblacji.

  `

  ## Etykiety anonimowe

  `

  W celu zapewnienia przejrzystości kodu użycie etykiet anonimowych ograniczone jest tylko dla skoków warunkowych oraz do 10-u wystąpień w przód/tył.

  Dla etykiet anonimowych został zarezerwowany znak '@', po takim znaku musi wystąpić znak określający skok w przód '+' lub w tył '-'. Dodatkowo można określić numer wystąpienia etykiety anonimowej z zakresu [0..9], brak numeru wystąpienia oznacza domyślnie 0 (zero).

       @+[0..9]     ; forward
       @-[0..9]     ; backward

       @+           ; @+0
       @-           ; @-0

      @ dex   ---- -------
        bne @+   |  --   |
        stx $80  |   |   |
      @ lda #0   |  --   |
        bne @- ---       |
        bne @-1  ---------

        ldx #6
      @ lda:cmp:req 20
      @ dex
        bne @-1

  `

  ## Etykiety lokalne

  `

  Każda definicja etykiety w obrębie makra `.MACRO`, procedury `.PROC` czy obszaru lokalnego `.LOCAL` domyślnie jest zasięgu lokalnego, innymi słowy jest lokalna. Takich etykiet użytkownik nie musi dodatkowo oznaczać.

  Etykiety lokalne definiujemy używając n/w równoważnych pseudo rozkazów:

       EQU
        =

  Aby mieć dostęp do etykiet o zasięgu globalnym (czyli zdefiniowanych poza makrem `.MACRO`, procedurą `.PROC`, obszarem lokalnym `.LOCAL`) i o takich samych nazwach jak lokalne, należy użyć operatora `':'`, np.:

      lp   ldx #0         ; definicja globalna etykiety LP

           test
           test

      test .macro

            lda :lp       ; znak ':' przed etykietą odczyta wartość etykiety globalnej LP

            sta lp+1      ; odwołanie do etykiety lokalnej LP w obszarze makra
      lp    lda #0        ; definicja etykiety lokalnej LP w obszarze makra

           .endm

  W w/w przykładzie występują definicje etykiet o tych samych nazwach (`LP`), lecz każda z nich ma inną wartość i jest innego zasięgu.

  `

  ## Etykiety globalne

  `

  Każda definicja etykiety dokonana w głównym bloku programu poza obszarem makra `.MACRO`, procedury `.PROC` czy obszaru lokalnego `.LOCAL` jest zasięgu globalnego, innymi słowy jest globalna.

  Etykiety globalne definiujemy używając n/w równoważnych pseudo rozkazów:

       EQU
        =

  lub dyrektywy .DEF o składni:

       .DEF :label [= expression]

  Dyrektywa .DEF umożliwia zdefiniowanie etykiety w aktualnym obszarze lokalnym, znak ':' na początku etykiety sygnalizuje etykietę globalną. Użycie dyrektywy o składni .DEF :label pozwala na zdefiniowanie etykiety globalnej z pominięciem aktualnego poziomu lokalności.

  Znak dwukropka ':' na początku etykiety ma specjalne znaczenie, informuje że odwołujemy się do etykiety globalnej, czyli etykiety z głównego bloku programu z pominięciem wszystkich poziomów lokalności.

  Więcej informacji na temat użycia dyrektywy .DEF w rozdziale Dyrektywa .DEF

  Przykład definicji etykiet globalnych:

      lab equ *
         lab2 equ $4000

      	?tmp = 0
      	?tmp += 40

      .proc name

            .def :?nazwa   = $A000
                 .def :nazwa=20

            .local lok1
              .def :@?nazw   = 'a'+32
            .endl

      .endp

  Przykładem zastosowania definicji etykiety globalnej tymczasowej jest m.in. makro `@CALL` (plik `..\EXAMPLES\MACROS\@CALL.MAC`), w którym występuje definicja etykiety tymczasowej `?@STACK_OFFSET`. Jest ona później wykorzystywana przez pozostałe makra wywoływane z poziomu makra `@CALL`, a służy do optymalizacji programu odkładającego parametry na stos programowy.

      @CALL .macro

        .def ?@stack_offset = 0    ; definicja etykiety globalnej tymczasowej ?@stack_offset

        ...
        ...

      @CALL_@ .macro

        sta @stack_address+?@stack_offset,x
        .def ?@stack_offset = ?@stack_offset + 1    ; modyfikacja etykiety ?@stack_offset

       .endm

  `

  ## Etykiety tymczasowe

  `

  Definicja etykiety tymczasowej posiada tą właściwość, że jej wartość może ulegać zmianie wielokrotnie nawet podczas jednego przebiegu asemblacji. Normalnie próba ponownej definicji etykiety kończy się komunikatem `Label declared twice`. Nie będzie takiego komunikatu jeśli jest to etykieta tymczasowa.

  Zasięg etykiet tymczasowych uzależniony jest od obszaru w jakim etykieta została zdefiniowana. Etykiety tymczasowe mogą posiadać zasięg lokalny (Etykiety lokalne) lub globalny (Etykiety globalne).

  Etykietę tymczasową definiuje użytkownik poprzez umieszczenie na początku nazwy etykiety znaku zapytania `'?'`, np.:

       ?label

  Etykiet tymczasowych nie powinno używać się do nazw procedur `.PROC`, makr `.MACRO`, obszarów lokalnych `.LOCAL`, struktur `.STRUCT`, tablic `.ARRAY`.

  Etykiety tymczasowe definiujemy używając n/w równoważnych pseudo rozkazów:

       EQU
        =

  Dodatkowo możemy je modyfikować za pomocą znanych z `C` operatorów:

       -= expression
       += expression
       --
       ++

  W/w operatory modyfikujące dotyczą tylko etykiet tymczasowych, próba ich użycia dla innego typu etykiety skończy się komunikatem błędu `Improper syntax`.

  Przykład użycia etykiet tymczasowych:

      ?loc = $567
      ?loc2 = ?loc+$2000

      	 lda ?loc
      	 sta ?loc2

      ?loc = $123

      	 lda ?loc

  `

  ## Etykiety lokalne w stylu MAE

  `

  Opcja OPT ?+ informuje MADS aby etykiety zaczynające się znakiem '?' interpretował jako etykiety lokalne tak jak robi to MAE. Domyślnie etykiety zaczynające się znakiem '?' traktowane są przez MADS jako Etykiety tymczasowe.

  Przykład użycia etykiet lokalnych w stylu MAE:

             opt ?+
             org $2000

      local1 ldx #7
      ?lop   sta $a000,x
             dex
             bpl ?lop

      local2 ldx #7
      ?lop   sta $b000,x
             dex
             bpl ?lop

  SPARTA DOS X

  `

  ## Budowa plików Sparta DOS X, Atari DOS

  `

  Przedruk z Serious Magazine, autor Qcyk/Dial.

  Plik sam w sobie jest tylko niewiele wartym zbiorem bajtów. Mnóstwo liczb, które mogą oznaczać wszystko, a zarazem nic, jeśli nie wiadomo jak je zinterpretować. Większość plików wyposaża się z tego powodu w różnorodne nagłówki, w których pamiętane są informacje o tym co plik zawiera, ew. jak go potem traktować przy odczycie. Do takich należą również pliki wykonywalne, binarne, czy po prostu: przeznaczone do załadowania z poziomu `DOS'u`. Wszak `DOS` to też program i jak każdy inny ma prawo oczekiwać danych o określonej, znanej mu strukturze.

  Tradycyjne pliki binarne, rozpoznawane przez wszystkie `DOS'y` dla komputerów `Atari XL/XE`, mają budowę blokową, gdzie każdy blok posiada swój nagłówek. Istnieją dwa rodzaje nagłówków:

       1. dta a($ffff),a(str_adr),a(end_adr)

       2. dta a(str_adr),a(end_adr)

  `str_adr` - adres, pod który zostanie załadowany pierwszy bajt danych

  `end_adr` - adres, pod który zostanie załadowany ostatni bajt

  Pierwszy blok w pliku musi mieć nagłówek typu `$ffff`, pozostałe bloki dowolnie. Za nagłówkiem oczywiście powinny znaleźć się dane w ilości:

         (end_adr-str_adr)+1

  Tyle tytułem przypomnienia. Twórcy systemu Sparta DOS X zachowali powyższy standard, dodając jednocześnie kilka nowych typów nagłówków. Ciągle więc mamy do czynienia z plikiem podzielonym na bloki, z tym że rodzajów bloków jest teraz dużo więcej. Oto one:

  #### 1. Blok nierelokowalny (ładowany pod stały adres w pamięci):

          dta a($fffa),a(str_adr),a(end_adr)

  Jest to to samo co blok `$ffff` - nie ma znaczenia, który zostanie użyty. `$fffa` będzie jednak wyraźnie wskazywać, że program jest przeznaczony dla `SDX` - inny `DOS` takiego pliku nie odczyta.

  #### 2. Blok relokowalny (ładowany pod `MEMLO` we wskazany rodzaj pamięci):

          dta a($fffe),b(blk_num),b(blk_id)
          dta a(blk_off),a(blk_len)

  `blk_num` - numer bloku w pliku. Każdy blok relokowalny powinien posiadać swój własny numer. Ponieważ adresy ładowania bloków nie są znane, bloki identyfikowane są właśnie poprzez swoje numery. Mogą one przyjmować wartości z zakresu 0-7, z tym że w praktyce stosuje się zwykle numerację od 1 w górę.

  `blk_id` - bity 1-5 stanowią indeks pamięci, do której blok ma zostać załadowany. Spotkałem się z dwoma wartościami:

       $00 - pamięć podstawowa
       $02 - pamięć rozszerzona

  Ustawienie dodatkowo bitu 7 oznacza brak bloku danych. `SDX` nic wtedy nie ładuje, ale rezerwuje pamięć.

  `blk_off` - tzw. przesunięcie adresów w bloku, czyli po prostu adres, pod który był assemblowany kod. Jest to potrzebne przy uaktualnianiu adresów odwołujących się do zawartości bloku.

  `blk_len` - długość bloku. Tyle danych powinno być za nagłówkiem chyba, że jest to blok rezerwujący pamięć wtedy danych nie ma.

  Pisząc kod relokowalny trzeba mieć na uwadze kilka ograniczeń jakie narzuca idea "przemieszczalnego" kodu. Wszystkie adresy odwołujące się do obszaru takiego programu muszą zostać uaktualnione podczas ładowania, w związku z tym nie można używać sekwencji takich jak np.:

             lda coś
             ...
            coś equ *
             ...
          Zamiast tego, pozostaje np.:
             lda _coś
             ldx _coś+1
             ...
            _coś dta a(coś)
             ...
            coś equ *

  #### 3. Blok aktualizacji adresów odnoszących się do bloku relokowalnego:

          dta a($fffd),b(blk_num),a(blk_len)

  `blk_num` - numer bloku, do którego odnoszą się uaktualniane adresy.

  `blk_len` - długość bloku aktualizacji (bez nagłówka). Jest ona ignorowana.

  Adresy są uaktualniane poprzez dodanie do adresu istniejącego różnicy pomiędzy adresem, pod który został załadowany wskazany blok relokowalny, a wartością `blk_off` (adresem asemblacji) tego bloku. Można to przedstawić wzorem:

             ADR=ADR+(blk_adr-blk_off)

  "Ciało" bloku aktualizacji stanowią wskaźniki do poprawianych adresów oraz rozkazy specjalne. Wskaźnik jest liczbą z zakresu `$00-$fb` i oznacza przesunięcie względem miejsca poprzedniej aktualizacji. Miejsce to jest pamiętane przez program ładujący jako bezpośredni adres, nazwijmy go licznikiem aktualizacji. Licznik ten można zainicjować za pomocą funkcji specjalnych, którymi są liczby większe od `$fb`:

  `$fc` oznacza koniec bloku aktualizacji,

  `$fd,a(ADDR)` następuje aktualizacja adresu wskazanego bezpośrednio przez `ADDR`. Tym samym wartość `ADDR` jest wpisywana do licznika aktualizacji i od niej będą liczone kolejne przesunięcia,

  `$fe,b(blk_num)` do licznika aktualizacji wstawiany jest adres bloku wskazanego przez `blk_num`, czyli kolejne aktualizacje będą się odnosiły do kodu zawartego w tym bloku,

  `$ff` licznik aktualizacji zwiększany jest o `$fa` (bez aktualizacji adresu).

  #### 4. Blok aktualizacji adresów procedur zdefiniowanych symbolami:

          dta a($fffb),c'SMB_NAME',a(blk_len)

  `SMB_NAME` - symboliczna nazwa procedury (lub tablicy, rejestru systemowego itp.) Osiem znaków w kodzie `ATASCII`,

  `blk_len` - jak w bloku `$fffd`.

  Po nagłówku występuje ciąg wskaźników określających położenie adresów do zaktualizowania - identycznie jak w bloku `$fffd`. Adresy są zmieniane poprzez dodanie do istniejącego adresu, adresu procedury określonej symbolem. Pozwala to na wykorzystywanie w programach procedur, których adresów nie znamy, np. procedur dodawanych przez inne programy uruchamiane w środowisku `SDX`. Także procedury systemowe powinny być wykorzystywane w ten sposób, przecież mogą one mieć różne adresy w różnych wersjach Sparty.

  #### 5. Blok definicji nowych symboli:

          dta a($fffc),b(blk_num),a(smb_off)
          dta c'SMB_NAME'

  `blk_num` - numer bloku, w którym znajduje się definiowana procedura. Wynika z tego, że procedura musi być załadowana jako blok relokowalny.

  `smb_off` - przesunięcie adresu procedury w bloku, czyli offset procedury względem początku bloku (pierwszy bajt ma numer 0) powiększony o wartość `blk_off` tego bloku. Inaczej jest to adres pod jaki procedura została zassemblowana, `SMB_NAME` - symboliczna nazwa definiowanej procedury.

  Bloki typu `$fffb`, `$fffc`, `$fffd` nie są na stałe zatrzymywane w pamięci. System wykorzystuje je tylko podczas ładowania programu.

  `

  ## Programowanie Sparta DOS X (SDX)

  `

  Składnia dotycząca obsługi `Sparta DOS X`, zaczerpnięta została z `FastAssemblera` autorstwa `Marka Goderskiego`, poniżej cytat z instrukcji dołączonej do `FA`. Pliki źródłowe `*.FAS` można obecnie bez większych problemów asemblować `MADS-em`. Rozkazy relokowalne mają zawsze 2 bajtowy argument, nie ma możliwości relokowania 3 bajtowych argumentów `(65816)`.

  Najważniejszą nowością w `SDX` dla programisty jest możliwość prostego pisania programów relokowalnych. Ponieważ procesor `MOS 6502` nie posiada adresowania względnego, (prócz krótkich skoków warunkowych) programiści z `ICD` zastosowali specjalne mechanizmy ładowania bloków programu. Cały proces polega na załadowaniu bloku, a następnie specjalnego bloku aktualizacji adresów. Wszystkie adresy w bloku programu są liczone od zera. Wystarczy więc dodać do nich wartość `memlo` aby otrzymać adres właściwy. Które adresy zwiększyć, a które pozostawić? Właśnie po to jest specjalny blok aktualizacji który zawiera wskaźniki (specjalnie kodowane) do tychże adresów. Tak więc po bloku lub blokach `RELOC` obowiązkowe jest wykonanie `UPDATE ADRESS` dla poprawnego działania programu. Również po blokach `SPARTA` w których rozkazy (lub wektory) odwołują się do bloków `RELOC` lub `EMPTY` obowiązkowe jest wykonanie `UPDATE ADRESS`.

  Następną innowacją jest wprowadzenie symboli. Otóż niektóre procedury usługowe `SDX` zostały zdefiniowane za pomocą nazw! Nazwy te maja zawsze 8 liter (podobnie jak nazwy plików). Zamiast korzystać z tablic wektorów lub skoków (jak w OS) korzystamy z symboli definiowanych `SMB`. Po wczytaniu bloku lub bloków programu `SDX` ładuje blok aktualizacji symboli i w podobny sposób jak przy blokach relokowalnych zamienia adresy w programie. Symbole mogą być używane dla bloków `RELOC` i `SPARTA`.

  Programista może zdefiniować własne symbole zastępujące `SDX` lub zupełnie nowe dla wykorzystania przez inne programy. Robi się to poprzez blok `UPDATE NEW`. Trzeba jednak wiedzieć że nowy symbol musi być zawarty w bloku `RELOC`.

  Liczba bloków `RELOC` i `EMPTY` jest ograniczona do 7 przez `SDX`.

  Bloki takie można łączyć w łańcuchy np:

             blk sparta $600
             ...

             blk reloc main
             ...

             blk empty $100 main
             ...

             blk reloc extended
             ...

             blk empty $200 extended

  Oznacza to że rozkazy w tych blokach mogą odwoływać się do wszystkich bloków w łańcuchu.

  Łańcuch taki nie jest przerywany przez aktualizację adresów, lub symboli ale jest niszczony przez definicję nowego symbolu, oraz inne bloki (np: dos).

  `Uwaga:` Łańcuch taki ma sens tylko wtedy gdy wszystkie jego bloki ładują się do tej samej pamięci, lub gdy program przy odpowiednich odwołaniach przełącza pamięć.

  `Uwaga:` Rozkazy i wektory w blokach `RELOC` i `EMPTY` nie powinny odwoływać się do bloków `SPARTA!` Może to spowodować błąd gdy użytkownik załaduje program komendą `LOAD`, a użyje go po dłuższym czasie. O ile bloki `RELOC` i `EMPTY` były bezpieczne to nigdy nie wiadomo co jest w pamięci tam gdzie ostatnio był blok `SPARTA!`

  Równie niebezpieczne jest używanie odwołań do bloków `RELOC` i `EMPTY` przez bloki `SPARTA` (powód jak wyżej), jednakże podczas instalowania nakładek (*.sys) z użyciem `INSTALL` jest to czasem niezbędne, stąd jest dopuszczalne. Można także inicjować blok `SPARTA` (porzez `$2E2`) będzie on wtedy zawsze uruchomiony, a potem już zbędny.

  `Uwaga:` Pomiędzy blokami `SPARTA`, a `RELOC` i `EMPTY` może dojść do kolizji adresów! `FA` rozpoznaje odwołania do innych bloków poprzez adresy, przyjmując `PC` dla `RELOC` i `EMPTY` od `$1000`, tak więc gdy mieszamy te bloki należy mieć pewność ze `SPARTA` leży poniżej `$1000` (np:`$600`) lub powyżej ostatniego bloku relokowalnego, zazwyczaj wystarcza `$4000`. Błąd taki nie jest przez kompilator wykrywany !

  KOD RELOKOWALNY

  Kod relokowalny to taki kod, który nie ma z góry określonego adresu ładowania do pamięci komputera, kod taki musi zadziałać niezależnie od adresu załadowania. W Atari XE/XL kod relokowalny udostępnia system Sparta DOS X (SDX), więcej na ten temat można przeczytać w rozdziale Programowanie Sparta DOS X.

  Kod relokowalny dla SDX posiada podstawowe ograniczenie jakim jest relokowanie tylko adresów typu WORD, nie ma także obsługi rozkazów CPU 65816. MADS udostępnia możliwość generowania kodu relokowalnego w formacie SDX jak i swoim własnym niekompatybilnym z SDX, który znosi wcześniej wymienione ograniczenia.

  Format zapisu pliku z kodem relokowalnym MADS-a jest podobny do tego znanego z SDX, podobnie występuje tutaj blok główny i bloki dodatkowe z informacją o adresach które należy poddać relokacji. MADS stosuje prostszy zapis bloków aktualizacji, bez "kompresji" jaką stosuje SDX.

  Zalety kodu relokowalnego MADS-a:

- uwzględnia rozmiar argumentów dla CPU 6502, 65816
- można używać wszystkie rozkazy CPU, bez ograniczeń
- pozwala na relokacje młodszych i starszych bajtów adresu

  Ograniczenia kodu relokowalnego MADS-a:

- deklaracji etykiet przez EQU dokonujemy przed blokiem .RELOC
- jeśli chcemy zdefiniować nową etykietę w bloku .RELOC musimy jej nazwę poprzedzić spacją lub tabulatorem (etykieta globalna)
- nie można używać pseudo rozkazów ORG, RMB, LMB, NMB oraz dyrektywy .DS
- nie można relokować najstarszego bajtu ze słowa 24bit, np. lda ^$121416 Przykładem tego jak prosto można stworzyć kod relokowalny jest plik ..\EXAMPLES\TETRIS_RELOC.ASM, który od strony użytej listy rozkazów CPU i pseudo rozkazów definiujących dane niczym nie różni się od wersji nierelokowalnej ..\EXAMPLES\TETRIS.ASM

  `

  ## Blok relokowalny .RELOC

  `

  Blok relokowalny MADS-a zostanie wygenerowany po użyciu dyrektywy:

       .RELOC [.BYTE|.WORD]

  Blok aktualizacji dla bloku relokowalnego MADS-a wywołujemy używając pseudo rozkazu BLK:

       BLK UPDATE ADDRESS

  Po dyrektywie .RELOC możliwe jest podanie typu bloku relokowalnego (.BYTE, .WORD), domyślnie jest to typ .WORD. Typ .BYTE dotyczy bloku przeznaczonego do umieszczenia wyłącznie na stronie zerowej (będzie zawierał rozkazy strony zerowej), MADS będzie asemblował taki blok od adresu $0000. Typ .WORD oznacza że MADS będzie asemblował blok relokowalny od adresu $0100 i będzie przeznaczony do umieszczenia w dowolnym obszarze pamięci (nie będzie zawierał rozkazów strony zerowej).

  Nagłówek bloku .RELOC przypomina ten znany z DOS-a, dodatkowo został on rozszerzony o 10 nowych bajtów czyli w sumie zajmuje 16 bajtów, np.:

      HEADER            .WORD = $FFFF
      START_ADDRESS     .WORD = $0000
      END_ADDRESS       .WORD = FILE_LENGTH-1
      MADS_RELOC_HEADER .WORD = $524D
      UNUSED            .BYTE = $00
      CONFIG            .BYTE (bit0)
      @STACK_POINTER    .WORD
      @STACK_ADDRESS    .WORD
      @PROC_VARS_ADR    .WORD

  `MADS_RELOC_HEADER` | `zawsze o wartości $524D co odpowiada znakom 'MR' (M-ADS R-ELOC)`
  `FILE_LENGTH` | `to długość bloku relokowalnego bez 16 bajtowego nagłówka`
  `CONFIG` | `wykorzystany jest obecnie tylko bit0 tego bajtu, bit0=0 oznacza blok relokowalny asemblowany od adresu $0000, bit0=1 blok relokowalny asemblowany od adresu $0100`

  Ostatnie 6 bajtów zawiera informację o wartościach etykiet potrzebnych do działania stosu programowego @STACK_POINTER, @STACK_ADDRESS, @PROC_VARS_ADR jeśli zostały użyte podczas asemblacji bloków relokowalnych. Jeśli poszczególne bloki .RELOC zostały zasemblowane z różnymi wartościami tych etykiet i są one linkowane wystąpi wówczas komunikat ostrzeżenia Incompatible stack parameters. Jeśli stos programowy nie został użyty wartościami tych etykiet są zera.

  Pseudo rozkaz .RELOC powoduje przełączenie MADS-a w tryb generowania kodu relokowalnego z uwzględnianiem rozmiaru argumentów rozkazów CPU 6502, 65816. W obszarze takiego kodu niemożliwe jest używanie pseudo rozkazów ORG, LMB, NMB, RMB oraz dyrektywy .DS. Niemożliwy jest powrót MADS-a do trybu generowania kodu nie relokowalnego, możliwe jest wygenerowanie więcej niż jednego bloku .RELOC.

  Użycie dyrektywy .RELOC powoduje dodatkowo zwiększenie licznika wirtualnych banków MADS-a, przez co taki obszar staje się lokalny i niewidoczny dla innych bloków. Więcej informacji na temat wirtualnych banków w rozdziale Wirtualne banki pamięci (OPT B-).

  Na końcu bloku .RELOC wymagane jest wygenerowanie bloku aktualizacji, realizuje to pseudo rozkaz BLK z identyczną składnią jak dla bloku relokowalnego SDX ("BLK UPDATE ADDRESS"). Format zapisu takiego bloku aktualizacji nie jest jednak identyczny z SDX, ma następującą postać:

      HEADER       WORD ($FFEF)
      TYPE         CHAR (B-YTE, W-ORD, L-ONG, D-WORD, <, >)
      DATA_LENGTH  WORD
      DATA         WORD [BYTE]

  `HEADER` | `zawsze o wartości $FFEF`
  `TYPE` | `typ danych zapisany jest na bitach 0..6 tego bajtu i określa typ modyfikowanych adresów, znak "<" oznacza młodszy bajt adresu, znak ">" oznacza starszy bajt adresu.`
  `DATA_LENGTH` | `to liczba 2-bajtowych danych (adresów) do modyfikacji`
  `DATA` | `to właściwy ciąg danych służących modyfikacji głównego bloku relokowalnego. Pod wskazanym tutaj adresem należy odczytać wartość typu TYPE a następnie zmodyfikować na podstawie nowego adresu ładowania.`

  Wyjątek stanowi blok aktualizacji dla starszych bajtów adresów ">", dla takiego bloku w DATA zapisywany jest jeszcze dodatkowy bajt BYTE (młodszy bajt modyfikowanego adresu). Aby dokonać aktualizacji starszych bajtów, musimy odczytać bajt spod adresu WORD w DATA, dodać go do aktualnego adresu relokacji i dodać jeszcze młodszy bajt z BYTE w DATA. Tak nowo obliczony starszy bajt umieszczamy pod adresem WORD z DATA.

  `

  ## Symbole zewnętrzne

  `

  Symbole zewnętrzne informują, że zmienne i procedury które reprezentują będą znajdowały się gdzieś na zewnątrz, poza aktualnym programem. Nie musimy określać gdzie. Musimy jedynie podać ich nazwy oraz typy. W zależności od typu danych jakie reprezentuje symbol instrukcje asemblera tłumaczone są na odpowiednie kody maszynowe, asembler musi znać rozmiar używanych danych.

  Aktualnie nie istnieje możliwość dokonywania operacji na symbolach external typu '^' (najstarszy bajt).

  Symbole zewnętrzne mogą być używane w blokach relokowalnych .RELOC jak i w zwykłych blokach DOS-a.

  Symbole zewnętrzne (external) deklarujemy używając pseudo rozkazu EXT lub dyrektywy .EXTRN:

      label EXT type
      label .EXTRN type
      .EXTRN label1,label2,label3... type

  Blok aktualizacji dla symboli external wywołujemy używając pseudo rozkazu BLK:

       BLK UPDATE EXTERNAL

  UWAGA: Zostaną zapisane symbole, które zostały użyte w programie.

  Symbole external nie mają zdefiniowanej wartości tylko typ (`.BYTE, .WORD, .LONG , .DWORD`) np.:

      name EXT .BYTE

      label_name EXT .WORD

       .EXTRN label_name .WORD

      wait EXT .PROC (.BYTE delay)

  Symbol external z deklaracją procedury .PROC przyjmuje domyślnie typ .WORD, próba odwołania się do nazwy takiej etykiety zostanie potraktowana przez MADS jako próba wywołania procedury, więcej na temat wywołań procedur .PROC w rozdziale Procedury. W procesie asemblacji po napotkaniu odwołania do symbolu external zawsze podstawiane są zera.

  Symbole external przydać się nam mogą wówczas gdy chcemy zasemblować program oddzielnie, niezależnie od reszty właściwego programu. W takim programie występują wówczas najczęściej odwołania do procedur, zmiennych które zostały zdefiniowane gdzieś indziej, na zewnątrz, a my nie znamy ich wartości tylko typ. W tym momencie z pomocą przychodzą symbole external, które umożliwiają asemblację takiego programu mimo braku właściwych procedur czy zmiennych.

  Innym zastosowaniem symboli external mogą być tzw. "pluginy" programy zewnętrzne połączone z programem głównym i realizujące dodatkowe czynności. Są to swoistego rodzaje biblioteki, wykorzystujące procedury programu głównego, rozszerzające jego funkcjonalność. Aby stworzyć taki plugin należałoby określić jakie procedury udostępnia program główny (ich nazwy+parametry i typ) oraz stworzyć procedurę odczytu pliku z symbolami external, ta procedura realizowałaby dołączanie pluginów do głównego programu.

  Poniżej format zapisu nagłówka w pliku z symbolami external typu B-YTE, W-ORD, L-ONG i D-WORD po wywołaniu przez BLK UPDATE EXTERNAL:

      HEADER        WORD ($FFEE)
      TYPE          CHAR (B-YTE, W-ORD, L-ONG, D-WORD, <, >)
      DATA_LENGTH   WORD
      LABEL_LENGTH  WORD
      LABEL_NAME    ATASCII
      DATA          WORD .. .. ..

  `HEADER` | `zawsze o wartości $FFEE`
  `TYPE` | `typ danych zapisany jest na bitach 0..6 tego bajtu i określa typ modyfikowanych adresów`
  `DATA_LENGTH` | `to liczba 2-bajtowych danych (adresów) do modyfikacji`
  `LABEL_LENGTH` | `to długość nazwy symbolu wyrażona w bajtach`
  `LABEL_NAME` | `to nazwa symbolu w kodach ATASCII`
  `DATA` | `właściwy ciąg danych służących modyfikacji głównego bloku relokowalnego. Pod wskazanym tutaj adresem należy odczytać wartość typu TYPE a następnie zmodyfikować na podstawie nowej wartości symbolu.`

  Przykładem zastosowania symboli external i struktur .STRUCT jest przykładowa biblioteka prymitywów graficznych (PLOT, LINE, CIRCLE) z katalogu ..\EXAMPLES\LIBRARIES\GRAPHICS\LIB. Poszczególne moduły wykorzystują tutaj dość sporą liczbę zmiennych na stronie zerowej, jeśli chcemy aby adresy tych zmiennych były relokowalne musielibyśmy każdą z osobna zmienną zadeklarować jako symbol zewnętrzny przez EXT (lub .EXTRN). Możemy to uprościć wykorzystując tylko jeden symbol zewnętrzny i strukturę danych .STRUCT. Za pomocą struktur definiujemy "mapę" zmiennych ZP, potem jeden symbol external ZPAGE typu .BYTE bo chcemy aby zmienne były na stronie zerowej. Teraz odwołując się do zmiennej musimy zapisać to w sposób wymuszający relokowalność np. ZPAGE+ZP.DX i tak powstał moduł całkowicie relokowalny z możliwością zmiany adresu zmiennych w przestrzeni strony zerowej.

  `

  ## Symbole publiczne

  `

  Symbole publiczne udostępniają zmienne i procedury występujące w bloku relokowalnym pozostałej części asemblowanego programu. Dzięki symbolom publicznym możemy odwoływać się do zmiennych i procedur "zaszytych" np. w bibliotekach.

  Symbole publiczne mogą być używane w blokach relokowalnych .RELOC jak i w zwykłych blokach DOS-a.

  MADS sam rozpoznaje czy podana do upublicznienia etykieta jest zmienną, stałą czy też procedurą zadeklarowną przez .PROC, nie jest wymagana żadna dodatkowa informacja jak w przypadku symboli zewnętrznych.

  Symbole publiczne deklarujemy używając n/w dyrektyw:

       .PUBLIC label [,label2,...]
       .GLOBAL label [,label2,...]
       .GLOBL label [,label2,...]

  Dyrektywy .GLOBAL i .GLOBL zostały dodane z myślą o kompatybilności z innymi assemblerami, ich znaczenie jest identyczne z dyrektywą .PUBLIC.

  Blok aktualizacji dla symboli publicznych wywołujemy używając pseudo rozkazu BLK:

       BLK UPDATE PUBLIC

  Poniżej format zapisu nagłówka w pliku z symbolami publicznymi po wywołaniu przez BLK UPDATE PUBLIC:

      HEADER        WORD ($FFED)
      LENGTH        WORD
      TYPE          BYTE (B-YTE, W-ORD, L-ONG, D-WORD)
      LABEL_TYPE    CHAR (C-ONSTANT, V-ARIABLE, P-ROCEDURE, A-RRAY, S-TRUCT)
      LABEL_LENGTH  WORD
      LABEL_NAME    ATASCII
      ADDRESS       WORD

  MADS automatycznie dobiera odpowiedni typ dla upublicznianej etykiety:

- C-ONSTANT
etykieta nie poddająca się relokacji
- V-ARIABLE
etykieta poddająca się relokacji
- P-ROCEDURE
procedura zadeklarowana przez .PROC, podlega relokacji
- A-RRAY
tablica zadeklarowana przez .ARRAY, podlega relokacji
- S-TRUCT
struktura zadeklarowana przez .STRUCT, nie podlega relokacji Jeśli symbol dotyczy struktury .STRUCT wówczas zapisywane są dodatkowe informacje (typ pola struktury, nazwa pola struktury, liczba powtórzeń pola struktury):

    STRUCT_LABEL_TYPE    CHAR (B-YTE, W-ORD, L-ONG, D-WORD)
    STRUCT_LABEL_LENGTH  WORD
    STRUCT_LABEL_NAME    ATASCII
    STRUCT_LABEL_REPEAT  WORD

Jeśli symbol dotyczy tablicy .ARRAY wówczas zapisywane są dodatkowe informacje (maksymalny zadeklarowany indeks tablicy, typ zadeklarowanych pól tablicy):

    ARRAY_MAX_INDEX  WORD
    ARRAY_TYPE       CHAR (B-YTE, W-ORD, L-ONG, D-WORD)

Jeśli symbol dotyczy procedury .PROC wówczas zapisywane są dodatkowe informacje, niezależnie od tego czy procedura miała czy też nie miała zadeklarowane parametry:

    PROC_CPU_REG  BYTE (bits 00 - regA, 01 - regX, 10 - regY)
    PROC_TYPE     BYTE (D-EFAULT, R-EGISTRY, V-ARIABLE)
    PARAM_COUNT   WORD

Dla symboli dotyczących procedur .REG zapisywane są już teraz tylko typy tych parametrów w ilości PARAM_COUNT:

    PARAM_TYPE    CHAR (B-YTE, W-ORD, L-ONG, D-WORD)
    ...
    ...

Dla symboli dotyczących procedur .VAR zapisywane są typy parametrów i ich nazwy. PARAM_COUNT określa całkowitą długość tych danych:

    PARAM_TYPE    CHAR (B-YTE, W-ORD, L-ONG, D-WORD)
    PARAM_LENGTH  WORD
    PARAM_NAME    ATASCII
    ...
    ...

`HEADER` | `zawsze o wartości $FFED`
`LENGTH` | `to liczba symboli zapisanych w bloku aktualizacji`
`TYPE` | `typ symbolizowanych danych B-YTE, W-ORD, L-ONG, D-WORD`
`LABEL_TYPE` | `typ symbolu: V-ARIABLE, C-ONSTANT, P-ROCEDURE, A-RRAY, S-TRUCT Dla typu P zapisywane są dodatkowe informacje: PROC_CPU_REG, PROC_TYPE, PARAM_COUNT, PARAM_TYPE Dla typu A zapisywane są dodatkowe informacje: ARRAY_MAX_INDEX, ARRAY_TYPE Dla typu S zapisywane są dodatkowe informacje: STRUCT_LABEL_TYPE, STRUCT_LABEL_LENGTH, STRUCT_LABEL_NAME, STRUCT_LABEL_REPEAT`
`LABEL_LENGTH` | `długość etykiety symbolu publicznego wyrażona w bajtach`
`LABEL_NAME` | `etykieta symbolu publicznego zapisana w kodach ATASCII`
`ADDRESS` | `adres przypisany symbolowi w bloku relokowalnym .RELOC. Ta wartość zostaje poddana relokacji poprzez dodanie do niej aktualnego adresu asemblacji.`
`PROC_CPU_REG` | `informacja o kolejności użycia rejestrów CPU dla procedury typu .REG`
`PROC_TYPE` | `typ procedury: D-EFAULT domyślny typ wykorzystujący do przekazywania parametrów stos programowy MADS-a R-EGISTRY parametry do procedury przekazywane są przez rejestry CPU (.REG) V-ARIABLE parametry do procedury przekazywane są przez zmienne (.VAR)`
`PARAM_COUNT` | `informacja o liczbie parametrów procedury (.REG) lub całkowitej długości danych zawierających informację o typie parametrów i ich nazwach (.VAR)`
`PARAM_TYPE` | `typ parametrów zapisany za pomocą znaków 'B', 'W', 'L', 'D'`
`PARAM_LENGTH` | `długość nazwy parametru (.VAR)`
`PARAM_NAME` | `nazwa parametru w kodach ATASCII (.VAR)`

`

## .LONGA, .LONGI

`

     .LONGA ON|OFF
     .LONGI ON|OFF

Dyrektywa .LONGA informuje assembler o rozmiarze rejestru akumulatora, 16bit gdy ON, 8bit gdy OFF.

Dyrektywa .LONGI informuje assembler o rozmiarze rejestrów indeksowych XY, 16bit gdy ON, 8bit gdy OFF.

Dyrektywy wpływają na rozmiar argumentu przy adresowaniu absolutnym CPU 65816.

`

## Linkowanie .LINK

`

     .LINK 'filename'

Dyrektywa .LINK wymaga podania jako parametru nazwy pliku do relokacji. Akceptowane są tylko pliki DOS Atari, pliki SDX nie są akceptowane.

Jeśli adres ładowania pliku jest inny niż $0000 oznacza to że plik nie zawiera kodu relokowalnego, jednak może zawierać bloki aktualizacji dla symboli zewnętrznych i publicznych. Dyrektywa .LINK akceptuje pliki o dowolnym adresie ładowania, jednak relokacji poddawane są tylko te o adresie ładowania $0000, więcej szczegółów na temat budowy takiego pliku zostało zawartych w rozdziale Blok relokowalny .RELOC.

Dyrektywa .LINK pozwala na łączenie kodu relokowalnego z nierelokowalnym. MADS na podstawie bloków aktualizacji dokonuje automatycznej relokacji takiego pliku. Uwzględniane są wszystkie 3 rodzaje bloków aktualizacji (ADDRESS, EXTERNAL, PUBLIC).

Nie ma ograniczeń co do adresu pod którym umieszczany jest plik relokowalny.

Jeśli blok relokowalny do działania wymaga stosu programowego MADS-a wówczas etykiety @STACK_POINTER, @STACK_ADDRESS, @PROC_VARS_ADR zostaną automatycznie zaktualizowane na podstawie nagłówka bloku .RELOC. Wymagane jest aby bloki .RELOC i program główny operowały na tym samym stosie programowym jeśli jest on konieczny.

MNEMONIKI

`

## Dostępne rozkazy 6502

`

       LDA   LDX   LDY   STA   STX   STY   ADC   AND
       ASL   SBC   JSR   JMP   LSR   ORA   CMP   CPY
       CPX   DEC   INC   EOR   ROL   ROR   BRK   CLC
       CLI   CLV   CLD   PHP   PLP   PHA   PLA   RTI
       RTS   SEC   SEI   SED   INY   INX   DEY   DEX
       TXA   TYA   TXS   TAY   TAX   TSX   NOP   BPL
       BMI   BNE   BCC   BCS   BEQ   BVC   BVS   BIT

Możliwe jest użycie rozszerzenia mnemonika po znaku kropki `'.'` dla rozkazów typu LDA, LDX, LDY, STA, STX, STY:

       .b lub .z          BYTE
       .a lub .w lub .q   WORD

    np.
       lda.w $80   ; AD 80 00
       lda   $80   ; A5 80

`

## Dostępne nielegalne rozkazy 6502

`

       ASO   RLN   LSE   RRD   SAX   LAX   DCP   ISB
       ANC   ALR   ARR   ANE   ANX   SBX   LAS   SHA
       SHS   SHX   SHY   NPO   CIM

``

## Dostępne rozkazy 65816

Oczywiście dostępne są rozkazy `6502`, a oprócz nich:

       STZ   SEP   REP   TRB   TSB   BRA   COP   MVN
       MVP   PEA   PHB   PHD   PHK   PHX   PHY   PLB
       PLD   PLX   PLY   RTL   STP   TCD   TCS   TDC
       TSC   TXY   TYX   WAI   WDM   XBA   XCE   INA
       DEA   BRL   JSL   JML

Możliwe jest użycie rozszerzenia mnemonika w stylu XASM a:, z:, r: ,np.:

     XASM        MADS
     lda a:0     lda.a 0
     ldx z:0     lda.z 0

     org r:$40   org $40,*

Możliwe jest użycie rozszerzenia mnemonika po znaku kropki `'.'` dla rozkazów typu LDA, LDX, LDY, STA, STX, STY:

       .b lub .z          BYTE
       .a lub .w lub .q   WORD
       .t lub .l          TRIPLE, LONG (24bit)

    np.
       lda.w #$00   ; A9 00 00
       lda   #$80   ; A9 80

Wyjątki stanowią rozkazy n/w, którym nie można zmienić rozmiaru rejestru w adresowaniu absolutnym (niektóre assemblery nie wymagają dla tych rozkazów podania znaku `'#'`, jednak `MADS` wymaga tego)

`

### #$xx

`

       SEP   REP   COP

`

### #$xxxx

`

       PEA

Innym wyjątkiem jest tryb adresowania pośredni długi, który reprezentowany jest przez nawiasy kwadratowe `[ ]`. Jak wiemy tego typu nawiasy wykorzystywane są też do obliczania wyrażeń, jednak jeśli asembler napotka pierwszy znak `'['` uzna to za tryb adresowania pośredni długi i jeśli nie zasygnalizowaliśmy chęci używania `65816` wystąpi błąd z komunikatem `Illegal adressing mode`. Aby "oszukać" assembler wystarczy dać przed kwadratowym nawiasem otwierającym `'['` znak `'+'`.

     lda [2+4]     ; lda [6]
     lda +[2+4]    ; lda 6

DETEKCJA CPU

`

## Detekcja CPU6502, CPU65816

` Przykład zaczerpnięty ze strony http://www.s-direktnet.de/homepages/k_nadj/cputest.html. Program potrafi zdiagnozować obecność jednego z mikroprocesorów: `6502`, `65C02`, `65816`.

    /*

    How to detect on which CPU the assembler code is running

    (This information is from Draco, the author of SYSINFO 2.0)

    You can test on plain 6502-Code if there is a 65c816 CPU, the 16-Bit processor avaible
    in some XLs as a turbo-board, avaible. Draco told me how to do this:

    First we make sure, whether we are running on NMOS-CPU (6502) or CMOS (65c02,65c816).
    I will just show the "official" way which doesn`t uses "illegal opcodes":

    */

     org $2000

     opt c+

    DetectCPU

     lda #$99
     clc
     sed
     adc #$01
     cld
     beq DetectCPU_CMOS

    DetectCPU_02

     ldx #<_6502
     ldy #>_6502
     jsr $c642

     lda #0
     rts

    DetectCPU_CMOS

     lda #0
     rep #%00000010		;wyzerowanie bitu Z
     bne DetectCPU_C816

    DetectCPU_C02

     ldx #<_65c02
     ldy #>_65c02
     jsr $c642

     lda #1
     rts

    DetectCPU_C816

     ldx <_65816
     ldy >_65816
     jsr $c642

     lda #$80
     rts

    _6502   dta c'6502',$9b
    _65c02  dta c'65c02',$9b
    _65816  dta c'65816',$9b

Następny przykład detekcji CPU, ogranicza się do określenia obecności mikroprocesora `6502` lub `65816`. Program po disasemblacji inaczej wygląda dla `6502`, inaczej dla `65816`. `6502` rozkaz `'inc @'` uzna za `'nop'`, rozkaz `'xba'` uzna za `'sbc #'`. Dzięki takiej "przeźroczystości" możemy być pewni że program nie wykona żadnej nielegalnej operacji i uczciwie rozpozna właściwy CPU. Pomysłodawcą tego zwięzłego i jakże sprytnego testu jest Ullrich von Bassewitz.

     org $2000

     opt c+                 ; 65816 enabled

     lda #0

     inc @                  ; increment accumulator

     cmp #1
     bcc cpu6502

    ; ostateczny test na obecnosc 65816

     xba           ; put $01 in B accu
     dec @         ; A=$00 if 65C02
     xba           ; get $01 back if 65816
     inc @         ; make $01/$02

     cmp #2
     bne cpu6502

    cpu65816

     ldx <text65816
     ldy >text65816
     jsr $c642
     rts

    cpu6502

     ldx <text6502
     ldy >text6502
     jsr $c642
     rts

    text6502  dta c'6502',$9b
    text65816 dta c'65816',$9b

BANKI PAMIĘCI

Pewnie każdemu, kto miał do czynienia z architekturą małego Atari, pojęcie "bank pamięci" kojarzy się z pamięcią rozszerzoną, podzieloną na banki wielkości 16kb, przełączane w obszar `<$4000..$7FFF>`.

`MADS` też może to rozumieć w ten sposób (opcja `OPT B+`, Sprzętowe banki pamięci), jednak domyślnie rozumie to w sposób bardziej wirtualny (opcja `OPT B-`, Wirtualne banki pamięci).

Banków dotyczą n/w pseudo rozkazy:

     LMB #value
     NMB
     RMB

`

### LMB # (Load Memory Bank)

` Ustawiamy licznik banków `MADS-a` na konkretną wartość z zakresu `<$00..$FF>` (BANK = value), np.

     lmb #0
     lmb #bank
     lmb #5 , $6500      ; tylko gdy OPT B+

`

### NMB (Next Memory Bank)

` Zwiększamy o 1 licznik banków `MADS-a` (BANK = BANK + 1).

     nmb
     nmb  $6500          ; tylko gdy OPT B+

`

### RMB (Reset Memory Bank)

` Zerujemy licznik banków `MADS-a` (BANK = 0).

     rmb
     rmb $3500           ; tylko gdy OPT B+
     rmb $8500           ; tylko gdy OPT B+

`MADS` podczas asemblacji, każdej nowo zdefiniowanej etykiecie przypisuje aktualną wartość licznika banków. Programista może mieć wpływ na wartość licznika banków dzięki w/w pseudo rozkazom.

- Etykiety z przypisanym licznikiem banków `MADS-a` =0 są zasięgu `globalnego`.
- Etykiety z przypisanym licznikiem banków `MADS-a` >0 są zasięgu `lokalnego`.
  `

  ## Wirtualne banki pamięci (OPT B-)

  `

  W `MADS` przez pojęcie "wirtualny bank pamięci" rozumiany jest każdy obszar oznaczony przez nowo zdefiniowaną etykietę z przypisaną aktualną wartością licznika banków (domyślnie licznik banków jest wyzerowany). Czyli wirtualny bank pamięci to nie koniecznie obszar pamięci `<$4000..$7FFF>`, ale każda etykieta reprezentująca jakiś obszar kodu programu, której przypisany został kod (wartość licznika banków) z zakresu `<$00..$FF>` przy pomocy odpowiednich pseudo rozkazów oddanych na użytek programisty (`NMB, RMB, LMB`).

  Wyjątek stanowią bloki .RELOC w których nie można samodzielnie zmieniać licznika banków, realizuje to automatycznie MADS, który zwiększa licznik za każdym wywołaniem dyrektywy .RELOC. Licznik banków w takim przypadku przyjmuje wartości z zakresu <$0001..$FFF7>.

  Programista może odczytać wartość licznika banków, który został przypisany etykiecie za pomocą operatora `'='` np.:

      label

       ldx #=label

  W w/w przykładzie do rejestru `regX CPU` zapisaliśmy wartość licznika banków pamięci `MADS-a` przypisany etykiecie `LABEL`.

  Innym przydatnym operatorem może być znak dwukropka `':'` umieszczony na początku nazwy etykiety. Spowoduje to że `MADS` odczyta wartość takiej etykiety pomijając ograniczenia zasięgu, które wprowadza licznik banków `MADS-a`. Niekiedy może spowodować to komplikacje, np. jeśli wystąpiło więcej etykiet o tej samej nazwie ale w różnych obszarach lokalnych albo w obszarach o różnych wartościach licznika wirtualnych banków.

       lmb #5

      label5
       nop

       lmb #6

      label6
       nop

       lda :label5

  Dla w/w przykładu brak operatora `':'` na początku nazwy etykiety w rozkazie `'lda :label5'` skończy się komunikatem błędu `ERROR: Undeclared label LABEL5 (BANK=6)`.

  Wirtualnych banków pamięci można użyc do indeksowania tablicy zawierającej wartości dla `PORTB`. Takie też jest ich zastosowanie w przypadku wybrania opcji `OPT B+`.

  `

  ## Sprzętowe banki pamięci (OPT B+)

  ` Ten tryb działania `MADS-a` można określić jako "czuły na banki" (`BANK SENSITIVE`).

  Sprzętowe banki pamięci są rozszerzeniem wirtualnych banków. Rozumiane są przez `MADS` jako banki rozszerzonej pamięci, włączane w obszar `<$4000..$7FFF>`. Działanie pseudo rozkazów `NMB, RMB, LMB` zostaje rozszerzone o wywołanie makra `@BANK_ADD`, które można znaleźć w katalogu `..\EXAMPLES\MACROS\`.

  W tym trybie działania `MADS` potrzebuje deklaracji konkretnych makr:

       @BANK_ADD
       @BANK_JMP

  oraz potrzebuje definicji etykiet o nazwach:

      @TAB_MEM_BANKS
      @PROC_ADD_BANK

  Etykieta `@TAB_MEM_BANKS` definiuje adres tablicy, z której wartości będą przepisywane do rejestru `PORTB` odpowiedzialnego za przełączanie banków rozszerzonej pamięci. Możemy sobie ułatwić sprawę i skorzystać z gotowej procedury wykrywającej banki rozszerzonej pamięci dołączonej do `MADS-a`, plik `..\EXAMPLES\PROCEDURES\@MEM_DETECT.ASM`.

  Etykieta `@PROC_ADD_BANK` używana jest przez makro `@BANK_ADD` i definiuje adres pod jakim znajdzie się kod programu przełączający bank pamięci rozszerzonej.

  Programista może odczytać wartość licznika banków, który został przypisany etykiecie za pomocą operatora `'='`, np.:

      label

       ldy #=label

  W w/w przykładzie do rejestru `regY` zapisaliśmy wartość licznika banków pamięci `MADS-a` przypisany etykiecie `LABEL`.

  Jeśli licznik banków `MADS-a` = 0 to:
- kod programu musi znajdować się poza obszarem <$4000..$7FFF>
- nowo zdefiniowane etykiety w tym obszarze są globalne
- można odwoływać się do wszystkich zdefiniowanych etykiet bez ograniczeń, bez względu na numer banku
- skok w obszar banku możliwy przy użyciu makra @BANK_JMP (..\EXAMPLES\MACROS\@BANK_JMP.MAC), parametr dla tego makra nie musi być poprzedzony operatorem ':'

  Jeśli licznik banków `MADS-a` > 0 to:
- kod programu musi znajdować się w obszarze <$4000..$7FFF>
- nowo zdefiniowane etykiety w tym obszarze są lokalne
- można odwoływać się tylko do etykiet globalnych i tych zdefiniowanych w obszarze aktualnego banku
- pseudo rozkaz LMB, NMB powoduje wykonanie makra @BANK_ADD, które włącza nowy bank rozszerzonej pamięci na podstawie licznika banków MADS-a oraz ustawia nowy adres asemblacji (domyślnie na $4000)
- pseudo rozkaz RMB powoduje wyzerowanie licznika banków pamięci MADS-a oraz ustawienie nowego adresu asemblacji poza bankiem (domyślnie na $8000)
- skok w obszar innego banku możliwy przy użyciu makra @BANK_JMP (..\EXAMPLES\MACROS\@BANK_JMP), parametr dla tego makra musi być poprzedzony operatorem ':'

  Przykładem wykorzystania tego trybu pracy `MADS-a` jest plik `..\EXAMPLES\XMS_BANKS.ASM`. W tym przykładzie kod programu znajduje się w dwóch różnych bankach rozszerzonej pamięci i wykonuje się jakby był jedną całością.

## HISTORIA

v2.1.0

- dodany komunikat ostrzeżenia 'Buggy indirect jump' w przypadku użycia rozkazu JMP(ABS)
- dodana dyrektywa .FILEEXISTS('filename') zwracajaca 1 gdy plik w podanej ścieżce istnije, 0 gdy nie istnieje
- rozszerzony komunikat 'Value out of range (VALUE must be between X and Y)'

v2.0.9

- .cbm 'text' konwersja na znaki ekranowe Commodore C64
- usunięty błąd kiedy procedura .PROC znajdująca się w bloku .LOCAL nie została oznaczona jako "do asemblacji" mimo tego że było do niej odwołanie z poziomu makra .MACRO w bloku .LOCAL
- usunięty błąd, etykiety tymczasowe ?label były oznaczane "do relokacji"

v2.0.8

- krótszy kod dla #CYCLE
- poprawki dla .BY, .WO, .HE, .SB, .CB, .FL
- komunikat błędu 'Improper syntax' w przypadku użycia .BY, .WO, .HE, .SB, .CB, .FL w bloku .STRUCT
- dodane nowe dyrektywy dla 65816 .LONGA ON|OFF, .LONGI ON|OFF
- poprawione działanie śledzenia rozmiaru rejestrów 65816 gdy 'OPT T+'
- dodany przełącznik -FV:VALUE pozwalający ustalić wartość wypełnienia pamięci gdy 'OPT F+'
- dodana możliwość podania argumentu jako ciągu dwóch znaków (poprzednio tylko 1 znak) np. lda #'AB' , mwa #'XY' $80

v2.0.7

- poprawione generowanie kodu wynikowego dla nielegali DOP, SHA
- dodane nowe dyrektywy (65816) .A8, .A16, .I8, .I16, .AI8, .IA8, .AI16, .IA16 pozwalające ustawić rozmiar rejestrów AXY
- dodane nowe dyrektywy (65816) .ASIZE, .ISIZE zwracające aktualnie ustawiony rozmiar rejestrów AXY
- rozkaz JMP zmieniany jest na JML (65816) tylko gdy skok dotyczy innego 64KB banku niż obecny
- dodany nowy przełącznik '-ml:value' (margin-left property), który umożliwia zmianę lewego marginesu generowanego listingu w zakresie od 32 do 128 znaków

v2.0.6

- poprawione parsowanie parametrów makra zapisanych przy pomocy etykiet

        .macro test currentRow, previousRow
            .print Tmp%%currentRowAllowed
            .print Tmp%%previousRowAllowed
        .endm

- poprawione alokowanie danych .ARRAY gdy nie ma określonego rozmiaru, lub jest to tablica inna niż jednowymiarowa
- zwiększona liczba przebiegów dla .PROC, w pewnych warunkach dla parametru "xa .reg" parametr był źle interpretowany
- nowa dyrektywa .DEFINE pozwalająca definiować jedno liniowe makra (można definiować wielokrotnie w tym samym przebiegu)

      .DEFINE MACRO_NAME expression

      .DEFINE pisz .print %%1+%%2

      pisz (5,12)

      .define text .sb

      text 'atari'

- nowa dyrektywa .UNDEF MACRO_NAME, usuwa definicję jedno liniowego makra MACRO_NAME

v2.0.5

- tablice .ARRAY w bloku .PROC są pomijane jeśli użyto przełącznik -X (exclude unreferenced procedure)
- użycie .ARRAY w bloku .STRUCT nie będzie generować już zer w pliku wynikowym
- nowa dyrektywa .XGET, pozwalająca wczytać do bufora pamięci MADS-a plik i dodatkowo zmodyfikować jego bajty pod warunkiem że są różne od zera (przydatne dla VBXE)

v2.0.4

- usunięty błąd powodujący błędny zapis bloku aktualizacji dla starszego bajtu adresu w bloku .RELOC
- .DB i .DW usunięte
- .DBYTE (MSB/LSB) odkłada słowo w odwrotnej kolejności (starszy/młodszy)
- dodane dyrektywy .WGET (WORD), .LGET (LONG), .DGET (DWORD)
- poprawione działanie makro rozkazków ADW, SBW, np.:

    	adw (tmp),y #1 posx
    	adw (tmp),y ptr2 ptr4

v2.0.2

- poprawione alokowanie danych dla .SB [+<byte>],<bytes|string|char>

v2.0.1

- poprawione alokowanie danych dla .ARRAY gdy typ większy od .BYTE
- .SIZEOF zwraca rozmiar dla wbudowanych typów .BYTE, .WORD, .LONG, .DWORD
- dodana relokowalna wersja playera MPT examples\players\mpt_player_reloc.asm
- poprawione działanie dyrektywy .DS w blokach SDX (blk sparta $xxx) które nie są relokowalne

v1.9.8

- naprawione działanie rozkazów 65816 PEA, PEI, PER
- dodana możliwość podania kodu dla .RELOC [.BYTE|WORD] [TYPE]

v1.9.7

- dyrektywa .DEF definiuje etykiety o zasiegu lokalnym, jeśli poprzedzić ją znakiem ':' to globalne
- poprawki dla liczb zmiennoprzecinkowych .FL, poprawione kodowane zera, dokonywane zaokrąglenie do 10 miejsc po przecinku
- dla bloków Sparta DOS X 'blk reloc' i 'blk empty' dodana możliwość określenia innego typu pamięci niż $00 (main), $02 (extended), np.:

      blk reloc $40

- poprawka umożliwiająca użycie dyrektywy .PRINT po 'blk empty'
- dodana możliwość definiowania wielowymiarowych tablic .ARRAY, np.:

    .array scr [24][40]
      [11][16] = "atari"
    .enda

      mva #"!" scr[11][22]

- dodana możliwość definiowania tablicy .ARRAY poprzez dyrektywę .DS, np.:

    tmp .ds .array [5][12][4] .word

- dodana możliwość definiowania tablicy .ARRAY poprzez pseudorozkaz EQU (=), np.:

    fnt = $e000 .array [128] [8] .byte

- naprawione działanie makrorozkazu ADW w połączeniu z makrorozkazem SCC itp.
- poprawki dla .REPT, m.in. komentarz wieloliniowy /* */ jest teraz właściwie rozpoznawany

v1.9.6

- poprawione działanie etykiet anonimowych dla mnemoników łączonych znakiem ':', np.:

           ldx #8
    @      lda:cmp:req 20
           dex
           bne @-

- dodany pseudo rozkaz COS(centre,amp,size[,first,last]) generujący wartości dla funkcji cosinus
- dodany komunikat błędu 'Improper syntax' w przypadku użycia dyrektywy .DS w bloku .STRUCT
- naprawione działanie pseudo rozkazu ORG, np.:

    	opt h-
    	ORG [a($ffff),d'atari',c'ble',20,30,40],$8000,$a000

- addytywne bloki .LOCAL otrzymują kolejne adresy, poprzednio adres ustalany był na podstawie pierwszego wystąpienia takiego bloku
- dodany komunikat ostrzeżenia w przypadku stworzenia kolejnego addytywnego bloku .LOCAL o tej samej nazwie "Ambiguous label LOCAL_NAME"
- dodane mnemoniki PER (PEA rell), PEI (PEA (zp)) dla 65816
- dodane nowy typ danych M (najstarszy bajt LONG) i G (najstarszy bajt DWORD) dla pseudorozkazu DTA, np.:

     dta m($44556677)   ; -> $55
     dta g($44556677)   ; -> $44

- dyrektywa .LEN (.SIZEOF) rozszerzona o obsługę danych alokowanych poprzez DTA STRUCT_NAME, np.:

    .STRUCT free_ptr_struct
      prev .WORD
      next .word
    .ENDS

    free_ptr_t dta free_ptr_struct [3]

    	.print .sizeof(free_ptr_t)    ; free_ptr_struct [0..3] = 16 bytes

- zmiany dla operacji odczytu plików poprzez ICL, INS itp. plik do odczytu/zapisu będzie poszukiwany najpierw w ścieżce, która prowadzi do obecnie otwartego pliku, następnie ze ścieżki z której został uruchomiony główny asemblowany plik i na końcu ze ścieżek podanych parametrem -i (additional include directories)
- poprawione rozpoznawanie wielkości znaków gdy aktywowany jest przełącznik -c (char sensitive) dla struktur, np.:

    .struct fcb
    sEcbuf  .byte
    .ends

    data dta fcb [1] (0)

            lda     data[0].sEcbuf

- rozszerzone działanie dyrektywy .REPT o możliwość jej zagnieżdżania np.:

     .rept 2,#*2              ;  1 - $0000
                              ;  2 - $0000
     .print '1 - ',#          ;  1 - $0001
                              ;  2 - $0000
     .rept :1                 ;  2 - $0001
     .print '2 - ',.r         ;  2 - $0002
     .endr                    ;
                              ;
     .endr                    ;

- krótsza wersja pętli #WHILE bez wyrażenia, pętla trwa dopóki LABEL <> 0

    #while .word label
    #end

v1.9.5

- dodany pseudorozkaz SET pozwalający redefiniować etykietę, podobne działanie jak etykiety tymczasowe zaczynające się znakiem '?', np.:

    temp set 12

         lda #temp

    temp set 23

         lda #temp

- dodana możliwość wymuszenia trybu adresowania w stylu XASM ('a:', 'z:'), np.:

     XASM        MADS
     lda a:0     lda.a 0
     ldx z:0     lda.z 0

- dodana możliwość określenia nowego adresu relokacji kodu w stylu XASM ('r:'), np.:

     XASM        MADS
     org r:$40   org $40,*

- poprawione działanie parametru '-x Exclude unreferenced procedures', zmienne .VAR nie są alokowane gdy procedura jest nieużywana
- rozszerzona składnia dla jednoliniowych pętli :rept, możliwe wykorzystanie licznika pętli jako parametru :1 (%%1), np.:

    line0
    line1
    line2
    line3

    ladr :4 dta l(line:1)
    hadr :4 dta h(line:1)

- dodany komunikat ostrzeżenia w przypadku użycia nielegalnych niestabilnych rozkazów CPU6502, np. CIM
- dodana nowa funkcjonalność dla pseudorozkazów RUN, INI, które teraz zachowują adres asemblacji, poprzednio przestawiały adres asemblacji na $2E0 (RUN), $2E2 (INI)
- dodana obsługa etykiet anonimowych (anonymous labels) @, @+[1..9] (forward), @-[1..9] (backward), w celu zapewnienia przejrzystości kodu ograniczone jest używania takich etykiet tylko dla skoków warunkowych oraz do 10 wystąpień w przód/tył, np.:

    @ dex   ---- -------
      bne @+   |  --   |
      stx $80  |   |   |
    @ lda #0   |  --   |
      bne @- ---       |
      bne @-1  ---------

- rozszerzone działanie dyrektyw #IF, #WHILE o zmienne deklarowane przez .VAR, dotychczas wymagane było podanie typu zmiennej, np.:

     .var temp .word

     #if temp>#2100
     #end

     #if .word temp>#2100
     #end

v1.9.4

- dodana normalizacja ścieżek dla plików, tak aby działały pod Unixami, znaki '\' zamieniane są na '/'
- poprawione przekazywanie dyrektyw jako parametrów do procedur i makr, dyrektywy nie były rozpoznawane przy włączonym przełączniku -c (case sensitive)
- poprawione działanie .USE [.USING]
- dodana informacja w postaci ostrzeżenia (WARNING) o etykiecie powodującej nieskończoną ilość przebiegów asemblacji (INFINITE LOOP)
- dodany zapis dwóch bajtów nagłówka FF FF dla pliku zawierającego blok o adresie ładowania $FFFF
- komentarze po mnemonikach nie wymagających argumentu zostaną potraktowane jako błąd, wyjątkiem jest łączenie rozkazów w stylu xasm poprzez znak ':', np.:

     pla $00          ->  ERROR: Extra characters on line
     pha:pla $00      ->  OK

- rozszerzona składnia makr o możliwość używania parametrów w postaci nazw a nie tylko wartości numerycznych-decymalnych, np.:

    .macro SetColor val,reg
     lda :val
     sta :reg
    .endm

    .macro SetColor2 (arg1, arg2)
     lda #:arg1
     sta :arg2
    .endm

- naprawione definiowanie etykiet dla n/w sytuacji, pierwsza etykieta nie zostanie zignorowana

    temp  label = 100

v1.9.3

- poprawione przetwarzanie bloków .PROC, które w pewnych okolicznościach mogły zostać pominięte podczas asemblacji
- poprawiony zapis BLK EMPTY dla plików SDX jeśli zastosowaliśmy deklarację takiego bloku przez .DS
- poprawki dotyczące testowania końca linii
- dodane dyrektywy .FILESIZE, .SIZEOF jako odpowiednik dotychczasowej dyrektywy .LEN
- rozszerzona składnia dla pól struktury .STRUCT, np.:

    .struct name
     .byte label0
     .byte :5 label1
     label2 .byte
     label3 :2 .word
    .ends

v1.9.2

- możliwość określenia adresu dla .ZPVAR = $XX
- usprawnione odwołania do etykiet wyliczeniowych .ENUM, np. enum_label(field0, field1)
- dodana możliwość generowania bloku dla symboli zewnętrznych BLK UPDATE EXTRN dla plików DOS-a, poprzednio tylko dla plików .RELOC, np.:

      .extrn vbase .word
      org $2000
      lda #$80
      sta vbase+$5d

      blk update extrn

- dodany komunikat błędu "Could not use NAME in this context" w przypadku rozkazów odwołań do bloków .MACRO, .ENUM, .STRUCT
- poprawiony błąd który uniemożliwiał użycie 'EQU' w nazwie etykiety
- dodana dyrektywa .CB +byte,....., ostatni bajt ciągu znakowego zapisywany jest w inwersie
- dodana obsługa segmentów poprzez dyrektywy .SEGDEF, .SEGMENT, .ENDSEG
- dodana nowa dyrektywa #CYCLE #N generująca kod 6502 o zadanej liczbie cykli N
- dodana obsługa nielegalnych rozkazów CPU 6502, przykład w pliku ..\examples\test6502_illegal.asm
- uaktualnione pliki konfiguracyjne dla Notepad++ '..\syntax\Notepad++'
- poprawiony zapis pliku LST
- naprawiona alokacja pamięci dla zmiennych strukturalnych, rozszerzona składnia dla .STRUCT

    .struct LABEL
     x,y,z .word     // wiele zmiennych tego samego typu w jednej linii
     .byte a,b
    .ends

    .enum type
      a=1,b=2
    .ende

    .struct label2
      x type
      type y
    .ends

v1.9.0

- naprawiony zapis linii z komentarzem /* */ do pliku listingu *.LST, poprzednio takie linie nie były zapisywane
- poprawka dla etykiet deklarowanych z linii komend -d:label, poprzednio takie etykiety widziane były tylko w pierwszym przebiegu
- w przypadku addytywności bloków .LOCAL tylko pierwszy adres z takich bloków jest zapisywany
- poprawki dotyczące parsowania makr, poprzednio etykiety zaczynające się od END mogły zostać zinterpretowane jako pseudo rozkaz END
- poprawka odczytu dla pustego pliku relokowalnego, poprzednio występował błąd 'Value out of range'
- poprawki dla .USING (.USE)

v1.8.8 - 1.8.9

- uaktualniony silnik duchów programowych ..\EXAMPLES\SPRITES\CHARS o duchy 8x24
- w przypadku braku podania rozszerzenia pliku i braku istnienia takiego pliku dla ICL 'filename' zostanie domyślnie przyjęte rozszerzenie *.ASM ICL 'filename.asm'
- poprawione działanie komentarzy /* */ w blokach .MACRO i .REPT
- usunięty błąd uniemożliwiający poprawną asemblację bloku #IF, #WHILE dla wyrażeń łączonych przez .OR, .AND
- przełączniki w linii komend mogą być poprzedzone tylko znakiem '-', poprzednio także '/' jednak były problemy z działaniem tego znaku na MacOSX
- poprawiony zakres działania dyrektywy .USING, dla aktualnej przestrzeni nazw i kolejnych zawierających się w tej przestrzeni nazw

v1.8.6 - 1.8.7

- usprawnione rozpoznawanie komentarzy /* */ w wyrażeniach
- domyślny adres dla .ZPVAR ustawiony na $0080, poprzednio $0000
- dodana nowa dyrektywa .ELIF jako krótszy odpowiednik dyrektywy .ELSEIF
- rozszerzone działanie dyrektywy .LEN o możliwość podania jako parametru nazwy pliku, zwracana jest wówczas długość takiego pliku
- usprawnione działanie dyrektywy .DEF w wyrażeniach warunku .IF (.IFDEF, .IFNDEF)

v1.8.5

- dodane makro relokujące moduły RMT ...\EXAMPLES\MSX\RMT_PLAYER_RELOCATOR\
- dodany test składni dla nie asemblowanych procedur .PROC gdy aktywny jest przełącznik -x "Exclude unreferenced procedures"
- poprawione działanie przełącznika "-d:label[=value]", podanie wartości dla etykiety jest teraz opcjonalne, domyślnie mads przypisze wartość 1
- dyrektywy .DS i .ALIGN nie spowodują alokacji zmiennych zdefiniowanych przez .VAR
- alokacja zmiennych .VAR przed nowym blokiem ORG nie nastąpi jeśli blok ORG znajduje się w bloku .LOCAL lub .PROC
- poprawione łamanie wierszy znakiem '\' w ciągach ograniczonych nawiasami ()
- usunięty błąd powodujący relokowanie adresu dla wyrażenia dyrektywy .ERROR (ERT)
- usunięte zauważone błędy przy parsowaniu parametrów linii komend
- usunięte zauważone błędy dotyczące optymalizacji długości kodu makro rozkazów MVA, MWA itp.
- poprawiony kod realizujący zagnieżdżanie bloków .PROC
- poprawiony kod realizujący działanie pseudo rozkazów warunku IFT ELI ELS EIF
- dodany komunikat "'#' is allowed only in repeated lines" dla przypadków użycia licznika pętli # (.R) poza pętlą
- usunięty błąd powodujący błędne alokowanie zmiennych zadeklarowanych przez dyrektywę .VAR podczas wykonywania makra
- w celu ujednolicenia składni odwołania do etykiet typów wyliczeniowych możliwe są tylko poprzez znak kropki '.', poprzednio także przez '::'
- możliwe krótsze odwołania do typów wyliczeniowych enum_label(fields), np. :

    .enum typ
     val0 = 1
     val1 = 5
     val2 = 9
    .ende

     lda #typ(val0|val2)  ; == "lda #typ.val0|typ.val2"

- rozszerzona składnia dyrektywy .SAV, np.:

     .sav 'filename',offset,length
     .sav 'filenema',length
     .sav [offset] 'filename',offset2,length
     .sav length
     .sav offset,length

- rozszerzona składnia dyrektywy .ARRAY, w przypadku braku podania maksymalnego indeksu tablicy zostanie on obliczony na podstawie ilości wprowadzonych elementów, elementy można wprowadzać bez konieczności poprzedzenia ich indeksem [expression], np.:

    .array temp .byte
     1,4,6                  ; [0..2]   = 1,4,6
     [12] = 9,3             ; [12..13] = 9,3
     [5]:[8] = 10,16        ; [5..6]   = 10,16 ; [8..9] = 10,16
     0,0,\                  ; [14..17] = 0,0,1,1
     1,1
    .enda                   ; 18 elementów, TEMP [0..17]

- dodana możliwość alokacji zmiennej typu strukturalnego przy pomocy dyrektyw .VAR i .ZPVAR, np.:

    .struct Point
     x .byte
     y .byte
    .ends

     .var a,b,c Point
     .zpvar Point f,g,i

- dodana możliwość alokacji zmiennej typu wyliczeniowego przy pomocy dyrektyw .VAR i .ZPVAR, np.:

    .enum Boolean
     false = 0
     true = 1
    .ende

     .var test Boolean
     .zpvar Boolean test

- dodana możliwość deklaracji pól struktury przy pomocy typów wyliczeniowych, np.:

    .enum EState
      DONE, DIRECTORY_SEARCH, INIT_LOADING, LOADING
    .ende

    .struct SLoader
        m_file_start .word
        m_file_length .word

        m_state EState
    .ends

v1.8.3 - 1.8.4

- nowy silnik duchów programowych z minimalnymi wymaganiami pamięci, bez dodatkowych buforów pamięci obrazu ...EXAMPLES\SPRITES\CHARS_NG
- nowa wersja pakera Huffmana (kompatybilna z Free Pascal Compiler-em, "fpc -MDelphi sqz15.pas") i dekompresora Huffmana SQZ15 ...EXAMPLES\COMPRESSION\SQUASH
- poprawiony kod generowany dla rozkazów MVP, MVN, PEA, BRA (CPU 65816)
- dodane nowe rozkazy BRL, JSL, JML (CPU 65816), jako odpowiedniki rozkazów długich skoków BRA, JSR, JMP
- blok aktualizacji etykiet zewnętrznych (external) został rozszerzony o zapis młodszego i starszego bajtu adresu takiej etykiety
- poprawione działanie dyrektywy .USE (.USING), działa niezależnie od przestrzeni nazw w której zostanie użyta
- usunięty błąd, który powodował w pewnych sytuacjach pomijanie asemblacji bloku #IF, #WHILE
- dodana możliwość definiowania zmiennych poprzez dyrektywę .DS lub pseudo rozkaz ORG przed blokiem .RELOC
- dodana dodatkowa forma składni dla dyrektywy .VAR, z tym że dla takiego przypadku nie ma możliwości określenia adresu umiejscowienia zmiennych w pamięci

     .VAR .TYPE lab1 lab2 lab3 .TYPE lab4 .TYPE lab5 lab6 ...

     .var .byte a,b,c .dword i j

- dodana możliwość definicji pojedyńczych zmiennych typu strukturalnego w krótszy sposób aniżeli dotąd przez DTA

    .struct @point
     x .byte
     y .byte
    .ends

    pointA	@point		; pointA dta @point [0] <=> pointA dta @point
    pointB	@point		; pointB dta @point [0] <=> pointB dta @point

    points	dta @point [100]

- dodana nowa dyrektywa .ZPVAR umożliwiająca automatyczne przydzielenie miejsca zmiennym na stronie zerowej

     .ZPVAR TYPE label1, label2 label3 = $80	; LABEL1=$80, LABEL2=LABEL1+TYPE, LABEL3=LABEL2+TYPE
     .ZPVAR label4, label5 TYPE			; LABEL4=LABEL3+TYPE, LABEL5=LABEL4+TYPE

     .print .zpvar

- poprawione działanie dyrektywy .ERROR i pseudo rozkazu ERT, możliwe jest umieszczenie dodatkowych informacji w wierszu podobnie jak dla .PRINT (.ECHO) np.:

      ERT *>$6000 , 'BUUU przekroczyliśmy zakres pamięci o ' , *-$6000 , ' bajtów'

- dodana możliwość zagnieżdżania bloków procedur .PROC, ten sam kod może być wywoływany z różnymi parametrami np.:

    .proc copySrc (.word src+1) .var

     .proc ToDst (.word src+1, dst+1) .var
     .endp

    	ldy #0
    src	lda $ffff,y
    dst	sta $ffff,y
    	iny
    	bne src

    	rts
    .endp

    	copySrc.ToDst #$a080 #$b000

    	copySrc #$a360

- dodane nowe dyrektywy .ENUM i .ENDE (.EEND)

    .enum	dni_tygodnia

    	poniedzialek = 1
    	wtorek, sroda = 5, czwartek = 7
    	piatek
    	sobota
    	niedziela

    .ende

    	ift dzien==dni_tygodnia::wtorek
    	.print 'wtorek'
    	eif

- rozszerzona funkcjonalność komentarzy wieloliniowych /* */ o możliwość umieszczania ich gdziekolwiek

     lda #12+ /* komentarz */ 23

- umożliwiona relokacja adresów definiowanych dyrektywą .DEF

     .reloc
     .def label=*
     lda label

- dodana możliwość użycia znaków { } do oznaczenia bloku (z wyjątkiem bloków .MACRO), znak '{','}' zostaje rozpoznany na początku nowego wiersza, np.:

    #while .word ad+1<=#$bc40+39
    {
    ad	sta $bc40

    	inw ad+1
    }

    .proc lab
    {
    	.local temp2
    	{
    	}

    	.array tab [255] .long
    	{}
    }

v1.8.2

- zniesione ograniczenie długości pliku dla pseudo rozkazu INS (poprzednio długość wczytywanego pliku ograniczona była do 65536 bajtów)
- dodany komunikat błędu 'The referenced label ... has not previously been defined properly' w przypadku etykiet, które nie zostały zdefiniowane do końca, np. tylko w pierwszym przebiegu wartością nieokreśloną
- dodana nowa dyrektywa .ECHO jako odpowiednik dyrektywy .PRINT, dodatkowo informacje generowane przez .PRINT (.ECHO) zapisywane są teraz także w listingu *.LST
- dodana nowa dyrektywa .ALIGN pozwalająca na wyrównanie do zadanego zakresu pamięci, dodatkowo można określić wartość jaką wypełnić pamięć

      [label] .ALIGN N[,fill]

- dodany nowy przełącznik -U (Warn of unused labels)

1.8.1

- rozszerzone działanie znaku backslash '\', umieszczenie go na końcu wiersza oznacza kontynuację aktualnego wiersza od nowego wiersza, np.:

      macro_temp \
      _____________________________________parametr1_________________________________________________\
      _____________________________________parametr2_________________________________________________\
      _____________________________________parametr3_________________________________________________

      lda\
      #____________________________________label________________________________________\
      +__________________________________expression___________________________________

- zmienione testowanie niekończącego wywoływania się makr po którym wystąpi błąd 'Infinite loop'
- naprawiony zapis etykiet do pliku *.LAB, błąd powstał po dodaniu addytywności obszarów LOCAL
- poprawione działanie pseudo rozkazu SIN (kod zapożyczony z XASM)
- poprawione rozpoznawanie dyrektyw przy włączonym przełączniku -C (Case sensitive)
- usprawniony odczyt bloków .REPT (wskazanie prawidłowej linii z błędem) i .MACRO
- zablokowane użycie .VAR w bloku .REPT
- umożliwione zagnieżdżanie oraz wielokrotne uruchamianie (poprzez makra) pętli .REPT i :repeat (poprzednio występował komunikat 'Use .REPT directive')
- umożliwione przekazywanie parametrów do bloku .REPT, np.

    .REPT 10, #
    label:1           ; LABEL0, LABEL1, LABEL2 ... LABEL9
    .ENDR

    .REPT 5, $12,$33,$44,$55,$66
     dta :1,:2,:3,:4,:5            ; $12,$33,$44,$55,$66
     dta :5,:4,:3,:2,:1            ; $66,$55,$44,$33,$12
    .ENDR

1.7.9 - 1.8.0

- poprawiony błąd w opisie przełącznika -F, poprzednio 'Label at first column', prawidłowy opis to 'CPU command at first column'
- przepisana od nowa obsługa dyrektywy .DS i opcji OPT F+ (dodana możliwość użycia bloków RUN i INI)
- przepisana od nowa obsługa opcji OPT ?+ (etykiety lokalne w standardzie MAE)
- dodana możliwość upublicznienia w blokach PUBLIC tablic zadeklarowanych przez .ARRAY oraz deklaracji struktur .STRUCT
- dyrektywa generująca kod 6502 dla decyzji .TEST zastąpiona została przez dyrektywę #IF, dyrektywa .ENDT przez #END, dodatkowo możliwe jest użycie dyrektywy #ELSE np.:

     # if .byte i>#8 .and .byte i<#200
     # else
           #if .word j = #12
           #end
     # end

- dyrektywa generująca kod 6502 dla iteracji .WHILE zastąpiona została przez dyrektywę #WHILE, dyrektywa .ENDW przez #END, np.:

     lda 20               ->       lda 20
     # while .byte @=20   ->  wait cmp 20
     # end                ->       sne
                          ->       jmp wait

- dyrektywy #IF i #WHILE akceptują dwa dodatkowe operatory '==' i '!='
- dodana dyrektywa .EXITM jako odpowiednik .EXIT
- dodana dyrektywa .FI jako odpowiednik .ENDIF
- dodana dyrektywa .IFDEF jako krótszy odpowiednik dyrektyw .IF .DEF
- dodana dyrektywa .IFNDEF jako krótszy odpowiednik dyrektyw .IF .NOT .DEF
- umożliwione zostało definiowanie makr w obszarze procedury .PROC, podsumowując aktualnie dopuszczalne jest zdefiniowanie makra w obszarze .LOCAL i .PROC
- wystąpienie jakiegokolwiek ostrzeżenia podczas asemblacji nie zmieni kodu wyjścia (exit_code=0), zmiana podyktowana potrzebą kompatybilności z linuxowym makefile
- ujednolicony sposób deklaracji etykiet lokalnych i globalnych, "białe znaki" przed nazwą etykiety nie wymuszą zdefiniowania takiej etykiety jako globalnej, umożliwi to tylko dyrektywa .DEF :LABEL
- poprawione makra @CALL.MAC i @CALL_2.MAC, zmienna tymczasowa globalna ?@stack_offset modyfikowana jest teraz przez dyrektywę .DEF
- rezygnacja z opcji -E (Eat White spaces), aktualnie jest ta opcja zawsze włączona
- poprawione wyświetlanie numeru linii z błędem w aktualnie wykonywanym makrze
- skrócone nazwy etykiet tworzonych podczas wykonywania makr (łatwiejsza ich identyfikacja w pliku *.LAB)
- poprawione działanie opcji OPT H-
- dodane nowe makro rozkazy INL (increse LONG), IND (increse DWORD), DEL (decrese LONG), DED (decrese DWORD)
- dodane nowe makro rozkazy CPB (compare BYTE), CPW (compare WORD), CPL (compare LONG), CPD (compare DWORD)
- usprawnione i rozszerzone działanie dyrektyw #TEST i #WHILE w oparciu o kod generowany przez makro rozkazy CPB, CPW, CPL, CPD, dyrektywy #TEST i #WHILE dla wyrażeń '=#0' i '<>#0' generują najkrótszy kod wynikowy
- dodana optymalizacja długości generowanego kodu dla makro rozkazów MWA, MWX, MWY
- dodana nowa opcja OPT R optymalizująca kod makro rozkazów MWA, MWX, MWY, MVA, MVX, MVY ze względu na zawartość rejestrów, np.:

                        opt r-        opt r+
        mva #0 $80  ->  lda #$00  ->  lda #0
        mva #0 $81  ->  sta $80   ->  sta $80
                        lda #$00  ->  sta $81
                        sta $81   ->

- rozszerzona funkcjonalność dyrektywy .DEF o możliwość przypisania wartości nowo deklarowanej etykiecie, np.:

     .def label = 1

- rozszerzona funkcjonalność dyrektywy .DEF o możliwość zdefiniowania etykiety globalnej niezależnie od aktulnego obszaru lokalnego, np.:

     .def :label

- umożliwiona została addytywność obszarów .LOCAL, tzn. może istnieć wiele obszarów lokalnych o tej samej nazwie, symbole zawarte w takich obszarach należeć będą do wspólnej przestrzeni nazw, np.:

    .local namespace

     .proc proc1
     .endp

    .endl

    .local namespace

     .proc proc2
     .endp

    .endl

1.7.8

- dodane dyrektywy .MEND, .PGEND, .REND jako odpowiedniki .ENDM, .ENDPG, .ENDR
- obecnie deklaracja makra musi kończyć się dyrektywą .ENDM lub .MEND (poprzednio dopuszczalne było użycie dyrektywy .END)
- poprawiony sposób wykonywania makr dzięki czemu umożliwione zostało wykonanie dyrektywy .ENDL z poziomu wykonywanego makra
- poprawione zauważone błędy dotyczące starszych bajtów relokowanego adresu oraz bloku aktualizacji symboli publicznych
- dodana nowa dyrektywa .USING (.USE) pozwalająca określić ścieżkę poszukiwań dla nazw etykiet
- poprawione działanie dyrektyw .LOCAL, .DEF, których błędne działanie objawiało się w szczególnych przypadkach
- poprawione działanie makro rozkazów skoków (SNE, RNE itp.), których błędne działanie objawiało się w szczególnych przypadkach
- rozszerzona składnia dyrektywy .TEST (kod 6502 dla warunku) o dowolną ilość wyrażeń połączonych przez .OR lub .AND (brak możliwości zmiany piorytetu wartościowania przy pomocy nawiasów), np.:

     .test .byte k>#10+1 .or .word j>#100 .and .word j<#105 .or .byte k<=#5
     ...
     ...
     .endt

- rozszerzona składnia dyrektywy .WHILE (kod 6502 dla pętli) o dowolną ilość wyrażeń połączonych przez .OR lub .AND (brak możliwości zmiany piorytetu wartościowania przy pomocy nawiasów), np.:

     .while .byte k>#4 .and .byte k<#39
     ...
     ...
     .endw

1.7.6 - 1.7.7

- dodany nowy przełącznik -B:ADDRESS umożliwiający asemblacje od zadanego adresu
- dodany nowa opcja OPT F+- pozwalająca tworzyć bloki ciągłej pamięci (przydatne dla cartów)
- dodana obsługa parametrów typu .LONG i .DWORD przekazywanych do procedur .PROC typu .VAR (poprzednio akceptowanymi typami parametrów był tylko .BYTE i .WORD)
- dodana nowa dyrektywa .FL realizująca zapis liczb rzeczywistych REAL w formacie FP Atari, np.:

    pi .fl 3.1415926535897932384626433832795  ; 40 03 14 15 92 65
    tb .fl 0.5 12.34 -2.30 0.00002
    tb .fl 0.5, 12.34, -2.30, 0.00002

- umożliwiony został zapis wartości innych typów niż tylko .BYTE w bloku .ARRAY
- dodana obsługa typów wielokrotnych dla .STRUCT, poprzednio takie typy były akceptowane jednak pamięć nie była właściwie dla nich rezerwowana, np.:

      .struct test
       x :200 .byte
       y :999 .long
      .ends

    buf dta test [0]

- poprawione błędy dotyczące generowania kodu relokowalnego zauważone przez Laoo, np.:

      .reloc

       lda temp
    temp .long $aabbcc

- błąd 'Addres relocation overload' wystąpi teraz tylko gdy wyrażenie będzie dotyczyć więcej niż jednej etykiety relokowalnej, poprzednio każde wyrażenie z udziałem etykiety relokowalnej powodowało wyświetlenie tego komunikatu błędu
- blok aktualizacji symboli plublicznych rozszerzony został o możliwość przekazywania stałych różnych typów B-YTE, W-ORD, L-ONG, D-WORD, poprzednio przekazywanym typem był tylko W-ORD
- zmienione działanie dyrektywy .VAR w blokach .LOCAL znajdujących się w bloku .PROC, zmienne takie zawsze odkładane są na końcu bloku przed dyrektywą .ENDP, w pozostałych przypadkach na końcu bloku .LOCAL przed dyrektywą .ENDL
- umożliwiona została relokowalność kodu generowanego przez dyrektywy .WHILE i .TEST
- poprawione działanie testowania wartości typu .WORD w kodzie generowanym przez dyrektywy .WHILE i .TEST
- dodana nowa dyrektywa .ADR zwracająca adres etykiety przed zmianą adresu asemblacji
- dodana nowa dyrektywa .LEN zwracająca długość bloków zdefiniowanych przez .PROC i .ARRAY
- poprawione działanie operacji dzielenia, mnożenia i modulo, poprzednio błędnie był interpretowany piorytet dla tych operacji
- komentarze z końca linii nie poprzedzone znakiem komentarza będą powodować wystąpienie błędu 'Unexpected end of line'
- dodana możliwość przypisania zmiennej pól zdefiniowanych przez strukture, np.:

    @point .struct
           x .byte
           y .byte
           .ends

    a @point
    b @point
    c @point

- rozszerzona składnia .STRUCT o możliwość dodania nowych pól bez definiowania nazwy pola, np.:

     .struct @id
      id .word
     .ends

     .struct @mem
      @id
      adr .word
     .ends

- rozszerzona składnia makro rozkazu MWA o możliwość użycia adresowania pośredniego strony zerowej postindeksowanego Y, np.:

      mwa ($80),y $a000,x
      mwa $bc40,y ($f0),y
      mwa ($80),y ($82),y

- rozszerzona składnia dyrektywy .EXTRN, obecnie możliwe jest zapowiedzenie większej ilości etykiet różnych typów w jednym wierszu, zapowiedzenie procedury .PROC w takim wierszu musi znajdować się na jego końcu, np.:

      .extrn a,b,c,d .byte  x y z .word  line .proc(.byte x,y) .reg

- rozszerzona składnia dyrektywy .VAR, obecnie możliwe jest zadeklarowanie większej ilości etykiet różnych typów w jednym wierszu oraz przypisanie im adresu od którego zostaną odłożone w pamięci, np.:

      .var x y z .byte bit :2 .dword = $80

- rozszerzona składnia dla parametrów procedur przekazywanych przez zmienne .VAR, możliwe jest podanie przesunięcia np.:

    move .proc (.word src+1,dst+1) .var

    src lda $ffff
    dst sta $ffff

         .endp

- dodana nowa dyrektywa .NOWARN wyłączająca wyświetlenie ostrzeżenia dla aktualnie asemblowanego wiersza, np.:

     .nowarn PROCNAME

- dodane nowe makro rozkazy PHR, PLR, realizujące odkładanie i zdejmowanie wartości rejestrów z udziałem stosu sprzętowego, np.:

      PHR -> PHA         PLR -> PLA
             TXA                TAY
             PHA                PLA
             TYA                TAX
             PHA                PLA

- dodane nowe makro rozkazy ADB, SBB realizujące dodawanie i odejmowanie wartości typu .BYTE, np.:

     ADB $80 #12 $b000  ->  lda $80
                            clc
                            adc #12
                            sta $b000

     SBB #200 $a000     ->  lda #200
                            sec
                            sbc $a000
                            sta $a000

- dodana możliwość użycia składni C dla liczb szestnastkowych, np.:

     lda 0x2000
     ldx #0x12

    temp = 0x8000

1.7.5

- dyrektywa .DS w blokach relokowalnych SDX RELOC i MADS RELOC deklaruje od teraz pusty blok
- dodany nowy przełącznik -F, który umożliwia umieszczanie rozkazów CPU i pseudo rozkazów od pierwszej kolumny w wierszu
- przepisane od nowa procedury odczytu bloków .MACRO, .REPT oraz procedura realizująca dzielenie wiersza przy pomocy znaku '\'
- dodane nowe pseudo rozkazy ADW, SBW realizujące dodawanie i odejmowanie wartości typu WORD dla CPU6502, np.:

      adw hlp #40        ; hlp=hlp+40
      adw hlp #20 pom    ; pom=hlp+20

- rozszerzone działanie dyrektywy .DEF o możliwość zdefiniowania etykiety, np.: .DEF label
- zwiększona liczba przebiegów dla deklaracji etykiet przez EQU dla pewnych szczególnych przypadków

1.7.4

- naprawione działanie dyrektywy .PRINT, dotąd mogła nie wyświetlić wartości etykiet zaczynającej się na literę 'A','B','C','D','E','F','G','H','L','T','V'
- zablokowane działanie dyrektywy .DS w blokach .RELOC i SDX oraz naprawione jej działanie z instrukcją warunkową .IF (IFT)
- usprawnione przeszukiwanie ścieżek dostępu -i:path (można odwoływać się do podkatalogów tam zawartych)
- w przypadku wystąpienia błędów podczas asemblacji wyświetlane są one wszystkie a nie tylko pierwszy z błędów
- poprawione zauważone błędy, m.in. użycie makra w pliku .RELOC mogło spowodować w pewnych sytuacjach zapis błędnej informacji o relokownych adresach
- uproszczony został sposób kończenia procedur wykorzystujących stos programowy MADS-a, nie ma potrzeby używania dyrektywy .EXIT, a dyrektywa .ENDP nie powoduje już dodatkowych działań na stosie programowym
- dodana nowa dyrektywa .SYMBOL jako odpowiednik bloku aktualizacji BLK UPDATE NEW SYMBOL 'SYMBOL', dyrektywę .SYMBOL można użyć w dowolnym miejscu programu
- dodane automatyczne wywoływanie bloków aktualizacji (ADDRESS, EXTERNAL, PUBLIC, SYMBOL) dla .RELOC i SDX
- dodane nowe dyrektywy .BY, .WO, .HE, .EN, .SB (zapożyczone z MAE)
- dodany nowy przełącznik OPT ?- (domyślnie) etykiety ze znakiem zapytania (?labels) traktowane są jako etykiety tymczasowe, OPT ?+ etykiety ze znakiem zapytania (?labels) traktowane są jako lokalne i tymczasowe, nazwą obszaru lokalnego jest ostatnio użyta etykieta bez znaku zapytania
- dodane dyrektywy .LEND, .PEND, .AEND, .WEND, .TEND, .SEND jako odpowiedniki dyrektyw .ENDL, .ENDP, .ENDW, ENDW, .ENDT, .ENDS
- dodane nowe dyrektywy .GLOBAL i .GLOBL jako odpowiednik (zamiennik) dyrektywy .PUBLIC
- dodana optymalizacja skoków warunkowych JEQ, JNE, JPL, JMI, JCC, JCS, JVC, JVS, jeśli jest taka możliwość wybierany jest skok krótki typu BEQ, BNE, BPL, BMI, BCC, BCS, BVC, BVS
- dodany nowy domyślny separator znak spacji dla przekazywanych parametrów do .PROC, .MACRO, dotąd był to tylko znak przecinka
- usprawnienia dotyczące przekazywania parametrów do makr i procedur, np. paramatrem makra może być dyrektywa zwracająca wartość wyrażenia lub symbol licznika pętli '#'

      :12 makro #

- dodana możliwość użycia znaku spacji jako separatora dla .VAR, .EXTRN, np.

      .EXTRN a b c d .word
      .VAR i = 1  j = 2 .byte
      .VAR a b c d .byte

- rozszerzona składnia dla .VAR umożliwiająca zaincjowanie zmiennych stałą, np.:

     .var i = 10  j = 12 .byte
     .var a , b = 2 .byte

- dodane nowe dyrektywy .WHILE, .ENDW pozwalające na automatyczne wygenerowanie kodu dla pętli WHILE, np.:

             ldx #$ff
     .while .word adr < #$bc40+40*24
             stx $bc40
        adr: equ *-2
             inw adr
     .endw

- dodane nowe dyrektywy .TEST, .ENDT pozwalające na automatyczne wygenerowanie kodu dla warunku, np.:

     .test .byte (@>=#'a')
      .test .byte (@<=#'z')

      .endt
     .endt

1.7.3

- dodana możliwość zmiany adresu asemblacji .PROC lub .LOCAL bez zmiany adresu ładowania
- usunięto optymalizację kodu dla makro rozkazów MWA itp., która mogła powodować w szczególnych przypadkach zapętlenie się MADS-a
- dodane dyrektywy .REG, .VAR pozwalające określić sposób przekazywania parametrów do procedur (.REG przez rejestry CPU, .VAR przez zmienne)
- dodana dyrektywa .VAR pozwalająca na deklarację zmiennych w blokach .PROC, .LOCAL, zadeklarowane zmiennne są fizycznie odkładane na końcu takiego bloku
- rozszerzona składnia dla dyrektywy .EXTRN, np. EXTRN label1,label2,label3... TYPE
- jesli brak deklaracji etykiet dla stosu programowego MADS-a, przyjmowane są domyślne wartości @PROC_VARS_ADR=$0500, @STACK_ADDRESS=$0600, @STACK_POINTER=$FE
- dodany repeat_counter #, który można używać zamiennie z dyrektywą .R
- wystapi błąd '^ not relocatable' przy próbie relokacji rozkazu 'lda ^label'
- dodana obsługa symboli publicznych dla stałych (C-ONSTANT) w blokach PUBLIC
- poprawiona relokowalnosc dla tablic .ARRAY, danych stworzonych przez .STRUCT, parametrów przekazywanych do procedur przez stała #

v1.7.2

- przepisana na nowo obsługa pseudo rozkazów REQ, RNE, RPL, RMI, RCC, RCS, RVC, RVS, SEQ, SNE, SPL, SMI, SCC, SCS, SVC, SVS
- poprawione działanie dyrektywy .LINK dla bloków o stałych adresach
- poprawione testowanie słów zarezerwowanych (można używać nazw zarezerwowanych dla 65816 gdy używamy tylko 6502)
- zmiany w listingu, wyświetla informacje o numerze banku tylko gdy bank > 0
- dodana obsługa makro rozkazów MWA, MWX, MWY, MVA, MVX, MVY, ADD, SUB, INW, DEW (do ich obsługi nie są już potrzebne makra)

v1.7.1

- dodana możliwość używania nazw mnemoników 65816 w trybie pracy 6502, w trybie 65816 wystąpi już błąd Reserved word
- poprawione działanie pseudo rozkazów skoków SCC, RNE itp. w makrach
- usprawnione wykonywanie wielu makr rozdzielonych znakiem dwukropka ':'

v1.7.0

- usunięty błąd, który powodował zbyt mała liczbę przebiegów asemblacji
- dodana obsługa pseudo rozkazów JEQ, JNE, JPL, JMI, JCC, JCS, JVC, JVS (makra nie są już potrzebne do ich obsługi)

v1.6.9

- rozszerzona składnia dla .ARRAY, .PUT
- dodany pseudo rozkaz EXT pozwalający na deklaracje etykiety external
- dodane makra JEQ, JNE, JPL, JMI, JCC, JCS
- dodane dyrektywy .PAGES i .ENDPG
- dodana dyrektywa .END zastepujaca inne dyrektywy .END?
- przełącznik -H zastąpiony został przez -HC (generuje plik nagłówkowy dla CC65)
- dodany nowy przełącznik -HM generujący plik nagłówkowy dla MADS-a z sortowaniem na etykiety typu CONSTANTS, VARIABLES, PROCEDURES
- dodana nowa dyrektywa .RELOC generująca kod relokowalny w formacie MADS-a

v1.6.8

- dodana nowa dyrektywa .PUT oraz rozszerzona składnia dla dyrektywy .GET (../EXAMPLES/MSX/MPT_PLAYER/MPT_RELOCATOR.MAC , ../EXAMPLES/MSX/TMC_PLAYER/TMC_RELOCATOR.MAC)
- dodana obsługa pseudo rozkazów XASM-a REQ, RNE, RPL, RMI, RCC, RCS, RVC, RVS, SEQ, SNE, SPL, SMI, SCC, SCS, SVC, SVS
- dodana możliwość łączenia dowolnej liczby znanych MADS-owi mnemoników przy pomocy znaku ':' (styl XASM-a), np.:

      lda:cmp:req 20
      ldx:ldy:lda:iny label

v1.6.6 - 1.6.7

- źródło MADS-a kompatybilne z Free Pascal Compiler, po kompilacji możliwe jest jego używanie na innych platformach systemowych, jak np. Linux, Mac OS, OS/2 itp.
- od teraz MADS sam dobiera odpowiednią liczbę przebiegów asemblacji, przełącznik '/3' nie jest już potrzebny
- poprawiony i rozbudowany został mechanizm przekazywania parametrów do MADS-a (rozdział 'Przełączniki assemblera')
- poprawione zostało wywołanie makra w linii rozdzielanej znakiem '\' oraz usprawnione rozpoznawanie i wykonywanie linii rozdzielanych znakami '\'
- poprawiony błąd, w którym MADS mylił dyrektywę .ENDM z pseudorozkazem IFT
- poprawione działanie instrukcji warunkowych .ELSEIF, .ELSE
- poprawione testowanie poprawności instrukcji warunkowych w makrach
- obsługa procedur .PROC została rozbudowana o nowe makra i mechanizmy, dzięki którym podobna jest w działaniu jak i łatwości użycia do procedur z języków wyższego poziomu
- dla procedur .PROC z zadeklarowanymi parametrami potrzebna jest teraz dodatkowa deklaracja @PROC_VARS_ADR
- brak ograniczeń w liczbie parametrów przekazywanych do procedur, jedynym ograniczeniem jest dostępna pamięć
- dodany nowy przełącznik /d:label=value pozwalający zdefiniować nową etykietę MADS-a z poziomu linii poleceń
- dodany nowy przełącznik /x "Exclude unreferenced procedures" pozwalający pominąć podczas asemblacji nie używane w programie procedury zadeklarowane dyrektywą .PROC
- nowa opcja OPT T+ (track sep, rep) śledząca zmiany rozmiaru rejestrów A,X,Y dokonywane przez rozkazy SEP, REP (CPU 65816)
- nowe biblioteki w katalogu ..\EXAMPLES\LIBRARIES
- w deklaracji obszaru lokalnego .LOCAL nie jest wymagane podanie nazwy obszaru
- nowe operatory '-=', '+=', '++', '--' pozwalające zmniejszyć/zwiększyć wartość etykiety tymczasowej, np.:

      ?label --      ->   ?label=?label-1
      ?lab ++        ->   ?lab=?lab+1
      ?temp += 3     ->   ?temp=?temp+3
      ?ofset -= 5    ->   ?ofset=?ofset-5

- rozszerzona o znak przecinka składnia deklaracji parametrów procedur, np.:

     .proc nazwa (.byte a,b,c .word d,e)
     .endp