----------------------------------------------------------------------------

                              XA 2.1.0
                              
                      65(c)02 Cross-Assembler 
                 
                         von Andre Fachat
                         
----------------------------------------------------------------------------

     * Block-Struktur (Versteckte Label)

     * Sehr schnell durch hashing 
     
     * C-hnlicher Preprozessor
     
---------------------------------------------------------------------------- 

 1.  Was ist das berhaupt und Geschichte
 
 2.  Aufruf und Features
 
 3.  6502 Assembler

 4.  Pseudo-Opcodes, Block-Struktur und Gltigkeitsbereich von Labels
  
 5.  Preprozessor

----------------------------------------------------------------------------


1.  Was ist das berhaupt und Geschichte
----------------------------------------

Mit dem Cross-Assembler knnen auf einem Rechner Programme fr einen 
anderen Rechner(typ) erstellt werden. Die Programmdateien mssen dann
nur noch auf das Zielsystem bertragen werden. In diesem Fall handelt 
es sich um einen 6502-Cross-Assembler. Der 6502 ist ein 8-Bit-Prozessor,
der ursprnglich von MOS Technologies entwickelt wurde. Er tut seine
Dienste u.a. im Apple II, Commodore PET, VC20 und C64 (in abgewandelter
Form) und vielen anderen. 
Inzwischen gibt es ihn in vielen Varianten mit verschiedenen Zustzen
und in verschiedenen Gehusen. Gemeinsam ist allen der Befehlssatz, 
der fr den Assembler die Grundlage bildet. Die CMOS-Versionen bieten
allerdings Erweiterungen des Befehlssatzes. 
Die Idee zu einem Cross-Assembler entstand, als ich mir einen 6502-Computer
selbst baute und der (ebenfalls selbstgeschriebene) Assembler auf dem C64
zu langsam wurde. Nachdem auch noch ein Atari ST bei mir rumstand, war
die Idee schnell in die Tat umgesetzt.


2.  Aufruf und Features
-----------------------

Der Assembler besteht nur aus dem Programm "xa". 
Der Assembler verarbeitet eine oder mehrere Quelldateien zu einer
Objektdatei, die direkt verwendet werden kann. Das Linken entfllt, da der
Aufwand zu gro und die Geschwindigkeit hoch genug ist, um die 
'Libraries' im Quelltext einzubinden. Ca. 350kByte Quelltext werden in
1 Minute und 50 Sekunden zu einer 32kByte Objektdatei fr ein EPROM 
assembliert (naja, der 8MHz Atari war nicht schnell. Aber dafr ist der 
Wert ziemlich gut. Mein 486DX4/100 braucht vielleicht 2 Sekunden)!
Als Ausgabedateien werden eine Objektdatei, eine Fehlerdatei und eine
Labeldatei geschrieben. 
   
Der Aufruf lautet:
XA Quell1 [Quell2 ...] [-oObject] [-eFehler] [-lLabel] [-C] [-v] [-x]

Die Angabe der Objekt-, Fehler- und Labeldatei ist optional, ohne Angabe
wird die Endung der ersten Quelldatei auf 'obj', 'err' und 'lab' verndert,
wenn "-x" angegeben ist. Ansonsten wird "a.o65" als Ausgabedatei verwendet
und keine Fehler- und Labeldatei geschrieben.
Die Option -C erzeugt Fehlermeldungen bei CMOS-Befehlen.
Im Environment werden die Variablen XAOUTPUT und XAINPUT untersttzt.
Falls die Quell- und Include-Dateien nicht gefunden werden, werden die in
XAINPUT aufgefhrten Pfade der Reihe nach durchgetestet. Falls XAOUTPUT
existiert, wird dieser Pfad als Pfad fr .err, .lab und .obj-Dateien
benutzt. Die Komponenten des Pfades sind mit ',' getrennt.

Die Labeldatei enthlt hinterher eine Liste aller Labels mit Block-Nummer
und Wert in dezimal in der Form: 'Label, 1,-1234' in lesbarem ASCII.
Die Fehlerdatei enthlt die Version des Assemblers, Datum und Uhrzeit des
Assemblerlaufs, die Liste der Fehler, die Ausdrcke, die mit #echo
und #print im Preprozessor erzeugt werden und eine Statistik ber die 
benutzten Resourcen (Speicherplatz etc.).
Die Objektdatei wird nur durch die Quelldatei bestimmt, es wird kein Code
vorgesetzt oder angehngt.
Die Quelldatei mu im ASCII-Format vorliegen. 


3.  6502 Assembler
------------------

Da dies kein 6502-Assemblerkurs werden soll, nur eine ganz kurze
Beschreibung. Untersttzt wird der Code fr alle Standard-6502 sowie
der Code fr die Rockwell 65C02-CPU. Der Prozessor hat drei Register, 
ber die die meisten Operationen laufen. Transferoperationen bentigen
deshalb immer einen Load- und einen Store-Befehl.
Zustzlich gibt es das Statusregister und den Stackpointer sowie,
natrlich, den Programmzhler. Der Stack liegt immer im Bereich $100 und
$1ff (Hexadezimal mit vorangestelltem '$'), weshalb der Stackpointer ein
8-Bit-Register ist. Eine besondere Behandlung durch krzere Befehle 
erfhrt die Zeropage ($0-$ff), bei deren Adresse das Hi-Byte Null ist.
Das Statusregister besitzt folgende Flags:

N    = Negativ
O    = Overflow
B    = Break
D    = Dezimal
I    = Interrupt
Z    = Zeroflag
C    = Carry

Befehle:

LDA       lade Akkumulator
LDX       lade X-Register
LDY       lade Y-Register

STA       speichere Akkumulator
STX       speichere X-Register
STY       speichere Y-Register
STZ       speichere NULL                               (*)

TAX       Kopiere Akku nach X
TAY       Kopiere Akku nach Y
TXA       Kopiere X nach Akku
TYA       Kopiere Y nach Akku
TSX       Kopiere Stackpointer nach X        
TXS       Kopiere X nach Stackpointer

ADC       Addiere zu Akku mit bertrag (Carry)         (D)
SBC       Subtrahiere von Akku mit Carry               (D)
AND       Logisches Und mit Akku   
ORA       Logisches Oder mit Akku
EOR       Exklusiv-Oder mit Akku
BIT       Bit-Test: Z=A&M, N=M7, O=M6
ROL       Rotiere Links Akku oder Speicher A=A*2+C, C=A7
ROR       Rotiere Rechts A=A/2+C*127, C=A0
ASL       Arithmetisches Linksschieben A=A*2
LSR       Logisches Rechtsschieben A=A/2
INX       Erhhe X-Register um eins
INY              Y
INC       Erhhe Akku oder Speicher um eins
DEX       Erniedrige X-Register um eins
DEY                  Y
DEC       Erniedrige Akku oder Speicher um eins

CMP       Vergleiche mit Akku (Substraktion ohne Akku zu verndern)
CPX       Vergleiche mit X-Register
CPY       Vergleiche mit Y-Register

BNE       Verzweige falls nicht Null
BEQ                       Null
BMI                       Negativ
BPL                       Positiv
BVC                       Overflow Clear
BVS                       Overflow Set
BCS                       Carry Set
BCC                       Carry Clear
BRA       Verzweige immer                              (*)

JMP       Springe an Adresse
JSR       Springe in Unterroutine, Rcksprungadresse auf dem Stack
RTS       Return from Subroutine

CLC       Carry-Flag lschen
SEC                  setzen
CLD       Dezimal-Flag lschen
SED                    setzen
CLI       Interrupt freigeben
SEI                 sperren
CLV       Overflow-Flag lschen

PHA       Akku auf Stack legen
PHX       XR                                           (*)
PHY       YR                                           (*)
PHP       Status
PLA       Akku vom Stack holen
PLX       XR                                           (*)
PLY       YR                                           (*)
PLP       Status

BRK       Lst Interrupt mit gesetztem Break-Flag aus
RTI       Return from Interrupt

NOP       No Operation

TRB       Test und Reset Speicher mit Akku             (*)
BBR       Branch on Bit Reset                          (*)
BBS       Branch on Bit Set                            (*)
RMB       Reset Memory Bit                             (*)
SMB       Set Memory Bit                               (*)

Die mit (*) markierten Befehle sind CMOS-Befehle. Auerdem haben einige
der anderen Befehle zustzliche Addressierungsarten. Die mit (D) markierten
Befehle arbeiten im Dezimal-Mode (Dezimal-Flag gesetzt) anders, nmlich
im BCD-Mode (eine Ziffer von 0-9 in 4 Bit).

Addressierungsarten:

-Immediate               LDA #$12
-Absolute                STA $1234
-Zeropage                EOR $10
-Bit,ZP,REL              BBR #7,$10,label
-Akku                    ASL
-Implied                 TAX
-(Indirect,x)            LDA ($10,X)
-(Indirect),y            STA ($3e),Y
-Zeropage,x              CMP $12,X
-Absolut,x               LDY $4356,x
-(Absolut,x)             jmp (jumptabelle,x)
-Absolut,y               ORA $2345,y
-Relative                BNE irgendwohin
-(Indirect)              jmp (berVektor)
-Zeropage,y              ldx $12,y
-Bit,Zeropage            RMB #1,zeropage

Bei Adressierungsarten, die in der Zeropage und Absolut existieren, wird, 
soweit mglich die Zeropage-Adressierung angewendet. Ein vorangestelltes
'!' erzwingt absolute Adressierung, auch bei einem Wert kleiner 256.
Als Wert oder Adresse knnen arithmetische Ausdrcke mit Hierarchie und
Klammerung verwendet werden. Der Assembler versteht folgende Operanden:

     123       -Dezimal
     $234      -Hexadezimal
     &123      -Oktal
     %010110   -Binr
     *         -Programmzhler
     "A"       -ASCII-Code
     labelx    -Label
     -(lab1+1) -Ausdruck
     
Folgende Operatoren knnen benutzt werden:

     +         -Addition                     9
     -         -Subtraktion                  9
     *         -Multiplikation               10
     /         -Integer-Division             10
     <<        -Shift nach links             8
     >>        -Shift nach rechts            8
     >=,=>     -grer oder gleich           7
     <=,=<     -kleiner oder gleich          7
     <         -kleiner                      7
     >         -grer                       7
     =         -gleich                       6
     <>,><     -ungleich                     6
     &&        -Logisches UND                2
     ||        -Logisches ODER               1
     &         -Bitweises UND                5
     |         -Bitweises ODER               3
     ^         -Bitweises Exklusiv-Oder      4
     
Die Operatoren mit der hheren Prioritt werden zuerst bearbeitet.
Ein gltiger Ausdruck ist dann z.B. 

     LDA       base+number*2,x
     
Bei Addressierungsarten, die nicht mit einer Klammer beginnen, darf
auch im ersten Ausdruck keine Klammer am Anfang stehen:

     LDX       (1+2)*2,y                ; Falsch  !
     LDX       2*(1+2),y                ; Richtig !
     
Vor einem Ausdruck kann ein unrer Operator stehen:
     
     <         bildet Lo-Byte des Wertes
     >         bildet Hi-Byte des Wertes
     
     LDA  #<adresse
     
Die Einzelnen Befehle werden durch ':' oder eine neue Zeile getrennt.
Hinter jedem Befehl kann, durch ';' abgetrennt ein Kommentar stehen.
Der Kommentar gilt bis zum nchsten Doppelpunkt oder bis zur nchsten 
Zeile.

 
4. Pseudo-Opcodes, Block-Struktur und Gltigkeitsbereich von Labels
-------------------------------------------------------------------

Folgende Pseudo-Opcodes stehen noch zur Verfgung:

     .byt      wert1,wert2,wert3, ...
     .word     wert1,wert2, ...
     .asc      "text1","text2", ...
     .dsb      lnge [,fllbyte]
     *=
     .(
     .)
     
Hierbei sind '.byt' und '.asc' identisch und legen Daten Byteweise im
Speicher ab. '.word' legt Daten Wortweise (=2 Byte) im Speicher ab.
'.dsb' fllt einen Speicherbereich der Lnge 'lnge' mit dem Wert
'fllbyte' ab. Falls fllbyte nicht abgegeben ist, wird mit Null gefllt.
Die folgenden Opcodes haben keine direkte Einwirkung auf die Objektdatei.
'*=' definiert den Programmzhler. 
'.(' erffnet einen neuen 'Block'. Alle Labels innerhalb eines solchen
Blocks sind lokal. Allerdings darf vorher kein Label gleichen Namens in
einem hheren Block definiert worden sein. '.)' schliet den Block wieder.
Die Maximale Blockschachtelungstiefe betrgt 16 Blocks.

Ein Label wird definiert dadurch, da es kein Opcode ist:

     label1    LDA #0              ; Position(=Programmzhler) des Opcodes
     label2    =1234               ; direkte definition
     label3 label4 label5          ; implizit Programmzhler, auch mehrere
                                   ; Labels werden definiert
     label6 label7 = 3		   ; label6 wird mit dem Wert des Programm-
				   ; zhlers gesetzt, label7 mit 3
     label8:   sta label2	   ; Da Opcodes mit ':' getrennt werden,
				   ; wird auch die bliche Schreibweise mit
				   ; 'label:' erkannt.

Dabei werden Gro- und Kleinbuchstaben unterschieden. 
Labels, die mit vorangestelltem '+' definiert werden, sind global (Block=0),
d.h. berall gltig. Mit vorangestellten '&' kann ein Label jeweils eine
Hierarchiestufe hher definiert werden als ohne '&'.
Mit vorangestelltem '-' kann ein Label umdefiniert werden:

     -sysmem   +=4  ; da gibts ==, +=, -=, *=, /=, &=, |=
     -syszp    =123
     

5. Preprozessor
---------------

Der Preprozessor ist stark an den Preprozessor der Sprache C angelehnt.
So sind die fr C typischen /* */ -Kommentare mglich.
Ein Preprozessor-Befehl wird mit einem '#' am Beginn der Zeile eingeleitet.

#include  "Dateiname"    fgt die Datei 'Dateiname' an dieser Stelle in den
                         Quelltext ein. Beim Laden wird zuerst der Name 
                         direkt gesucht, danach mit den Pfaden aus 
                         XAINPUT.
                         
#echo  Kommentar         Gibt Kommentar in der Fehlerdatei aus.

#print ausdruck          Gibt Ausdruck direkt, nach Preprzessorbehandlung
                         und nach dem Ausrechnen aus.
                         
#printdef DEFINIERT      Gibt die Definition in der Fehlerdatei aus.

#define   DEF  Text      Definiert DEF als Text, deshalb wird hinterher 
                         immer DEF durch Text ersetzt
                         
#ifdef    DEF            Der Quelltext bis zum folgenden #endif oder #else
                         wird nur assembliert, falls DEF vorher mit #define
                         definiert wurde.
                         
#else                    else halt...

#endif                   Beendet #if..-Konstrukt. Nach jedem #if.. mu!
                         ein #endif stehen. 

#ifndef  DEF             .... falls DEF nicht definiert wurde. 

#if ausdruck             .... falls ausdruck ungleich null ist.

#iflused label           .... falls Label schon benutzt wurde.

#ifldef label            .... falls Label schon definiert wurde.

Dabei beziehen sich #iflused und #ifldef auf Labels, nicht auf Preprozessor-
Definitionen! Damit lt sich z.B. eine Bibliotheksstruktur aufbauen:

#iflused  label
#ifldef   label
#echo     label schon definiert, nicht aus Library
#else
label     lda #0
          ....
#endif
#endif

Die #if-Schachtelungstiefe betrgt 15.

Mit #define knnen auch wie in C 'Funktionen' mit Parametern definiert 
werden.

#define mult(a,b)   ((a)*(b))


Literaturangaben
----------------

-"Das Maschinensprachebuch zum Commodore 64"
     Lothar Englisch
     Data Becker GmbH
-"Controller Products Data Book"
     Rockwell International, Semiconductor Products Division
-"Programmieren in C"
     Kernighan, Ritchie     
     Hanser Verlag

