---------------------------------------------------------------------------- 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 Gültigkeitsbereich von Labels 5. Preprozessor ---------------------------------------------------------------------------- 1. Was ist das überhaupt und Geschichte ---------------------------------------- Mit dem Cross-Assembler können auf einem Rechner Programme für einen anderen Rechner(typ) erstellt werden. Die Programmdateien müssen 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 ursprünglich 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 Zusätzen und in verschiedenen Gehäusen. Gemeinsam ist allen der Befehlssatz, der für 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 entfällt, 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 für ein EPROM assembliert (naja, der 8MHz Atari war nicht schnell. Aber dafür 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' verändert, 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 unterstützt. Falls die Quell- und Include-Dateien nicht gefunden werden, werden die in XAINPUT aufgeführten Pfade der Reihe nach durchgetestet. Falls XAOUTPUT existiert, wird dieser Pfad als Pfad für .err, .lab und .obj-Dateien benutzt. Die Komponenten des Pfades sind mit ',' getrennt. Die Labeldatei enthält hinterher eine Liste aller Labels mit Block-Nummer und Wert in dezimal in der Form: 'Label, 1,-1234' in lesbarem ASCII. Die Fehlerdatei enthält die Version des Assemblers, Datum und Uhrzeit des Assemblerlaufs, die Liste der Fehler, die Ausdrücke, 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 angehängt. Die Quelldatei muß im ASCII-Format vorliegen. 3. 6502 Assembler ------------------ Da dies kein 6502-Assemblerkurs werden soll, nur eine ganz kurze Beschreibung. Unterstützt wird der Code für alle Standard-6502 sowie der Code für die Rockwell 65C02-CPU. Der Prozessor hat drei Register, über die die meisten Operationen laufen. Transferoperationen benötigen deshalb immer einen Load- und einen Store-Befehl. Zusätzlich gibt es das Statusregister und den Stackpointer sowie, natürlich, den Programmzähler. Der Stack liegt immer im Bereich $100 und $1ff (Hexadezimal mit vorangestelltem '$'), weshalb der Stackpointer ein 8-Bit-Register ist. Eine besondere Behandlung durch kürzere Befehle erfährt 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 Erhöhe X-Register um eins INY Y INC Erhöhe 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 ver„ndern) 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 löschen SEC setzen CLD Dezimal-Flag löschen SED setzen CLI Interrupt freigeben SEI sperren CLV Overflow-Flag löschen PHA Akku auf Stack legen PHX XR (*) PHY YR (*) PHP Status PLA Akku vom Stack holen PLX XR (*) PLY YR (*) PLP Status BRK Löst 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. Außerdem haben einige der anderen Befehle zusätzliche Addressierungsarten. Die mit (D) markierten Befehle arbeiten im Dezimal-Mode (Dezimal-Flag gesetzt) anders, nämlich 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 möglich die Zeropage-Adressierung angewendet. Ein vorangestelltes '!' erzwingt absolute Adressierung, auch bei einem Wert kleiner 256. Als Wert oder Adresse können arithmetische Ausdrücke mit Hierarchie und Klammerung verwendet werden. Der Assembler versteht folgende Operanden: 123 -Dezimal $234 -Hexadezimal &123 -Oktal %010110 -Binär * -Programmzähler "A" -ASCII-Code labelx -Label -(lab1+1) -Ausdruck Folgende Operatoren können benutzt werden: + -Addition 9 - -Subtraktion 9 * -Multiplikation 10 / -Integer-Division 10 << -Shift nach links 8 >> -Shift nach rechts 8 >=,=> -größer oder gleich 7 <=,=< -kleiner oder gleich 7 < -kleiner 7 > -größer 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 höheren Priorität werden zuerst bearbeitet. Ein gültiger 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 unärer Operator stehen: < bildet Lo-Byte des Wertes > bildet Hi-Byte des Wertes LDA #