Die nützlichsten ROUTINEN 1987 written by Klaus Jahn

Sie haben sich bestimmt schon darübergeärgert, dass Sie In Maschinensprache
auf den BASIC-Komfort verzichten mußten.
Das soll sich nun auch für Sie ändern.
Ich gebe Ihnen hier eine komplette Auflistung der gesamten nützlichen ROM-Routinen im Spectrum-ROM.
Außerdem nenne ich Ihnen die Anwendung mit den Registern, die die Routinen benutzen. Sie werden sehen, daß einige Routinen mit dem so genannten Calculatorstack arbeiten;dieser ist eine Art Stapel, um 5-Byte-Fliesskommazahlen oder Stringparameter abzuspeichern, aber dazu Später mehr !
Ich zeige Ihnen jetzt die wichtigsten Routinen:

BEEP x/y,z:
a) ld a,{x}    Dividend der Tonlänge
   call 11560 auf Calculatorstack legen
b) ld a,{y}    Divisor der Tonlänge
   call 11560 auf Calculatorstack legen
c) rst 40 Calculatoraufruf
   Byt. #5     Zahlen dividieren
   Byt. #56    Ende des Calculators
d) ld a,{z}    Tonhöhe
   call 11560 auf Calculatorstack legen
e) call 1016   BEEP-Routine aufrufen.

BORDER x:
a) ld a,{x}    Farbe in Akku bringen
b) call 8859   BORDER-Routine aufrufen.

BRIGHT x:      [siehe "Farben setzen"]

CIRCLE x,y,z:
a) ld a,{x}    X-Koordinate   
call 11560 auf Calculatorstack legen
b) ld a,{y}    Y-Koordinate   
call 11560 auf Calculatorstack legen
c) ld a,{z}    Radius   
call 11560 auf Calculatorstack legen
d) exx
   push hl     hl' - Register sichern  
 exx
e) call 9005   CIRCLE-Routine aufrufen
f) exx
   pop hl      hl' - Register holen.
exx

CLS:           call 3435

COPY:          call 3756

DRAW x,y:
a) ld a,{x}    X-Koordinate
   call 11560 auf Calculatorstack legen
b) ld a,{y}    Y-Koordinate
   call 11560 auf Calculatorstack legen
c) exx
   push hl     hl' - Register sichern
   exx
d) call 9335   DRAW I - Routine
e) exx
   pop hl      hl' - Register holen.
   exx

DRAW x,y,z:
a) X- und Y- Koordinaten wie bei
   DRAW x,y auf den Calculatorstack bringen
b) ld a,{z}    Radiantenzahl   call 11560 auf Calculatorstack legen
c) hl' -Register sichern (siehe DRAW x,y)
d) call 9108   DRAW II - Routine
e) hl' -Register holen (Siehe DRAW x,y).

FLASH:         [siehe "Farben festlegen"]

INK:           [siehe "Farben festlegen"]

INVERSE:       [siehe "Farben festlegen"]

LIST x:
a) ld hl,{Startadresse von Zeile x}
b) call 6229

LOAD Header:
a) ld ix,{Anfangsadresse des Headers}
b) ld de,17
c) xor a
d) scf
e) call 1366   LOAD-Routine

LOAD CODE:
a) ld ix,{Anfangsadresse des Codes}
b) ld de,{Länge des Codes}
c) ld a,255
d) scf
e) call 1366   LOAD-Routine

NEW:           call 4535

OVER:          [siehe "Farben festlegen"]

PAPER:         [siehe "Farben festlegen"]

PAUSE x:
a) res 5,(iy+1) Eingabe freimachen
b) ld bc,{x}    Länge in msec. nach bc
c) call 7997

PLOT x,y:
a) ld c,{x}    X-Koordinate in c
b) ld b,{y}    Y-Koordinate in b
c) call 8927   PLOT-Routine

PRINT #x:
Bevor man irgendetwas zum erstenmal ausdruckt, muß der Bildkanal mit PRINT#
geöffnet werden ! Das geschieht so:
a) ld a,{x}    Kanalnummer in Akku
b) call 5633   Kanal öffnen
Die Kanäle lauten:
#3  Ausdruck auf Drucker
#2  Ausdruck auf Screen Zeile 0 bis 21
#1  Ausdruck auf Screen Zeile 22 bis 23
#0                  -//-
#255 Workspace
#254 Keyboard

PRINT CHR$(x):
a) ld a,{x}    Code des Zeichens in Akku
b) rst 16      Ausdruck

PRINT a$:
a) ld de,{Startadresse der Zeichenkette}
b) ld bc,{Länge der Zeichenkette}
c) call 8252   Textdruck.

PRINT x:  {x liegt im Bereich 0 - 9999}
a) ld bc,{x}   Zahl in bc-Register bringenb) 
call 6683   Zeilennummerdruck-Routine

PRINT x:
a) ld bc,{x}   Zahl
b) call 11563 auf Calculatorstack legen
c) call 11747  Zahlenausdruck.

PRINT AT y,x:
a) ld b,{24-y}
b) ld c,{33-x}
c) call 3545

SAVE Header:
a) ld ix,{Startadresse des Headers}
b) ld de,17
c) xor a
d) call 1218   SAVE-Routine

SAVE CODE:
a) ld ix,{Startadresse des Codes}
b) ld de,{Länge des Codes}
c) ld a,255
d) call 1218   SAVE-Routine.

SCROLL:        call 3282

STOP:          call 7406

VERIFY CODE:
a) ld ix,{Startadresse des Codes}
b) ld de,{Länge der Codes}
c) ld a,255
d) and a
call 1366   LOAD-Routine

SOUND x,y:
(Erzeugt einen kurzen Pfeifton. x ist die Tontiefe und liegt im Bereich
[1..65535]. y ist die Tonlänge und
liegt im Bereich [0..65535].)
a) ld hl,{x}
b) ld de,{y}
c) call 949

BASIC-Programm löschen:  call 4656

Calculatorstack löschen: call 5829

Ausdruck des obersten Calculatorstackwertes: call 11747

Akkuinhalt auf Calculatorstack legen: call 11560

bc - Registerinhalt auf Calculatorstack legen: call 11563

obersten Calculatorstackwert in den Akku bringen: call 11733

obersten Calculatorstackwert ins bc-Registerpaar bringen: call 11682

FARBEN FESTLEGEN:
Als Beispiel geben wir uns an, wie die Befehle
PAPER 7: INK 9: OVER 1    in Assembler aussehen:
Die normale temporäre Farbzuweisung geschieht ganz einfach mit rst 16.
Soll z.B. PAPER 7 ausgedrückt werden,
so schreibt man:
a) ld a,17     (=ASCII-Code von PAPER)
b) rst 16
c) ld a,7      (für PAPER 7)
d) rst 16
Sollen die Farben allerdings bleiben
(nach CLS oder PRINT #), dann muß man mit
folgenden call-Befehlen arbeiten:
a) call 3405
b) Festlegung der gewünschten Farbanweisung mit rst 16
c) call 7341

MEM-Anweisung:
a) call 7962
b) ld hl,65535
c) and a
d) sbc hl,bc
e) der in BASIC noch verfügbare Bereich steht jetzt im hl-Register.

EDIT: call 3884
Ausgabe eines Listings: call 6037

hl = hl * de: call 12457

Bei folgenden 3 Prüfroutinen trifft die Bedingung zu, wenn das Carry-Flag=0 ist:
Akku auf Zifferncode prüfen: call 11547
Akku auf Buchstabencode prüfen:call 11405
Akku auf alphanumerisch prüfen:call 11400

Ausgabe von Text, dessen letztes Byte mit gesetztem bit 7 markiert ist:
a) ld de,{Startadresse des Textes}
b) call 3082

BASIC-Zeilenkursor hoch: call 4185

BASIC-Zeilenkursor runter: call 4083

Löschen von Calculatorstack, Workspace und Editorspace: call 5808

Berechnen einer Bildschirm-Pixel-Adresse nach hl. Angegeben wird die (X,Y)-Pixelposition:
a) ld c,{X-Koordinate}
b) ld b,{Y-Koordinate}
c) call 8874
d) hl gibt die SCREEN$-Adresse an.

a = c + 10 * a: call 12171

Scrollen einer bestimmten Bildzeilen-
zahl (von unten gesehen):
a) ld b,{Zeilenzahl}
b) call 3584

Löschen einer bestimmten Bildzeilen- zahl (von unten gesehen):
a) ld b,{Zeilenzahl}
b) call 3652

Ausgabe einer Fehlermeldung:
Dazu wird der Befehl rst 8 benutzt. Der Code der Fehlermeldung wird einfach als ein Byte dem rst 8-Befehl angefügt.
Man befindet sich nach aufruf dieses Befehls sofort wieder im BASIC. Z.B. wird die Meldung 0 OK so gemacht:

a) rst 8
b) Byt. #255  {Meldecode minus 1}

POINT (x,y):
a) ld c,{x}
b) ld b,{y}
c) call 8910
d) call 7833
e) Ergebnis (1 oder 0) befindet sich im Akku.

SCREEN$ (y,x):
a) ld a,{y}    Y-Koordinate
   call 11560 auf Calculatorstack legen
b) ld a,{x}    X-Koordinate
   call 11560 auf Calculatorstack legen
c) call 9525   SCREEN$-Routine
d) call 11249  String-Parameter vom Calculatorstack holen
Jetzt befinden sich die Stringparameter
(Länge und Startadresse) in den
Registern bc und de. Um das Ergebnis
der Funktion SCREEN$ zu bekommen,
schreibt man einfach:
e) ld a,(de)
und das Ergebnis (der ASCII-Code) befindet sich im Akku.

ATTR (y,x):
a) ld c,{y}
b) ld b,{x}
c) call 9603
d) call 7833
e) Das Ergebnis steht im c-Register.

Stringdefinition:
Man kann einen String schaffen, indem man seine Startadresse ins de- und seine Länge ins bc-Register bringt.
Der Akku muß 0 sein; dann werden diese 5 Bytes mit der Routine
   call 10929
auf den Calculatorstack gebracht.
Mit der Routine
   call 11249
hingegen kann man ein Stringparameter vom Calculatorstapel herunterholen.

Der Calculator:
Wie man mit dem rst 40-Befehl umgeht, haben Sie ja schon bei dem BEEP-Befehl gesehen. Der Calculator kann immer nur den obersten oder die obersten 2 Calculatorstack-Elemente behandeln. Das Ergebnis wird dann wieder auf den Stack zurückgelegt. Ich gebe Ihnen jetzt eine komplette Auflistung der so genannten Calculator-opcodes, die die sämtlichen Spectrum-Funktionen darstellen.

Diese Opcodes werden einfach als Bytes hinter dem rst 40-Befehl angefügt.

Im Folgenden sehen Sie eine Liste, in der die Calculatoropcodes, also sämtliche BASIC-Funktionen des Spectrum aufgeführt sind. Bei jedem Opcode sehen Sie auch die Calculatorsack-Manipulation durch die Operationen. In der nun folgenden Liste ist immer das rechteste Calculatorstack-Element das oberste auf dem Stack liegende Element !

Opcode	Operation	Stack vorher	/Nachher
  1)	tauschen: 	X,Y,Z		X , Z , Y
  2)	löschen 	X,Y,Z 		X,Y
  3)	-		X,Y,Z  		X ,(Y - Z)
  4)	*		X,Y,Z		X ,(Y * Z)
  5)	/		X,Y,Z		X ,(Y / Z)
  6)	^		X,Y,Z		X ,(Y ^ Z)
 15)	+		X,Y,Z		X ,(Y + Z)
 31)	SIN		X,Y,Z		X,Y,(SIN Z) 
 32)	COS		X,Y,Z		X,Y,(COS Z)
 33)	TAN		X,Y,Z		X,Y,(TAN Z)
 34)	ASN		X,Y,Z		X,Y,(ASN Z)
 35)	ACS		X,Y,Z		X,Y,(ACS Z)
 36)	ATN		X,Y,Z		X,Y,(ATN Z)
 37)	LN		X,Y,Z		X,Y,(LN Z)
 38)	EXP		X,Y,Z		X,Y,(EXP Z)
 39)	INT		X,Y,Z		X,Y,(INT Z)
 40)	SQR		X,Y,Z		X,Y,(SQR Z)
 41)	SGN		X,Y,Z		X,Y,(SGN Z)
 42)	ABS		X,Y,Z		X,Y,(ABS Z)
 43)	PEEK		X,Y,Z		X,Y,(PEEK Z)
 44)	IN		X,Y,Z		X,Y,(IN Z)
 49)	dupliz.		X,Y,Z		X, Y, Z, Z
 50)	MOD/DIV	X,Y		Rest , (X/Y)
 56)	End Calc.
160)	0		X,Y		X,Y, 0
161)	1		X,Y		X,Y, 1
162)	0.5		X,Y		X,Y, 0.5
163)	PI/2		X,Y		X,Y, 1.5707
164)	10		X,Y		X,Y, 10
  8)	AND		X,Y,Z		X,(Y AND Z)
  7)	OR		X,Y,Z		X,(Y OR Z)
 48)	NOT		X,Y		X , (NOT Y)
 58)	Int.-Teil
	schneiden	X,Y,Z		X,Y, Z-INT Z

Es gibt aber hier auch die Funktionen, die mit Strings arbeiten; z.B. wandelt die STR$-Funktion einen numerischen Ausdruck in einen Stringausdruck um. Wenn man das mit dem Calculator tut, so muß man ein Stringparameter auch als solches vom Calculatorstack herunterholen und nicht etwa als Zahl.
Sie erinnern sich: Mit call 11249 kann man ein Stringparameter, welches auf dem Calculatorstack liegt, in die Register bc (die Stringlänge) und de (die Start-adresse des Strings) bringen. Umgekehrt kann man die Inhalte dieser beiden Registerpaare als Stringparameter mit call 10929 auf den Calculatorstapel~bringen.
Sehen Sie nun auch diese Funktionen:

Opcode	Operation	Stack vorher	/Nachher
 30)	LEN		X , Y$		X , LEN Y$
 46)	STR$		X,Y,Z		X,Y,STR$ Z
 47)	CHR$		X,Y,Z		X,Y,CHR$ Z
 25)	USR		X , Y$		X , USR Y$
 28)	CODE		X , Y$		X , CODE Y$
 23)	String + 	X , Y$ , Z$	X , Y$ + Z$
 27)	negieren	X,Y,Z		X , Y , (-Z)

Des Weiteren gibt es Testfunktionen, die als Ergebnis entweder eine 1 (wahr) oder eine 0 (falsch) liefern. Um Speicherplatz zu sparen, wurden alle 12 Vergleichsoperationen in eine Routine gepackt. Zur Unterscheidung dient in dem Falle das b-Register, denn man muß hier den Opcode zusätzlich ins b-Register laden.
In der folgenden Tafel sind diese Operationen mit  , b  gekennzeichnet. Beachten Sie, daß es 6 Vergleichsoperationen für numerische Operanden und 6 für Stringoperanden gibt !

Opcode	Operation	Stack vorher	/Nachher
  9 ,b	<=		X , Y		1 wenn X<=Y, 0 wenn X>Y
 10 ,b	>=		X , Y		1 wenn X>=Y, 0 wenn X<Y
 11 ,b	<>		X , Y		1 wenn X<>Y, 0 wenn X=Y
 12 ,b	>		X , Y		1 wenn X>Y, 0 wenn X<=Y
 13 ,b	<		X , Y		1 wenn X<Y, 0 wenn X>=Y
 14 ,b	=		X , Y		1 wenn X=Y, 0 wenn X<>Y

 17 ,b	<= String	X$ , Y$		1 wenn X<=Y$, 0 wenn X$>Y$
 18 ,b	>= String	X$ , Y$		1 wenn X>=Y$, 0 wenn X$<Y$
 19 ,b	<> String	X$ , Y$		1 wenn X<>Y$, 0 wenn X$=Y$
 20 ,b	> String 	X$ , Y$		1 wenn X$>Y$, 0 wenn X<=Y$
 21 ,b	< String		X$ , Y$		1 wenn X$<Y$, 0 wenn X>=Y$
 22 ,b	= String		X$ , Y$		1 wenn X$=Y$, 0 wenn X<>Y$

 54	< 0		X		1 wenn X<0, 0 wenn X>=0
 55	> 0		X		1 wenn X>0, 0 wenn X<=0

Ausrechnen eines Terms, der als String im Speicher steht:
Dazu benutzt man die VAL/VAL$-Routine.
Sie beginnt ab Adresse 13790; die Unterscheidung von VAL und VAL$ erfolgt wieder über das b-Register.
VAL hat den Operationscode 29
VAL$ hat den Operationscode 24.
Man kann z.B. mit der VAL-Routine eine mathenatische Aufgabe lösen, ähnlich PRINT VAL "12 * SIN (n/PI)". Nehmen wir an, unsere Aufgabe steht ab Adresse 60000 und ist 16 Bytes lang. So schreiben wir:
a) ld de,60000   {Startadresse}
b) ld bc,16      {Länge}
c) xor a
d) call 10934   Parameter auf Calc.stack
e) ld b,29      Opcode von VAL nach b
f) call 13790   VAL/VAL$-Routine
g) Das Ergebnis liegt auf dem Calculatorstack.

Und nun zum Schluß möchte ich Ihnen noch zeigen, wie man mit dem rst 40-Befehl umgeht. Man kann nämlich mehrere Operationen hintereinander ausführen. Nehmen wir z.B. an, wir wollten den Term
   10 + 23 * SIN ( x / 80 * PI )
mit dem Calculator berechnen.

Wir müßten zürst x auf den Calculator-Stack legen und dann von innen nach außen fertigrechnen:
a) X liegt auf Stack		X
b) ld a,80
c) call 11560			X , 80
d) rst 40
   Byt. #5    /			X / 8
   Byt. #163  PI/2		(X/80) , PI/2
   Byt. #49   DUPLICATE	(X/80) ,PI/2,PI/2
   Byt. #15			(X/80) ,PI/2+PI/2		(X/80) , PI
   Byt. #4			(x/80) * PI		(x/80*PI)
   Byt. #31   SIN			SIN (x/80*PI)
   Byt. #56   End.
e) ld a,23
f) call 11560			SIN(x/80*PI) , 23	SIN(x/80*PI) , 23
g) rst 40
   Byt. #4	*		23*SIN(x/80*PI)
   Byt. #164	10		23*SIN(x/80*PI) , 10
   Byt. #15	+		10+23*SIN(x/80*PI)
   Byt. #56   End.
h) ret
i) das Ergebnis liegt dann auf dem Calculatorstack !

Neben den BASIC-Funktionen stehen dem Calculator auch noch 6 Speicher zu Verfügung, in die er Werte bringen kann. Diese 6 Speicher werden wie folgt bezeichnet:"
MEM0 , MEM1 , MEM2 , MEM3 , MEM4 , MEM5

Um eine Kopie des obersten Calculator-stackwertes in eine dieser Speicherzellen zu bringen, benutzt man die Opcodes 192 bis 197. Um den Inhalt einer dieser Speicher auf den Calculatorstack zu legen, benutzt man die Opcodes 224 bis 229

Es gibt sogar Calculatoropcodes zum überspringen von Opcodes. Dazu gibt man hinter dem Befehlsopcode die Anzahl der zu überspringenden Opcodes an; diese kann auch negativ sein, um rückwärts zu springen.

Opcode: Ausführung:
 51	unbedingter Sprung
  0	Sprung nur dann, wenn das oberste Calculatorelement ungleich null ist.
53 ,b	Springt nur, wenn das b-Register ungleich Null ist. Außerdem wird das b-Register dekrementiert.
Bitte sehen Sie sich dazu noch das Beispiel auf der nächsten Seite an !

a) rst 40		Calculatoraufruf
b) Byt. #163		PI/2 auf Calculatorstack
c) Byt. #51		Sprung
   Byt. #3	------,	3 Bytes sollen übersprungen werden
d) Byt. #49	      |	PI/2 duplizieren
e) Byt. #15	      |	PI/2 + PI/2  (=PI)
f) Byt. #56	<----'	End of Calculator
g) ld a,2
   call 5633		Kanal #2 öffnen
h) call 11747		Oberstes Calculatorelement wird ausgedruckt.
i) ret

Es wird also nicht PI, sondern PI/2 (= "+STR$ (PI/2)+") ausgedruckt, da die beiden Opcodes zum verdoppeln übersprungen worden sind.

So, das war die Erklärung aller nützlichen ROM-Routinen und des Calculators rst 40.

 1987 by OMIKRON-Software all programs & MC-Routines written by Klaus Jahn, 6432 Heringen 1, W-Germany