C 64
Tabellen

ROM-Routinen in eigenen Programmen

Das Rad ist schon erfunden! Ähnlich verhält es sich mit verschiedenen Routinen, die ein Assembler-Programmierer immer wieder benötigt. Aber warum soll man sich die Arbeit des Programmierens machen, wenn das Betriebssystem viele ständig benötigte Routinen schon enthält und man nur noch zu wissen braucht, ab welcher Adresse sie stehen?

Angenommen, Sie möchten in Assembler einige komplexe Dinge programmieren wie beispielsweise eine neue mathematische Funktion (wie wäre es mit dem Kotangens) und diese auf dem Bildschirm ausgeben. Das ist eine große Aufgabe, zu der zunächst einmal die Übernahme des Arguments in das Maschinenprogramm, dann einige Fließkomma-Rechenoperationen und schließlich die Ausgabe auf dem Bildschirm geschrieben werden müßten, wenn da nicht schon fast alles an verborgener Stelle als fertige Programm-Module im Computer vorhanden wäre!

Sowohl im unteren (von $A000 bis $BFFF) als auch im oberen ROM-Bereich (von $E000 bis $FFFF) liegt die Firmware fest verschachtelt vor. Der untere ROM-Abschnitt wird manchmal auch Basic-Interpreter, der obere ROM-Bereich Betriebssystem genannt, wobei diese Einteilung aber den Kern der Sache nicht genau trifft, denn Interpreter, Editor und Betriebssystem führen ein gemischtes Dasein quer durch alle genannten ROM-Bereiche hindurch.

Mindestens fünf Informationen braucht ein Assembler-Programmierer, wenn er das breite Programmangebot des ROMs nutzen möchte:

  1. Einsprungadresse
  2. Format der Eingabeparameter
  3. Adressen der Eingabeparameter
  4. Adressen der Ausgabeparameter
  5. Format der Ausgabeparameter

Nicht alle Routinen, die man benutzen kann, erfordern alle fünf Informationen, manche weniger, einige auch mehr und schließlich gibt es noch Programmroutinen, die noch den Aufruf einer oder sogar mehrerer anderer Routinen nötig machen.

In der beigefügten Tabelle sind - nach Anwendungen sortiert - die wichtigsten Firmware-Möglichkeiten mit den erforderlichen Ein- und Ausgabeparametern aufgeführt. Das sind natürlich beileibenichtalle. Die Auswahl erfolgte subjektiv! Es sind einfach diejenigen, die mir bislang am häufigsten untergekommen sind. Außerdem wurde auf die Kernel-Routinen verzichtet: Man findet diese sehr gut dokumentiert bereits in einer Reihe von Büchern und im Assembler-Kurs.

Die Tabelle nennt den Label-Namen, die Einsprungadresse und gibt eine Kurzbeschreibung der Funktion. Das Ein- und auch das Ausgabeformat ist ebenso angegeben wie auch die Adressen, an denen diese Parameter übergeben werden. Die verwendeten Bezeichnungen halten sich eng an die im Assembler-Kurs kennengelernten. Sie sind allgemein üblich:

FAC Fließkomma-Akku 1
ARG Fließkomma-Akku 2
A Akkumulator
X,Y X-, Y-Register
A/Y 2-Byte-Angabe im Format LSB/MSB im Akku/Y-Register
FLPT Fließkommazahl im Normalformat
MFLPT gepacktes Fließkommaformat

Damit das alles nicht so trocken abläuft, soll noch ein kleines Beispiel vorgestellt werden! Die oben schon erwähnte Kotangens-Funktion wird in einem Maschinenprogramm erzeugt, das durch USR anzuspringen ist. In Bild 1 finden Sie ein Flußdiagramm zu dem Programm, welches hier als Hypra-Ass-Listing abgebildet ist (Listing 1). Ein kurzes Testprogramm liefert Listing 2.

Bild 1. Flußdiagramm einer Kotangens-Funktion

Der Einsprung mittels USR bietet den Vorteil, daß der Übergabewert gleich im FLPT-Fbrmat im FAC »landet«. Es ist aber sinnvoll, den Übergabeparameter mittels der MOVMF-Routine zu »retten«, weil durch die Kosinus-Funktion der FAC verändert wird. Wenn auch das Ergebnis der Kosinus-Funktion mittels MOVMF beiseite gelegt wurde, holen wir durch MOVFM den Anfangswert wieder in den FAC und bilden mittels SIN den Sinus davon. Schließlich teilen wir den im Speicher stehenden Kosinuswert durch den im FAC befindlichen Sinuswert (unter Verwendung von FDIV). Das Ergebnis ist der Kotangens:

COTX = (COSX/SIN X)

Dieser Wert befindet sich nun im FAC und wird mit dem RTS an das Basic-Programm zurückgeliefert. Im Testprogramm weisen wir ihm dann die Variable E zu.

Dieses kurze Beispiel soll Ihnen den Mund wässrig machen. Sehr viel detaillierter werden die ROM-Routinen im Kurs »Von Basic zu Assembler« im 64’er behandelt werden.

(Heino Ponnath/hm)

Literatur:
1. Kassera/Kassera, Programmieren in Maschinensprache, München 1985: Markt & Technik Verlag, MT 830
2. West, C64 Computerhandbuch, München 1984, Te-wi
3. Babel/Krause/Dripke, Das Interface Age Systemhandbuch zum C 64, München 1983: Interface Age Verlag
4. Ponnath, C 64 Wunderland der Grafik, München 1985: Markt & Technik Verlag MT 756.

1. Routinen, die die Kooperation von Basic und Assembler erleichtern:

Label Adresse Funktion Eingabe Ausgabe
Format Adresse Format Adresse
CHRGET 0073 Holt nächstes Byte 1 Byte Basic-Text 1 Byte A
CHRGOT 0073 Holt aktuelles Byte 1 Byte Basic-Text 1 Byte A
READY A474 Erzeugt READY-Status - - - -
LINGET A96B Holt Integerwert
(0-63999)
ASCII-Zahl Basic-Text 2-Byte Integer 14/15
FRMNUM AD8A Holt beliebigen nume-
rischen Ausdruck
Basic-
Ausdruck
Basic-Text FLPT FAC
FRMEVL AD9E Holt beliebigen
Ausdruck
Basic-
Ausdruck
Basic-Text a) bei Fließkomma:
FLPT FAC
b) bei Integer:
FLPT FAC
c) bei String:
Zeiger auf FAC+3,
Descriptor FAC+4
Diese Routine setzt außerdem eine Reihe von Flaggen:
VALTYP($0D) 0=Zahl FF=String
INTFLAG ($0E) 0=Fließkomma 80=integer
War Ausdruck einfache Variable, dann zeigt VARNAM ($45/6)
das 1. Byte des Variablen-Namens
CHKCLS AEF7 Prüft auf » ) « ASCII Basic-Text - -
CHKOPN AEFA Prüft auf » ( « ASCII Basic-Text - -
CHKCOM AEFD Prüft auf »,« ASCII Basic-Text - -
SYNCHR AEFF Prüft auf Zeichen
im Akkumulator
ASCII Basic-Text
A
- -
Diese 4 Routinen überlesen das Zeichen, wenn vorhanden.
Wenn nicht vorhanden, folgt SYNTAX ERROR
ISVAR AF28 Sucht Variablenwert Name +
Kennung
$45/46 a) Zahl:
FLPT FAC
b) String:
Descriptor-FAC+3
ORDVAR B0E7 Sucht Variablennamen Name+
Kennung
$45/46 Adresse $47/48
GTBYTC B79B Holt Zahl (0-255) ASCII Basic-Text 1 Byte X
GETNUM B7EB Liest 2 Integerzahlen
(Trennung durch Komma)
1. Zahl: 0 bis 65535
2. Zahl: 0 bis 255
ASCII Basic-Text 2Byte-Int.
1Byte-Int.
$14/15
X
COMBYT E200 Prüft auf »,« und holt
folgende Zahl
ASCII Basic-Text 1 Byte X

2. Routinen, die die Verschiebungen im Speicher durchführen:

BLTUC A3BF Verschiebt Blöcke Adressen:
Quelle
Start $5F/60
Ende+1 $5A/5B
Ziel
Ende+1 $58/59 - -
PUTINT A9C4 Schiebt FAC als Integer FLPT FAC 2Byte- angegebene
in Variable Adresse $49/50 Integer Variable
PTFLPT A9D6 Schiebt FAC FLPT FAC MFLPT angegebene
in Variable Adresse $49/50 Variable
GETSPT AA2C Schiebt String- Zeiger FAC+3 Descriptor angegebene
descriptor in Variable Adresse $49/50 Variable
STRVAL B7B5 Zahlenstring in ASCII ab $22 FLPT FAC
FAC einlesen Länge A
CONUPK BA8C Lädt ARG aus Speicher MFLPT A/Y FLPT ARG
MOVFM BBA2 Lädt FAC aus Speicher MFLPT A/Y FLPT ARG
MOVMF BBD4 Schiebt FAC FLPT MFLPT ange-
in Speicher Adresse FAC X/Y gebener
Speicher
MOVFA BBFC ARG in FAC kopieren FLPT ARG FLPT FAC
MOVAF BCOC FAC in ARG kopieren FLPT FAC FLPT ARG
ACTOFC BC3C Akku in FAC schieben 1Byte A FLPT FAC

3. Routinen zur Arithmetik:

ASCADD AA27 Addiert ASCII-Ziffer
zu FAC
ASCII
Ziffer
A FLPT FAC
OROP AFE6 FAC=(FAC)OR(ARG) FLPT FAC,ARG FLPT FAC
ANDOP AFE9 FAC=(FAC)AND(ARG) FLPT
0
FAC,ARG
Y
FLPT FAC
FACINX B1AA FAC wird als Integer
in A/Y abgelegt
FLPT FAC 2Byte-
Integer
A/Y
UMULT B357 16-Bit-Multiplikation 2-Byte-Integer
Zahl1
Zahl2

$28/29
$71/72
2Byte-
Integer
X/Y
CIVAYF B391 Integer (-32768 bis
32767) in FAC
2Byte-
Integer
A/Y FLPT FAC
SGNFT B3A2 Integer (0 bis 255)
in FAC
1Byte y FLPT FAC
GETADR B7F7 Wandelt FAC zu
Integer (0-65535)
FLPT FAC 2Byte-
Integer
Y/A
+$14/15
FADDH B849 FAC = FAC + 0,5 FLPT FAC FLPT FAC
FSUB B850 FAC=Speicherzahl-FAC MFLPT Zeiger A/Y FLPT FAC
FSUBT B853 FAC = ARG - FAC FLPT FAC FLPT FAC
FADD B867 FAC=Speicherzahl +FAC MFLPT
MFLPT
Zeiger A/Y
FAC
FLPT FAC
FADDT B86A FAC = ARG + FAC FLPT ARG,FAC FLPT FAC
COMPLT B947 Erzeugt Zweierkomplement von FAC FLPT FAC FLPT FAC
LOG B9EA FAC = In(FAC) FLPT FAC FLPT FAC
FMULT BA28 FAC=Speicherwert*FAC MFLPT Zeiger A/Y FLPT FAC
FLPT FAC
FMULTT BA30 FAC = ARG * FAC FLPT ARG,FAC FLPT FAC
MUL10 BAE2 FAC = 10 * FAC FLPT FAC FLPT FAC
DIV10 BAFE FAC = FAC/10 FLPT FAC FLPT FAC
FDIVF BB07 FAC=ARG/Speicherzahl MFLPT Zeiger A/Y FLPT FAC
FLPT ARG
FDIV BB0F FAC=Speicherzahl/FAC MFLPT Zeiger A/Y FLPT FAC
FLPT FAC
FDIVT BB14 FAC = ARG/FAC FLPT FAC,ARG FLPT FAC
SIGN BC28 Ermittelt Vorzeichen
von FAC
FLPT FAC 1Byte A
1 ← +
0 → 0
FF ← -
ABS BC58 FAC = ABS(FAC) FLPT FAC FLPT FAC
FCOMP BC5B Vergleicht FAC mit
Speicherzahl
MFLPT Zeiger A/Y 1Byte: A
1: FAC > Speicher
0: FAC = Speicher
FF: FAC < Speicher
FLPT FAC
INT BCCC FAC = INT(FAC) FLPT FAC FLPT FAC
AADD BD7E Addiert A zu FAC FLPT FAC FLPT FAC
1Byte A
SQR BF71 FAC = SQR(FAC) FLPT FAC FLPT FAC
MPOT BF78 FAC=Speicherwert
↑ FAC
FLPT FAC FLPT FAC
MFLPT Zeiger A/Y
FPWRT BF7B FAC = ARG ↑ FAC FLPT ARG,FAC FLPT FAC
NEGOP BFB4 FAC = -FAC FLPT FAC FLPT FAC
EXP BFED FAC = e↑FAC FLPT FAC FLPT FAC
POLYX E059 Polynomberechnung
FAC=a0+a1x+a2x²+...
Adresse Zeiger A/Y FLPT FAC
Zeiger weist auf Start der Konstantentabelle.
1. Byte = Polynomgrad
Weitere Bytes sind die Koeffizienten des Polynoms
in der Reihenfolge an,.....,a0 im MFLPT-Format.
COS E264 FAC = COS(FAC) FLPT FAC FLPT FAC
SIN E26B FAC = SIN(FAC) FLPT FAC FLPT FAC
TAN E2B4 FAC = TAN(FAC) FLPT FAC FLPT FAC
ATN E30E FAC = ATN(FAC) FLPT FAC FLPT FAC

4. Auswahl von Ein-/Ausgabe-Routinen:

ERROR A437 Fehlermeldung ausgeben und READY Fehlernummer X ASCII Bildschirm
LIST A69C Listet Basic-Programm - - - -
NUMDON AABC Druckt FAC auf Bildschirm aus FLPT FAC ASCII Bildschirm
STROUT AB1E Gibt String auf Bildschirm aus. Ende=0 Adresse Zeiger A/Y ASCII Bildschirm
SYNERR AF08 Ausgabe SYNTAX ERROR - - ASCII Bildschirm
OVERR B97E Ausgabe OVERFLOW ERR. - - ASCII Bildschirm
LINPRT BDCD Druckt Integerzahl (0 bis 65535) aus. 2Byte-Integer X/A ASCII Bildschirm
FACOUT BDD7 Druckt FAC auf Bildschirm aus FLPT FAC ASCII Bildschirm
FOUT BDDD FAC wird zu ASCII-String (Ende=0). Kann direkt mit STROUT ausgegeben werden. FLPT FAC ASCII
(Ende=0)
Startadr.
ab $100

A/Y
SAVET E156 Save Parameter aus Basic-Text
VERFYT E165 Verify Parameter aus Basic-Text
LOADT E168 Load Parameter aus Basic-Text
SLPARA E1D4 Holt Parameter für Save, Verify, Load aus dem Basic-Text
PLOTK E50A Setzt Cursorposition Zeile
Spalte
X
Y
HOME E566 Cursor in Home-Position
PLOTR E56C Setzt Cursor-Position Zeile
Spalte
$D6
$D3
GETKBC E5B4 Holt Zeichen aus Tastaturpuffer - - 1Byte A
PRT E716 Gibt Zeichen in A auf Bildschirm aus 1Byte A ASCII Bildschirm
CLRLN E9FF Löscht xte Bildschirmzeile Zeilennummer X - -
Tabelle der ROM-Routinen
10 rem***test fuer cotangens***
20 poke785,0:poke786,96:rem usr-vektor
30 input"winkel";w:w=w*~/180:rem auf bogenmass
40 e=usr(w):rem aufruf des programmes
50 printw,e:rem ergebnis in e
60 end
Listing 2. Test der Kotangens-Funktion
10  -          .LI 1,4
20  -          .BA $6000
30  -;********************************
40  -;*                              *
50  -;*    BEISPIELPROGRAMM ZU DEN   *
60  -;*       R O M - ROUTINEN       *
70  -;*                              *
80  -;*      COTANGENS-FUNKTION      *
90  -;* HEIMO PONNATH  HAMBURG  1985 *
100  -;*                              *
110  -;********************************
120  -;
130  -;EINSPRUNG MITTELS USR
140  -;ZUVOR USR-VEKTOR EINSTELLEN!
150  -;
160  -          .EQ COS=$E264
165  -          .EQ MOVFM=$BBA2
170  -          .EQ MOVMF=$BBD4
180  -          .EQ SIN=$E26B
190  -          .EQ FDIV=$BB0F
200  -          .EQ WERT=$7000
205  -          .EQ WERT1=$7010
210  -;
212  -START     LDX #<(WERT1)
214  -          LDY #>(WERT1)
216  -          JSR MOVMF
220  -          JSR COS
230  -          LDX #<(WERT)
240  -          LDY #>(WERT)
250  -          JSR MOVMF
252  -          LDA #<(WERT1)
254  -          LDY #>(WERT1)
256  -          JSR MOVFM
260  -          JSR SIN
270  -          LDA #<(WERT)
280  -          LDY #>(WERT)
290  -          JSR FDIV
300  -          RTS
310  -;
320  -          .SY 1,4
330  -          .ST
Listing 1. Hypra-Ass-Listing der Kotangens-Funktion
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →