Banki pamięci, definiowanie i odwołania
Różnice i podobieństwa pomiędzy XASM i MADS
Syntax: MADS source [options] /l[:filename] Generate listing /o:filename Set object file name /t[:filename] List label table /h[:filename] Header file for CC65 /m:filename File with macro definitionDomyślne nazwy plików to:
source.lst
source.obx
source.lab
source.h
source.mac
Mad-Assembler v0.8 by TeBe/Madteam Source: D:\!Delphi\Masm\test.asm 1 * --- 2 ; to jest program 3 4 = 00,9033 obraz equ $9033 5 = 00,00A0 scr1 equ $a0 6 7 opt h- 8 org $2000 9 10 00,2000 EA main nop
W sumie są to trzy kolumny:
Pierwsza kolumna to numer banku przypisany do etykiety. Druga kolumna to wartość etykiety. Trzecia kolumna to nazwa etykiety. Specjalne znaczenie w nazwach etykiet mają znaki: etykieta zadeklarowana w makrze (dwa dwukropki) :: etykieta zadeklarowana podczas wykonywania makra (dwukropek) : etykieta zadeklarowana podczas wykonywania procedury (średnik) ; Wartość liczbowa, która występuje po znakach specjalnych, oznacza numer wywołania makra lub numer napotkanej deklaracji procedury (.PROC)Mad-Assembler v1.2.5beta by TeBe/Madteam Label table: 00 0400 @STACK_ADDRESS 00 00FF @STACK_POINTER 00 2000 MAIN 00 2019 LOOP 00 0080 HLP;1 00 204B THEX;1
#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
3 = bad parameters, assembling not started 2 = error occured 1 = warning(s) only (XASM only) 0 = no errors, no warnings
org $00 lda tmp+1 tmp lda #$00Dwu-przebiegowy assembler nie znając wartości etykiety 'TMP' przyjmie domyślnie, że jej wartość będzie dwu-bajtowa, czyli typu WORD i wygeneruje w sumie rozkaz 'lda W'.
Natomiast MADS uprzejmie wygeneruje rozkaz strony zerowej 'lda Z'. I to właściwie główna właściwość czterech biegó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 #$00Są 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. Innym sposobem na wymuszenie rozkazu strony zerowej jest użycie nawiasów klamrowych { } np.
dta {lda $00},$80 ; lda $80W MADS możemy robić tak samo, ale po co, czwarty bieg 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 #$00Czyli asembluj od adresu $20, ale załaduj pod adres $3080. Podsumowując:
org adres1,adres2Asembluj od adresu adres1, umieść w pamięci od adresu adres2. Taki ORG zawsze spowoduje stworzenie nowego bloku w pliku.
EQU value = value OPT [chlos][+-] ORG adres[,adres2] INS 'filename'[,ofset][,length] ICL 'filename' DTA [ablht](value1,value2...) DTA [cd]'string' RUN adres INI adres END :repeat NMB RMB LMB value .IF [IFT] expression .ELSE [ELS] .ELSEIF [ELI] expression .ENDIF [EIF] .PRINT 'string'["string"] lub .PRINT expression .ERROR [ERT] 'string'["string"] lub .ERROR [ERT] expression .MACRO .ENDM :parameter .EXIT .PROC .ENDP .WORD .BYTE .LONGCzyli w większości po staremu, chociaż parę zmian zaszło. W przypadku cudzysłowów można używać ' ' lub " ".
Examples: :4 asl @ :2 dta a(*)Znak ':' określa liczbę powtórzeń linii (w przypadku makr określa numer parametru).
c+ włącz obsługę CPU 65816 (16bit) c- włącz obsługę CPU 6502 (8bit) h+ zapisuj nagłówek pliku dla DOS h- nie zapisuj nagłówka pliku dla DOS l+ zapisuj listing do pliku (LST) l- nie zapisuj listingu (LST) o+ zapisuj wynik asemblacji do pliku wynikowego (OBX) o- nie zapisuj wyniku asemblacji do pliku wynikowego (OBX) s+ drukuj listing na ekranie s- nie drukuj listingu na ekranieWszystkie przełączniki 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) :)
adr asembluj od adresu ADR adr1,adr2 asembluj od adresu ADR1, ustaw nagłówek pliku na ADR2
b wartość typu BYTE a wartość typu WORD l młodszy bajt wartości (BYTE) h starszy bajt wartości (BYTE) t wartość 24bit (TRIPLE, TRIBYTE) c ciąg znaków ATASCII ograniczony apostrofem '' lub "", znak * na końcu spowoduje invers wartości ciągu, np. dta c'abecadlo'* d ciąg znaków INTERNAL ograniczony apostrofem '' lub "", znak * na końcu spowoduje invers wartości ciągu, np. dta d'abecadlo'*
value wartość z zakresu 0..$FFFE =label odczytuje numer banku używany przez zmienną o etykiecie LABELUstawia numer banku na nową wartość (BANK = value).
name .PROC [{.Typ1 Par1 .Typ2 Par2 ...}] .EXIT .ENDPMADS wymaga dla procedur zadeklarowania dwóch etykiet, o konkretnych nazwach (adres stosu, wskaźnik stosu):
@STACK_ADDRESS @STACK_POINTERBrak deklaracji dla w/w etykiet i próba użycia struktury .PROC spowoduje wystąpienie błędu 'Undeclared label .STACK_ADDRESS' lub 'Undeclared label .STACK_POINTER'.
name .PROC {.WORD name_par1 .BYTE name_par2}
.ExitProc .macro lda @STACK_POINTER sec sbc #:1 ; parametr przekazuje MADS sta @STACK_POINTER rts .endm
name .MACRO ['separator'] ["separator"] .EXIT .ENDM :parameter
'separator' Pojedyńczy apostrof określa separator, który będzie używany do oddzielenia parametrów przy wywołaniu makra.
"separator" Podwójny apostrof określa separator, który będzie używany do oddzielenia parametrów przy wywołaniu makra. Parametry zostaną automatycznie rozbite na dwa elementy: tryb adresacji i argument, np.:
przyklad #12 200 <30 przyklad .macro " " .endmMakro przyklad ma zadeklarowany separator-spację oraz podwójny apostrof ",czyli po wywołaniu makra parametry zostaną rozłożone na:
przyklad '#' 12 ' ' 200 '#' 0Tylko dla znaków '<' i '>' zostanie wyliczona wartość parametru. Przykład wykorzystania tak zadeklarowanych makr w pliku z makro rozkazami XASM'a XASM_MACRO.ASM
:$2 nop :+2 nop :%10 nopParametr :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:
.IF :0<2||:0>5 .ERROR "Wrong number of arguments" .ENDIFPrzykład makra:
load_word .macro lda <:1 sta :2 lda >:1 sta :2+1 .endm
proc_name @,#$166,$A400MADS po napotkaniu wywołania procedury, wymusza wykonanie makra @CALL z parametrami wyliczonymi na podstawie deklaracji procedury (rozbija każdy parametr na trzy składowe: tryb adresacji, typ parametru, wartość parametru w zapisie decymalnym).
@CALL proc_name,'@','B',0,'#','W',358,' ',W,41984Makro @CALL odłoży na stos zawartość akumulatora, następnie wartość $166, następnie wartość spod adresu $A400. Parametr przekazywany przez akumulator (@) powinien być zawsze na początku, 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 Wszelkie deklaracje etykiet w obrębie procedury są typu lokalnego. Aby odwołać się do etykiety spoza procedury należy poprzedzić ją znakiem dwukropka ':'. Jeśli poszukiwana przez assembler etykieta nie wystąpiła w obrębie procedury, wówczas nastąpi jej poszukiwanie w głównym programie. Wyjście z procedury .PROC nastąpi po napotkaniu rozkazu .EXIT, przez co MADS wymusi wykonanie makra .EXITPROC, które użytkownik sam może zaprojektować, albo skorzystać z dołączonego do MADS'a. W makrze .EXITPROC musi zostać zawarty program który zmodyfikuje 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. Liczbę bajtów przekazaną do procedury przekazuje do makra .EXITPROC MADS w postaci parametru.
name .PROC {.WORD name_par1 .BYTE name_par2}Zadeklarowanie parametrów procedury spowoduje automatyczne przypisanie im wartości. Etykiety parametrów w naszym w/w przykładzie przyjmą automatycznie następujące wartości:
name_par1 = @STACK_ADDRESS-liczba_bajtów_zajętych_przez_parametry (2) name_par2 = @STACK_ADDRESS-liczba_bajtów_zajętych_przez_parametry+2 (1)Aby móc odwołać się do parametru z poziomu procedury, musimy użyć wskaźnika stosu @STACK_POINTER, np.:
ldx @stack_pointer lda name_par1,x clc adc <$4000 sta WYNIK lda name_par1+1,x adc >$4000 sta WYNIK+1Czyli dokonaliśmy operacji WYNIK=NAME_PAR1+$4000 Odczytanie wartości parametrów możliwe jest tylko przy adresowaniu indeksowym. Użytkownik nie powinien ingerować w wartość @STACK_POINTER tylko zostawić to zadanie dedykowanym makrom. Można stworzyć makro, które będzie odczytywało wartość parametru i przekazywało do odpowiedniego rejestru, np. akumulatora.
@GetPar .macro ldx @stack_pointer lda :1,x .endmNasze przykładowe dodawanie będzie wyglądało teraz tak:
@GetPar name_par1 clc adc <$4000 sta WYNIK @GetPar name_par1+1 adc >$4000 sta WYNIK+1
macro_name [Par1,Par2,Par3 ...]Jeśli wpiszemy rozkaz składający się z siedmiu znaków, a czwartym znakiem będzie znak dwukropka':', np. 'lda:sta' wówczas znak ':' zostanie zastąpiony znakiem zapytania '?'. Tak zmodyfikowany rozkaz zostanie potraktowany jako próba wywołania makra. Jeśli nie zadeklarowaliśmy makra o nazwie 'lda?sta' wystąpi błąd. W ten sposób można zastąpić składnie XASM'a makrami MADS'a. Wszelkie deklaracje etykiet w obrębie makra są typu lokalnego. Aby odwołać się do etykiety spoza makra należy poprzedzić ją znakiem dwukropka ':'. Jeśli poszukiwana przez assembler etykieta nie wystąpiła w obrębie makra, wówczas nastąpi jej szukanie 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 zadeklarowanego 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. Przykład makra, które spowoduje przepełnienie stosu:
skok .macro skok .endmPrzykład programu, który przekazuje parametry do procedur:
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 bank pamieci .if :2<=$FFFF ; jesli 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 banku na 1 ; wszystkie deklaracje 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 banku na 2 ; wszystkie deklaracje 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 rtsOczywiś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 deklarowane 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 struktury .PROC jaką umożliwia MADS. Więcej o deklaracji procedury i operacjach jej dotyczących w rozdziale "Procedury".
NMB RMB LMB value
value wartość z zakresu 0..$FFFE =label odczytuje numer banku używany przez zmienną o etykiecie LABELUstawia numer banku na nową wartość (BANK = value).
org $2000 lda #$e3 sta $d301 rts ini $2000 nmb ; bank = bank + 1 (next memory bank) org $4000 icl 'program_w_dodatkowym_banku_pamieci.asm'albo tak:
org $2000 lda #$e3 sta $d301 rts ini $2000 lmb $e3 ; bank = $E3 (load memory bank) org $4000 icl 'program_w_dodatkowym_banku_pamieci.asm'Czyli musimy zatroszczyć się o to aby do PORTB wpisać konkretny kod banku rozszerzonej pamięci, zanim blok danych zostanie wczytany w obszar $4000..$7FFF lub inny. MADS zapisuje plik wynikowy w formacie Atari DOS, który nie przewiduje specjalnych nagłówków dla bloków ładujących się do pamięci rozszerzonej.
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)
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 BITMożliwe jest użycie rozszerzenia mnemonika po znaku kropki '.':
.b lub .z BYTE .a lub .w lub .q WORD np. lda.w $80 ; zapisze AD 80 00 lda $80 ; zapisze A5 80
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 DEAMożliwe jest użycie rozszerzenia mnemonika po znaku kropki '.':
.b lub .z BYTE .a lub .w lub .q WORD .t lub .l TRIPLE,TRIBYTE,LONG (24bit) np. lda.w #$8047 ; zapisze A9 47 80 lda #$80 ; zapisze A9 80Wyjątki stanowią rozkazy n/w, którym nie można zmienić rozmiaru rejestru w adresowaniu absolutnym:
SEP REP COP
PEAInnym 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 'Illegal adressing mode'. Aby "oszukać" assembler wystarczy dać przed kwadratowym nawiasem otwierającym '[' znak '+'.
lda [2+4] ; lda [6] lda +[2+4] ; lda 6
EQU =etykiety występują zawsze na początku wiersza etykiety muszą zaczynać się znakiem ['A'..'Z','_','?','@'] pozostałe dopuszczane znaki etykiety to ['A'..'Z','0'..'9','_','?','@'] Przykład deklaracji etykiety:
?nazwa EQU $A000 nazwa = 20 @?nazwa EQU 'a'+32Czyli doszła możliwość użycia znaku zapytania '?' i "małpki" '@' w nazwach etykiet. Znak kropki '.' na początku nazwy sugeruje że jest to pseudo rozkaz, natomiast znak zapytania '?' oznacza etykietę lokalną. We wcześniejszej wersji MADS była możliwość użycia w nazwie etykiety znaku kropki '.', zrezygnowałem jednak z tego ze względu na mniejszą przejrzystość w oznaczaniu rozszerzenia mnemonika i adresowaniu struktur. Zapis z użyciem przecinka ',' odwołania do struktury, czy rozszerzenia mnemonika jest niezbyt udany:
lda nazwa_stuktury,pole,x lda,w #$00Natomiast z użyciem kropki '.' zapis jest już przejrzysty i jednoznaczny, pozatym zgodny z zapisem znanym z C++, Delphi na PC:
lda nazwa_stuktury.pole,x lda.w #$00Maksymalna liczba etykiet i makr ograniczona jest ilością pamięci komputera. Konkretnie można dokonać 4294967296 (LONGWORD) wpisów do tablic dynamicznych. Jestem pewien że taka ilość jest wystarczająca :) Operacje arytmetyczne dokonywane są na wartościach typu INTEGER (signed 32 bit), jest to zakres wartości -2147483648..2147483647 Jeden wiersz może mieć długość 65536 bajtów, takiej długości może być też nazwa etykiety. Nie miałem jednak okazji sprawdzić tak długich etykiet i wierszy :)
?namePrzykład użycia etykiet lokalnych:
?loc = $567 ?loc2 = $4444 lda ?loc sta ?loc2 ?loc = $123 lda ?locDeklaracje i etykiety lokalne występują także w makrach i procedurach, jednak nie trzeba ich oznaczać dodatkowo. Każda deklaracja w obrębie makra czy procedury domyślnie jest lokalna. Aby jednak mieć dostęp do deklaracji globalnych spoza makra lub procedury należy użyć operatora ':', np.:
lp ldx #0 ; deklaracja globalna etykiety 'LP' test test test .macro lda :lp ; znak ':' przed etykietą odczyta wartość etykiety globalnej sta lp+1 ; odwołanie do etykiety lokalnej 'LP' w makrze lp lda #0 ; deklaracja etykiety lokalnej 'LP' .endmW w/w przykładzie występują deklaracje o tych samych nazwach, lecz każda z nich ma inną wartość i jest innego typu. Możemy się o tym przekonać przeglądając plik *.LAB
Label table: 00 2000 LP - wartość etykiety globalnej LP 00 2008 LP:1 - wartość etykiety lokalnej LP po pierwszym wywołaniu makra 00 2010 LP:2 - wartość etykiety lokalnej LP po drugim wywołaniu makra 00 2012 LP::1 - wartość etykiety lokalnej LP w pierwszym makrze przed jego wywołaniem
; to jest komentarz ; to jest komentarz lda #0 ; to jest komentarz lda #0 * to tez jest komentarz lda #0 i to tez jest komentarz, chociaż nie ma znaku ';' lub '*'Najbezpieczniej jest używać średnika ';' ponieważ znak '*' ma też inne znaczenia, może oznaczać operacje mnożenia, czy też aktualny adres podczas asemblacji. Średnik natomiast dedykowany jest tylko i wyłącznie do oznaczenia komentarza.
=Z tą różnicą że etykieta nie występuje na początku wiersza, musi poprzedzić ją minimum jedna spacja. Przykład definicji:
?nazwa = $A000 nazwa = 20 @?nazwa = 'a'+32Przykładem zastosowania definicji etykiety lokalnej jest makro @CALL, w którym występuje definicja etykiety ?@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 ?@stack_offset = 0 ... ... @CALL_@ .macro sta @stack_address+?@stack_offset,x ?@stack_offset = ?@stack_offset+1 .endm
org $2000 opt c+ lda #0 inc @ 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
lda $2000,x+ to odpowiednik lda $2000,x inxjeś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 to odpowiednik lda $2002,x
v1.2.9beta - poprawione błędy zauwazone przez Rastera (przyklad ..\RMT_PLAYER\MUSIC.A65 asembluje teraz poprawnie) - obsługa składni XASM'a typu 'lda:sta' za pomoca makr (przykłady w XASM_MACRO.ASM) - dodana obsługa pseudo rozkazu .ELSEIF oraz jego odpowiednika ELI - dodana obsługa pseudo rozkazu ERT (ERT expression) - dodany przełącznik '/m:filename' który pozwoli wczytać plik z definicjami makr v1.2.8beta - w wersji 1.2.7beta byla blednie asemblowana linia w stylu dta b(value1),b(value2),... - naprawione problemy z dzialaniem przelacznikow /l: /o: /t: - dodany przelacznik /h ktory tworzy plik *.h dla cc65 (wersja testowa) - rozbudowana deklaracja makr o separator i tryb dzialania (przyklad XASM_MACRO.ASM) - zmiana w deklaracji parametrow procedury, zamiast znakow '( )' sa teraz '{ }' - dodane kody wyjscia, takie same jak w XASM - pseudo rozkaz .IF ma teraz odpowiednik w pseudo rozkazie IFT - pseudo rozkaz .ELSE ma teraz odpowiednik w pseudo rozkazie ELS - pseudo rozkaz .ENDIF ma teraz odpowiednik w pseudo rozkazie EIF - dodana obsluga skladni w stylu LDA ADRES,Y[+-] (LDA (BYTE),Y[+-]) oraz LDA ADRES,Y[+-]expression - dodane przyklady w wersji dla MADS ProTracker'a i Inertii