; RSX - Erweiterung "SCRIPT" von Armin Mueller
; ; SCRIPT [,f] ,xp ,yp ,a$ : Text zeichnen ; ZOOM ,xv ,yv ,xl ,yl ,prop : Textgroesse festlegen ; SCROLL [,n] : Bildschirm scrollen ; SIZE ,xl ,yo ,br ,ho ,n ,m : Scrollfenster festlegen ; ; ; Systemroutinen ; ORG #a000 ; Programmstart ENT $ ; Einsprung ; rsxini:EQU #BCD1 ; KL LOG ON EXTENSION romver:EQU #B915 ; KL TASTE ROM romsel:EQU #B906 ; KL LOWER ROM setcol:EQU #BBDE ; GRA SET PEN move:EQU #BBC0 ; GRA MOVE ABSOLUTE drawr:EQU #BBF9 ; GRA LINE RELATIVE getmat:EQU #BBA5 ; (Adresse einer Zeichenmatrix holen) patch:EQU #AC04 ; (Indirection fuer Fehlerausgabe) error1:EQU #AE34 ; (diverse Routinen und Adressen error2:EQU #DD3F ; beim CPC 464 fuer die error3:EQU #B0C2 ; Patch - Routine) error4:EQU #FB21 ; ; RSX einbinden ; start:LD BC,beftab ; Anfang der RSX - Befehlstabelle LD HL,kernel ; Adresse fuer Verkettung der RSX CALL rsxini ; RSX einbinden LD A,#C9 ; RET an den Anfang setzen LD (start),A CALL romver ; Romversion ermitteln: LD A,H ; Fertig, falls kein CPC 464 AND A RET NZ LD A,(patch) ; Wenn der Patch schon belegt ist, CP #C9 ; z.B. mit dem Emulator, auch fertig RET NZ LD A,#C3 ; Sonst mit 'JP unloc' LD (patch),A ; die Patch - Routine aktivieren LD HL,unloc ; (siehe da) LD (patch+1),HL RET ; Ende der RSX-Einbindung ; ; Anfangswerte fuer ZOOM ; ylinie:DEFW 2 ; Liniendicke xlinie:DEFW 2 yvergr:DEFW 4 ; Vergroesserung xvergr:DEFW 4 yvgneg:DEFW -4 ; Zweierkomplement der Vergoesserung xvgneg:DEFW -4 ; ; Parameter - Ablage ; Die Parameter werden von den Befehlen benoetigt. ; Sie ueberschreiben aber die RSX Einbindung, da diese ; nur ein Mal aufgerufen wird. (26 Byte gespart) ; kernel:EQU start+1 ; Verkettung der RSX-Tabellen matrix:EQU ylinie-26 ; Matrix des aktuellen Zeichens text:EQU matrix+9 ; Zeiger auf den auszugebenden Text ypos:EQU text+2 ; Y-Position des Textes xpos:EQU ypos+2 ; X-Position farbe:EQU xpos+2 ; Farbe punkt1:EQU farbe+2 ; Speichert, welche Nachbarpunkte punkt2:EQU punkt1+1 ; verbunden werden muessen punkt3:EQU punkt2+1 punkt4:EQU punkt3+1 maske:EQU punkt4+1 ; Maske fuer die Zeichenmatrix zeile:EQU maske+1 ; Aktuelle Zeile der Zeichenmatrix proptn:EQU zeile+2 ; Proportion des Textes ; ; Tabelle der RSX - Befehle ; beftab:DEFW namen ; Zeiger auf die Namen JP script ; Programmteile (analog zu den Namen) JP scroll JP zoom JP size namen:DEFM "SCRIP" ; Namen der Befehle DEFB "T"+#80 DEFM "SCROL" DEFB "L"+#80 DEFM "ZOO" DEFB "M"+#80 DEFM "SIZ" DEFB "E"+#80 DEFB 0 ; Ende der Tabelle ; ; Routine legt Vergroesserung fest ; zoom:CP #05 ; Fuenf Parameter ? RET NZ ; Abbruch, falls nicht PUSH IX ; HL mit IX laden POP HL ; (alter Zeiger auf die Parameter) LD DE,proptn ; Zeiger auf die neue Parameterablage LD BC,#000A ; Parameter 10 Bytes lang LDIR ; Parameter kopieren ; LD HL,proptn ; Proportion direkt an die LD DE,pro+1 ; entsprechende Stelle im LDI ; Hauptprogramm kopieren LDI ; LD B,#02 ; Die X- und Y-Liniendicke declop:LD A,(HL) ; jeweils um 1 erniedrigen AND A JR Z,nicht ; (minimal auf 0), DEC A nicht:LD (HL),A ; damit das Verhaeltnis zur INC HL ; Vergroesserung stimmt INC HL DJNZ declop ; LD HL,ylinie ; Die 2 Lieniendicken und LD BC,#041F ; Vergroesserungen bearbeiten: zoomlp:LD A,(HL) ; Die Lowbytes verdoppeln, da die SLA A ; Vergroesserung nur in Zweierschritten AND C ; moeglich ist, dann auf max. #1F LD (HL),A ; begrenzen INC HL LD (HL),#00 ; Die Hibytes loeschen INC HL DJNZ zoomlp ; Das Ganze 4 mal durchfuehren ; LD HL,(yvergr) ; Von den beiden Vergroesserungen CALL swaphl ; jeweils noch eine negative LD (yvgneg),HL ; Ausfuehrung anfertigen LD HL,(xvergr) CALL swaphl LD (xvgneg),HL RET ; Fertig ; ; Hauptprogramm: vergroessern ; script:PUSH IX ; Die Parameter nach 'text' kopieren POP HL LD DE,text LD BC,#0008 LDIR ; CP #03 ; Falls 3 Parameter JR Z,nofarb ; -> Programm sofort ausfuehren CP 4 ; Falls nicht 4 Parameter RET NZ ; -> Abbruch LD A,(farbe) ; sonst vorher noch CALL setcol ; die Zeichenfarbe bestimmen ; nofarb:LD BC,#0008 ; Die Y-Vergroesserung * 8 LD DE,(yvergr) ; zur Y-Position des Textes addieren, CALL mult ; damit die linke untere Ecke des LD DE,(ypos) ; Textes auf die Koordinaten zeigt ADD HL,DE ; (Im Gegensatz zu "TAG" ist das LD (ypos),HL ; praktischer) ; LD HL,(text) ; HL mit dem Zeiger auf den Textkopf LD A,(HL) ; laden und schauen, wie lang der AND A ; Text ist RET Z ; -> Falls 0 Abbruch INC HL LD E,(HL) ; sonst den Anfang der Zeichenfolge INC HL ; indirekt in HL laden LD D,(HL) EX DE,HL LD B,A ; ... und ihre Laenge merken ; string:PUSH BC ; Textlaenge und -adresse merken PUSH HL LD A,(HL) ; das naechste Zeichen holen CALL getmat ; schauen, wo die Zeichenmatrix liegt CALL NC,romsel ; und eventuell das ROM aktivieren, LD DE,matrix ; danach bei 'matrix' ablegen LD BC,#0008 LDIR ; um die Abtastung zu erleichern, wird XOR A ; unter die Matrix noch eine leere LD (DE),A ; Zeile gesetzt ; LD D,A ; Vorbereitung zur Hauptschleife: LD E,A ; Die X-Koordinate wird auf 0 gesetzt, LD A,#80 ; die Maske zur Abtastung der Matrix LD (maske),A ; ist am Anfang &x10000000 xloop:LD HL,#0008 ; ... und die Y-Koordinate 8 yloop:PUSH HL ; Koordinaten retten PUSH DE LD BC,matrix-1 ; Aktuelle Matrixzeile berechnen ADD HL,BC LD (zeile),HL LD A,(maske) ; Und falls auf dieser Matixstelle AND (HL) ; ein Punkt gesetzt ist ... POP DE POP HL CALL NZ,zeichn ; -> die Zeichenroutine aufrufen DEC L ; den Punkt unterhalb bearbeiten, JR NZ,yloop ; wenn die Spalte noch nicht fertig ist LD A,(maske) ; sonst die Maske eine Spalte SRL A ; weiter rotiern LD (maske),A INC E ; die X-Koordinate erhoehen LD A,8 ; und pruefen, ob die CP E ; letzte Spalte erreicht ist JR NZ,xloop ; sonst naechste Spalte zeichnen ; pro:LD DE,8 ; Die Breite der Matrix (Proportion) LD BC,(xvergr) ; mit der X-Verg. multiplizieren CALL mult ; und zur alten X-Position dazuzaehlen, LD BC,(xpos) ; um die X-Pos. fuer das ADD HL,BC ; naechste Zeichen zu erhalten LD (xpos),HL ; POP HL ; den Zeiger auf das naechste INC HL ; Zeichen setzen POP BC ; so lange wiederholen, bis alle DJNZ string ; Zeichen auf dem Bildschirm sind RET ; Fertig! ; ; Unterprogramm zeichnen ; zeichn:PUSH HL ; Koordinaten retten PUSH DE ; PUSH HL LD HL,(zeile) ; Auf der Matrix testen, LD A,(maske) ; ob der Punkt links vom aktuellen SLA A ; Punkt gesetzt ist AND (HL) LD (punkt2),A ; Das Ergebnis merken ; INC HL ; Punkt unten LD A,(maske) AND (HL) LD (punkt1),A ; LD A,(maske) ; Punkt links unten SLA A AND (HL) LD (punkt3),A LD A,(maske) ; Punkt rechts unten SRL A AND (HL) LD (punkt4),A POP HL ; PUSH HL ; Die X-Position auf der Matrix (DE) LD BC,(xvergr) ; mit der X-Vergr. (BC) multiplizieren, CALL mult LD BC,(xpos) ; dann die X-Koordinate des Textes ADD HL,BC ; addieren, um die Bildschirmkoordinate POP DE ; des Punktes zu erhalten EX DE,HL ; PUSH DE CALL swaphl ; Das Vorzeichen der Y-Position auf EX DE,HL ; der Matrix (HL) tauschen und mit der LD BC,(yvergr) ; Y-Vergr. multiplizieren, CALL mult LD BC,(ypos) ; dann die Y-Koordinate des Textes ADD HL,BC ; addieren, um die Bildschirmkoordinate POP DE ; des Punktes zu erhalten ; LD A,(xlinie) ; Zaehler X auf X-Liniendicke setzen liniex:PUSH DE ; Koordinaten und Zaehler retten PUSH HL PUSH AF ; LD A,(ylinie) ; Zaehler Y auf Y-Liniendicke setzen liniey:PUSH AF ; Zaehler und Koordinaten retten PUSH HL PUSH DE ; LD A,(punkt1) ; Schauen, ob Punkt unten AND A ; belegt ist JR Z,askp2 ; -> weiter, falls nicht CALL move ; sonst Linie vom aktuellen LD DE,#0000 ; Matrixpunkt mit der Laenge yvgneg LD HL,(yvgneg) ; zum Punkt unten ziehen CALL drawr ; askp2:LD A,(punkt2) ; Schauen, ob Punkt links belegt ist AND A JR Z,askp3 ; -> weiter, falls nicht POP DE ; sonst Koordinaten holen POP HL PUSH HL PUSH DE CALL move ; Linie vom aktuellen Matrixpunkt LD HL,#0000 ; zum Punkt links ziehen LD DE,(xvgneg) CALL drawr ; askp3:LD A,(punkt3) ; Schauen, ob Punkt links unten AND A ; belegt ist JR Z,askp4 ; -> weiter, falls nicht POP DE ; sonst Koordinaten holen POP HL PUSH HL PUSH DE CALL move ; Linie vom aktuellen Matrixpunkt LD DE,(xvgneg) ; zum Punkt links unten ziehen LD HL,(yvgneg) CALL drawr ; askp4:LD A,(punkt4) ; Schauen, ob Punkt rechts unten AND A ; belegt ist JR Z,endy ; -> weiter, falls nicht POP DE ; sonst Koordinaten holen POP HL PUSH HL PUSH DE CALL move ; Linie vom aktuellen Matrixpunkt LD DE,(xvergr) ; zum Punkt rechts unten ziehen LD HL,(yvgneg) CALL drawr ; endy:POP DE ; Koordinaten und Zaehler Y holen POP HL POP AF AND A ; wenn Zaehler Y=0 JR Z,endx ; -> weiter mit Zaehler X LD I,A ; Sonst Zaehler Y merken POP AF ; Zaehler X holen PUSH AF AND A JR Z,zlinie ; wenn Zaehler x=0 oder LD BC,(xlinie) ; Zahler x=Liniendicke X, CP C ; dann -> Zaehler Y vermindern JR Z,zlinie XOR A ; sonst muss Zaehler Y=0 sein ADD HL,BC ; (Optimierung), Koord. korrigieren JR liniey ; Schleife noch mal ; zlinie:LD A,I ; Zaehler Y zurueckholen DEC A ; Zaehler vermindern DEC A INC HL ; Bildschirmkoordinate erhoehen INC HL JR liniey ; Schleife noch mal ; endx:POP AF ; Zaehler X und Koordinaten holen POP HL POP DE AND A JR Z,finish ; fertig, wenn Zaehler=0 DEC A ; sonst Zaehler vermindern DEC A INC DE ; Koordinate erhoehen INC DE JP liniex ; Schleife noch mal ; finish:POP DE ; Koordinaten auf der Matrix holen POP HL RET ; Zurueck zum Hauptprogramm ; ; universelle Scroll-Routine ; scroll:CP #01 ; Ein Parameter? JR NZ,ziel ; falls nicht, nur ein Mal scrollen LD A,(IX+0) ; sonst Zaehler mit scrlop:AND A ; Anzahl der Scrolls laden RET Z ; Fertig, wenn Zaehler=0 PUSH AF ; Zaehler merken LD B,#F5 frame:IN A,(C) ; Warten auf Frame fly back RRA JR NC,frame CALL ziel ; Scroller aufrufen POP AF DEC A ; Zaehler vermindern JR scrlop ; noch Mal ; ; eigentlicher Scroll ; ziel:LD DE,#C000 ; Adresse der oberen Bildschirmzeile quelle:LD HL,#C800 ; Adresse der Zeile darunter laenge:LD BC,#C750; Anzahl Zeilen und Breite einer Zeile DI ; Beschleunigung copy:PUSH BC ; alles merken PUSH DE PUSH HL LD B,#00 ; Anzahl Zeilen ausblenden LDIR ; Zeile umkopieren POP HL ; Register zurueck POP DE POP BC EX DE,HL CALL nexthl ; Naechste Zeile von DE EX DE,HL CALL nexthl ; Naechste Zeile von HL DJNZ copy ; Nochmal bis B=0 ; blanks:LD B,#01 ; Anzahl der aufzufuellenden Zeilen fill:LD H,D ; DE ein Byte rechts von HL LD L,E INC DE PUSH BC ; Register merken PUSH HL patter:LD (HL),#00 ; Erstes Byte mit Muster fuellen anzahl:LD BC,#004F ; Breite der restlichen Zeile in BC LDIR ; restliche Zeile fuellen POP HL ; Register holen POP BC CALL nexthl ; Naechste Zeile von HL EX DE,HL DJNZ fill ; Nochmal bis B=0 EI ; Interrupts wieder zulassen RET ; fertig ; ; Hilfsprogramm: Groesse des Scrolls patchen ; size:CP #06 ; Sechs Parameter? RET NZ ; -> Abbruch wenn nicht LD A,(IX+2) ; Scrollschritt muss >0 sein AND A RET Z LD A,(IX+6) ; Breite mindestens 2 CP 2 RET C ADD A,(IX+10) ; X+Breite hoechstens 80 CP 82 RET NC LD A,(IX+4) ; Hoehe mindestens 1 AND A RET Z ADD A,(IX+8) ; Y+Hoehe hoechstens 25 CP 27 RET NC LD A,(IX+8) ; Zaehler mit Y laden LD HL,#C000 ; Anfang des Bildschirms LD BC,#0050 ; Offset fuer 8 (Grafik-) Zeilen addy:DEC A ; Zur Startadresse so oft das Offset JR Z,addx ; dazuzaehlen, bis A=0 ADD HL,BC JR addy addx:LD D,A ; schliesslich noch X addieren LD E,(IX+10) DEC DE ADD HL,DE ; heraus kommt die Adresse der LD (ziel+1),HL ; Oberen Zeile LD A,(IX+2) ; Schittweit bei Anzahl der zu LD (blanks+1),A ; fuellenden Zeilen direkt eintragen, LD B,A PUSH BC ; aber vorerst merken addste:CALL nexthl ; Bildschirmadresse weiterrechnen DJNZ addste ; bis B=0 LD (quelle+1),HL ; dann als untere Zeile eintragen LD A,(IX+6) ; die Breite auch direkt eintragen LD (laenge+1),A DEC A ; zu fuellen ist aber 1 Byte weniger LD (anzahl+1),A LD A,(IX+4) ; Die Hoehe*8 abzueglich der Schritt- SLA A ; weite ergibt die Anzahl der Zeilen, SLA A ; die umkopiert werden muessen SLA A POP BC SUB B LD (laenge+2),A LD A,(IX+0) ; Das Muster direkt eintragen LD (patter+1),A RET ; Fertig! ; ; 16-Bit Multiplikation: HL = BC * DE ; mult:AND A ; Carry=0 LD HL,#0000 ; Ergebnis mit 0 ansetzen LD A,#10 ; 16 Bit zu Multiplizieren mult1:ADD HL,HL ; Ergebnis nach links rotieren RL E ; 1. Faktor nach links rotieren RL D JR NC,mult2 ; weiter, falls kein Uebertrag ADD HL,BC ; sonst 2. Faktor addieren JR NC,mult2 INC DE ; Ueberlauf vermerken mult2:DEC A ; noch mal, bis A=0 JR NZ,mult1 RET ; Fertig! ; ; Patch - Routine, um das "à" zu sparen ; unloc:LD A,E CP #0D ; Type mismatch ? RET NZ ; -> Nein LD HL,(error1) ; Aktuelle Statementadresse CALL error2 ; Blanks ueberlesen CP #7C ; RSX-Querstrich ? JR Z,unloc2 ; oder CP #83 ; CALL-Token ? RET NZ ; -> Nein unloc2:POP HL LD HL,(error3) ; "à" nachahmen CALL error4 SCF RET ; ; naechste Bildschirmzeile in HL ; nexthl:LD A,H ; Offset fuer eine Zeile (#800) ADD A,#08 ; addieren LD H,A RET NC SUB #40 ; falls Uebertrag, Offset fuer ganzen LD H,A ; Bildspeicher (#4000) subtrahieren LD A,L ; und Offset fuer 8 Zeilen (#50) ADD A,#50 ; addieren LD L,A RET NC INC H ; falls Uebertrag, H korrigieren RET ; Endgueltig fertig ; ; Vorzeichenwechsel in HL ; swaphl:PUSH DE ; DE retten XOR A ; Carry = 0 EX DE,HL LD HL,#0000 SBC HL,DE ; gewuenschte Zahl von 0 abziehen POP DE RET ; Fertig! |