USR

Aus C64-Wiki
Zur Navigation springenZur Suche springen
Begriffsklärung Der Titel dieses Artikels ist mehrdeutig. Weitere Bedeutungen finden sich unter USR (Begriffsklärung).
USR
Syntax: 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
Token: $b7 (183)
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. Die aufgerufene Routine bekommt den in Klammer ausgewerteten Ausdruck (der Klammerausdruck unmittelbar nach dem Funktionsnamen) übergeben, wobei der Typ (Fließkomma, Zeichenkette) dort entsprechend geprüft werden muss, um den Ausdruckswert auch richtig - könnte auch flexibel beide Typen akzeptieren - verarbeiten zu können (numerisch vom Fließkomma-Akkumulator, als String vom String-Descriptor-Stack).[1] Das Ergebnis wird an die Ausdrucksauswertung zurückgeliefert und kann dann ein numerischer Wert oder eine Zeichenkette sein. Passt der retournierte Typ nicht zum erwarteten Typ, wo die Funktion eingebettet ist, 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[2]. 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 | Quelltext bearbeiten]

Schnelle Multiplikation mit 10[Bearbeiten | Quelltext bearbeiten]

Eine schnelle Multiplikation mit 10[3]:

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[4].

Zeichenkette als Argument[Bearbeiten | Quelltext 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 | Quelltext 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 | Quelltext bearbeiten]

Beispiel für eine Zeichenkette als Retourwert[5]

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


Beispielimplementierung als String-Funktion[Bearbeiten | Quelltext bearbeiten]

Folgender Assembler-Code retourniert eine Zeichenkette der Länge 1, wobei diese stets den Buchstaben "A" enthält.[6] 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 | Quelltext bearbeiten]


Quellen[Bearbeiten | Quelltext bearbeiten]

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