USR

Aus C64-Wiki
Wechseln zu: Navigation, Suche
Begriffsklärung Der Titel dieses Artikels ist mehrdeutig. Weitere Bedeutungen finden sich unter USR (Begriffsklärung).
USR
Format: USR(<Parameter>)
Parameter
<Parameter>: mind. ein Parameter (Zeichenkette oder Zahl)
Einordnung
Typ: numerische Funktion
oder
String-Funktion
Kontext: System
Aufgabe: ruft eine Maschinensprache-Routine als Funktion auf
Abkürzung: uS
Verwandte Befehle
SYS

Anmerkung: Dieser Artikel beschreibt die numerische BASIC-Funktion USR unter BASIC V2 des Commodore 64.


Die BASIC-Funktion USR() ruft aus einem BASIC-Programm eine Maschinensprache-Routine als Funktion auf, wobei der Rückgabewert (Fließkomma oder Zeichenkette) vom aufgerufenen Ausdruck weiterverarbeitet werden kann. Das aufgerufene Programm kann bis zur schließenden runden Klammer entsprechende Argumente verarbeiten und ist jedenfalls dafür auch selbst verantwortlich dies zu tun. Anzahl der Argumente und deren jeweiliger Typ (Fließkomma, Zeichenkette) ist von der aufgerufenen Routine vorgegeben. Das Ergebnis wird der Ausdrucksauswertung zurückgeliefert und kann ein numerischer Wert oder eine Zeichenkette sein. Passt der retournierte Typ nicht zu dem von der Auswertung erwarteten, bricht der Interpreter mit der Fehlermeldung ?TYPE MISMATCH ERROR ab.

Die Startadresse des Maschinenprogramms muss vor dem Aufruf von USR() im Vektor mit den Speicheradressen 785 und 786 (USR-Vektor an den hexadez. Adressen $311/$312) abgelegt werden, typischerweise mit Hilfe des BASIC-Befehls POKE. Der Rückgabewert wird im Fließkomma-Akkumulator #1 beginnend bei der Speicheradresse 97 ($61) erwartet, welcher vom BASIC-Programm als Funktionswert weiter verarbeitet werden kann. An sich ist USR() als nummerische Funktion hinterlegt und der Interpreter erwartet demnach auch ein dazu passendes, numerisches Ergebnis als Fließkommazahl. Dennoch kann die Ausdrucksauswertung so gesteuert werden, dass auch eine Zeichenkette als Ergebnis akzeptiert wird (wie es auch andere String-Funktionen, z. B. CHR$ oder STR$, machen). Die Zeichenkette bzw. deren String-Descriptor muss hierbei am String-Descriptor-Stack für die weitere Ausdrucksauswertung abgelegt werden. Bei der Nutzung der gängigen ROM-Routinen (siehe Beispiel) befindet sich dann in den Speicherstellen $64/$65 der Zeiger auf den String-Descriptor und eine Kopie des Descriptors in $61/$62/$63 des Fließkomma-Akkumulators #1.

Nach einem Systemneustart des C64 ist die Startadresse mit $B248 initialisiert, welche auf die Ausgaberoutine der BASIC-Fehlermeldung ?ILLEGAL QUANTITY ERROR verzweigt[1]. Dieser Fehler wird bei USR()-Aufruf auch geliefert, bis eine andere Adresse gesetzt wird.

In Bezug auf die Argumentsyntax, wird bei fehlenden Argumenten der Fehler ?SYNTAX ERROR ausgegeben. Weitere Fehlermeldungen hängen von der aufgerufenen Maschinenprogramm-Routine ab, die etwa zu einer Ausgabe der BASIC-Fehlermeldung ?TYPE MISMATCH ERROR führen kann, wenn ein Argument nicht den gewünschten Typ aufweist oder die nicht im erwarteten Wertebereich befindliche Argumente mit ?ILLEGAL QUANTITY ERROR ahndet. Auch andere Fehlermeldungen könnten hervorgerufen werden.

Adressen der Funktion in anderen BASIC-Varianten:

BASIC USR-Vektor Adresse nach Neustart Anmerkung
BASIC V2 (C64) 785/786
$0311/$0312
45640
$B248
-
BASIC V2 (VC20) 1/2
$0001/$0002
53832
$D248
-
BASIC 3.5 (264-Serie) 1281/1282
$0501/$0502
39196
$991C
-
BASIC 7.0 (C128) 4633/4634
$1219/$121A
32040
$7D28
bezogen auf Bank 15

Beispiele[Bearbeiten]

Schnelle Multiplikation mit 10[Bearbeiten]

Eine schnelle Multiplikation mit 10[2]:

10 REM MULTIPLY BY 10 - $BAE2 ROUTINE
20 POKE 786,186: POKE 785,226
30 FOR I=1 TO 10
40 PRINT USR(1/I)
50 NEXT I

Die Ausgabe zeigt dann

 10
 5
 3.33333334
 2.5
 2
 1.66666667
 1.42857143
 1.25
 1.11111111
 1

Im Vergleich zu einer Multiplikation mit dem Ausdruck 1/I*10 ist die USR()-Variante deutlich (rund 40 %) schneller.

Mit den Zeilen

10 REM DIVIDE BY 10 - $BAFE ROUTINE
20 POKE 786,186: POKE 785,254

in obigem Beispiel hat man statt einer Mal-10-Funktion eine Durch-10-Funktion[3].

Zeichenkette als Argument[Bearbeiten]

Beispiel für eine Zeichenkette als Argument

10 REM LEN()-FUNKTION - $B77C ROUTINE
20 POKE 786,183: POKE 785,124
30 PRINT USR("123")
 3


FRE()-Funktion ohne Garbage-Collection[Bearbeiten]

Variante der FRE()-Funktion, die dabei nicht die Garbage Collection auslöst:

10 POKE 786,179: POKE 785,135
20 PRINT USR(0),FRE(0)
-26665    -26665


Zeichenkette als Rückgabewert[Bearbeiten]

Beispiel für eine Zeichenkette als Retourwert[4]

10 REM CHR$()-FUNKTION - $B6EC
20 POKE785,236: POKE786,182
30 A$=USR(49)
40 PRINT "<"+A$+">"
<1>


Beispielimplementierung als String-Funktion[Bearbeiten]

Folgender Assembler-Code retourniert eine Zeichenkette der Länge 1, wobei diese stets den Buchstaben "A" enthält.[5] Es erfolgt dabei keine Parameterauswertung.

USR:   LDA #1          ; Platz für 1 Zeichen am
       JSR $B47D       ; String-Heap anfordern, Descriptor in $61-$63
       
       LDA #"A"        ; das Zeichen für den String
       LDY #0          ; Index auf das erste Zeichen im String
       STA ($62),Y     ; Zeichen in den angeforderten String-Platz schreiben

       PLA             ; Aufruf aus Numeric Expression verwerfen,
       PLA             ; damit das Ergebnis vom Typ String sein kann.

       JMP $B4CA       ; String-Descriptor von $61 auf String-Stack


Weblinks[Bearbeiten]


Quellen[Bearbeiten]

  1. $E3BF/58303: Initialize BASIC RAM (auf AAY64) - Initialisierung des USR()-Vektors. Sprache:englisch
  2. $BAE2/47842: Multiply FAC#1 by 10 - Fließkommaakkumulator #1 mit Konstante 10 multiplizieren. Sprache:englisch
  3. $BAFE/47870: Divide FAC#1 by 10 - Fließkommaakkumulator #1 durch Konstante 10 dividieren. Sprache:englisch
  4. $B4D5/46293: Save String Descriptor - Zeichenkette in Fließkommaakkumulator #1 retournieren. Sprache:englisch
  5. $B6EC/46828: Evaluate <chr$> - Rückgabe eines String-Wertes bei einer Funktion Sprache:englisch