Tips & Tricks für Anfänger und Profis
In der Rubrik Tips & Tricks können wir Ihnen diesmal einige Routinen anbieten, die sich besonders zum Einbau in eigene Programme eignen.
Screen-Dump
Eine Bildschirmmaske kann auf viele verschiedene Arten auf den Bildschirm gebracht werden. Die einfachste ist wohl:
FOR I = 0 T0 999 : POKE 1024 + I, PEEK (STADR + I) : NEXTI
wobei STADR die Startadresse der Maske ist. Doch das ist zu langsam und eintönig. Das gleiche Programm in Assembler ist zirka 200 mal schneller, aber immer noch eintönig.
Das Programm »Screen-Dump« (siehe Listing 1) hilft dem ab. Auf über 100 verschiedene Arten kann hiermit das oben genannte Programm ablaufen (das heißt 100 verschiedene Reihenfolgen), von denen einige verblüffen, fast alle aber besser »aussehen« als dieses Programm. Auch die verstellbare Geschwindigkeit ermöglicht interessante Veränderungen.
Die Handhabung ist denkbar einfach:
SYS 680, Art, Stadr., Geschwindigkeit
- Art: Eine Zahl zwischen 0 und 127
- Stadr: Die Startadresse der Maske geteilt durch 256 (Highbyte).
- Geschwindigkeit: zwischen 1 und 255 verstellbar.
Also SYS 680, 20, 64, 8 kopiert den Bereich von 16384 bis 17383 auf sehr originelle Weise in den Bildschirm.
Andere »schöne Versionen« sind:
Art | Geschw. | Art | Geschw. |
2 | 1 | 6 | 4 |
9 | 4 | 13 | 8 |
19 | 2 | 20 | 8 |
28 | 8 | 33 | 4 |
36 | 10 | 44 | 4 |
46 | 20 | 61 | 20 |
64 | 4 | 65 | 10 |
66 | 4 | 84 | 4 |
88 | 2 | 98 | 8 |
104 | 4 | 106 | 2 |
120 | 20 | 125 | 20 |
Funktionsweise
Wie funktioniert Screen-Dump, wo es doch nur 100 Byte lang ist? Am besten ist das an folgendem Beispiel zu erkennen: Wir nehmen eine Gruppe von zwölf Elementen. Wie greift man nun nacheinander auf alle zwölf Elemente zu, so daß keine Reihenfolge erkennbar wird? Ganz einfach:
Wir nehmen eine Zahl, die mit 12 keinen gemeinsamen Teiler hat, zum Beispiel 5. Jetzt beginnen wir bei 0 und zählen 5 hinzu. Diese Zahl nehmen wir heraus. Dann zählen wir wieder 5 hinzu. Ergebnis 10. Unser zweites Element. Dann wieder + 5 = 15. Element 15 ist nicht vorhanden, also ziehen wir die Gesamtanzahl der Elemente ab. 15—12=3 und so weiter. Es ergibt sich die Reihenfolge: 5 10 3 8 1 6 11 4 9 2 7 12. Augenscheinlich völlig wahllos. Es funktioniert immer, wenn folgende Voraussetzungen erfüllt sind:
- Die Additionszahl (hier: 5) muß kleiner sein als die Gesamtzahl der Menge.
- Die Additionszahl darf mit der Gesamtzahl keinen gemeinsamen Teiler haben.
Im Screen-Dump wird dieses System mit einer Menge von 1 024 Elementen angewandt. Die möglichen Additionszahlen sind somit alle ungeraden Zahlen zwischen 0 und 255.
(Michael Schmidt/tr)10 fori=659to763:readj:pokei,j:next:print"{wht}{clr}{down}sys 680,art,block,geschwindigkeit{lblu} 20 new 1000 data164,6,162,32,202,208,253,136,208,248,96,0,0,0,0,0,0,0,17,1,0,32,155 1001 data183,134,2,32,155,183,134,5,32,155,183,134,6,165,2,10,9,1,133,97,169 1002 data4,162,0,134,2,133,3,134,4,160,0,177,4,145,2,165,2,24,101,97,133,2 1003 data133,4,144,4,230,3,230,5,165,3,201,8,208,11,169,4,133,3,165,5,56,233 1004 data4,133,5,32,147,2,165,2,208,211,165,3,201,4,208,205,96
Pseudo-Interrupt
Diese Befehlserweiterung erlaubt es, ein Basic-Programm zu jedem beliebigen Zeitpunkt per Tastendruck durch die F1-Taste unterbrechen zu lassen. Es kann dann in eine vorher definierte Basic-Routine gesprungen werden. Diese könnte zum Beispiel den noch freien Speicherplatz oder die Uhrzeit anzeigen.
Das Programm (Listing 2) bitte mit dem MSE eingeben. Es liegt dann im Speicherbereich von 40499 bis 40768. Geladen wird es absolut mit LOAD "PSEUDO-IRQ",8,1. Da das Programm im Bereich für die Basic-Variablen steht, muß es durch POKE 56,158:CLR vor Überschreiben geschützt werden. Nach dem Start durch »SYS 40541« stehen die neuen Befehle zur Verfügung:
- !F1JUMP
legt fest, in welche Zeile im Falle einer Unterbrechung durch die F1-Taste gesprungen werden soll. Tritt der Befehl mehrmals auf, so gilt die zuletzt angegebene Zeilennummer. - !JBACK bewirkt die Fortsetzung des Basic-Programms ab der Stelle, an der unterbrochen wurde.
- !SF1 verhindert Unterbrechungen. Dies kann zum Beispiel beim Aufbau einer Grafik oder bei Arbeiten mit der Diskettenstation wichtig sein.
- !CF1 läßt gesperrte Unterbrechungen wieder zu.
PROGRAMM : PSEUDO-IRQ 9E01 9F41 ----------------------------------- 9E01 : FF 89 00 20 73 00 C9 21 6A 9E09 : D0 03 4C 6D 9E A5 CB C9 F5 9E11 : 40 D0 06 20 79 00 4C E7 D8 9E19 : A7 C9 04 F0 06 20 79 00 0B 9E21 : 4C E7 A7 A5 CB C9 40 D0 AD 9E29 : FA AD 01 9E F0 06 20 79 C1 9E31 : 00 4C E7 A7 18 A9 03 20 61 9E39 : FB A3 A5 7A 48 A5 7B 48 EF 9E41 : A5 39 48 A5 3A 48 A9 75 C1 9E49 : 48 8D 01 9E AD 02 9E 85 DC 9E51 : 14 AD 03 9E 85 15 20 A3 99 9E59 : A8 4C AE A7 A9 04 8D 08 C9 9E61 : 03 A9 9E 8D 09 03 A9 75 CC 9E69 : 8D 01 9E 60 20 73 00 C9 5C 9E71 : 46 F0 07 C9 4A F0 41 4C F4 9E79 : F1 9E 20 73 00 C9 31 D0 E5 9E81 : 34 20 73 00 C9 4A D0 2D 2F 9E89 : 20 73 00 C9 55 D0 26 20 51 9E91 : 73 00 C9 4D D0 1F 20 73 8E 9E99 : 00 C9 50 D0 18 20 73 00 FC 9EA1 : 20 6B A9 A5 14 8D 02 9E 89 9EA9 : A5 15 8D 03 9E A9 00 8D EF 9EB1 : 01 9E 4C AE A7 4C 08 AF 47 9EB9 : 20 73 00 C9 42 D0 F6 20 93 9EC1 : 73 00 C9 41 D0 EF 20 73 C3 9EC9 : 00 C9 43 D0 E8 20 73 00 F6 9ED1 : C9 4B D0 E1 68 C9 75 D0 FC 9ED9 : 59 68 85 3A 68 85 39 68 77 9EE1 : 85 7B 68 85 7A A9 00 8D FF 9EE9 : 01 9E 20 79 00 4C E7 A7 C2 9EF1 : C9 53 F0 07 C9 43 F0 1C 34 9EF9 : 4C 08 AF 20 73 00 C9 46 24 9F01 : D0 B3 20 73 00 C9 31 D0 D6 9F09 : AC A9 75 8D 01 9E 20 73 05 9F11 : 00 4C AE A7 20 73 00 C9 09 9F19 : 46 D0 9A 20 73 00 C9 31 33 9F21 : D0 93 A9 00 8D 01 9E 20 C1 9F29 : 73 00 4C AE A7 4A 42 41 DE 9F31 : 43 CB A9 2E 85 22 A9 9F D9 9F39 : 85 23 4C 47 A4 01 00 A5 E9
List-Schutz für Basic-Programme
Dieser List-Schutz ist für Nichteingeweihte sehr verblüffend. Die Grundidee dazu stammt aus dem Bericht »Disketten-Manipulationen« aus 64’er, Ausgabe 6/85. Er wurde jedoch etwas ausgebaut, so daß hier beim Listen alle Steuercodes aktiv werden. Dies wird dadurch erreicht, daß man in eine Speicherstelle vor den Codes die Zahl 141 schreibt. Um nun ein Programm zu schützen, lädt man es und gibt folgende zwei Zeilen ein:
1 poke2067,73:goto 10 2 rem"a{clr}{down}{down}{down}{yel}it is not allowed to list this program{blu}aa
Danach gibt man im Direktmodus POKE 2067,71 : POKE 2073,141 : POKE 2118,0 : POKE 2119,0 ein und speichert das Programm.
Listet man nun das Programm, so wird der Bildschirm gelöscht und der Text in der REM-Zeile ausgegeben. Durch das künstlich erzeugte Basic-Programm-Ende-Zeichen (drei Nullen) wird das Listen abgebrochen. Wird im Programm dann auch noch durch POKE 788,52 die RUN-STOP-, und durch POKE 792,193 die RESTORE-Taste ausgeschaltet, kann keiner mehr an das Programm. Aufheben läßt sich dieser List-Schutz nur mit einem Monitor und mit der Kenntnis der Funktionsweise des Schutzes.
(Thomas Uttendorfer/tr)Sichere INPUT-Routine in Basic
Ich habe bisher immer eine leistungsfähige INPUT-Routine in Basic vermißt. Das ging anscheinend nicht nur mir so, denn in einigen abgedruckten Programmen (zum Beispiel Ligatab, Listing des Monats, 3/85) fehlt eine solche Routine, was zu chaotischen Ergebnissen führen kann. (Wenn man zum Beispiel aus Versehen an Stelle der Shift-Taste die Crsr-Down-Taste gedrückt hat, so nützt es dem Anwender wenig, wenn er mit der Crsr-Up-Taste wieder in das Eingabefeld zurückkehrt, weil jetzt der INPUT-Befehl die ganze Zeile als Eingabe ansieht.) Deshalb hier eine INPUT-Routine, die folgende Vorteile hat:
- Da die Routine (Listing 3) in Basic geschrieben ist, ist sie für jeden Programmierer leicht verständlich und abänderbar,
- Der Programmierer kann beim Aufruf der Routine gleich Ort, mini- und maximale Länge und die zulässigen Zeichen der Eingabe festlegen.
- Jedes Zeichen wird gleich bei der Eingabe auf seine »Richtigkeit« überprüft.
- Es wird nur die tatsächliche Eingabe als Eingabe übernommen (und nicht noch eventuell Teile der Maske).
- Es funktionieren noch sämtliche Sonderfunktionstasten (inst, del, home, clr und so weiter).
- Der Anwender kann das Eingabefeld nicht verlassen.
- Die Routine ist mit 1,5 KByte relativ kurz.
Benutzung der Routine:
- Setzen des Parameterstrings
- Aufruf mit gosub 60000
- Übergabe von in$ an gewünschte Variable
Der Parameterstring:
Er setzt sich zusammen aus:
Stelle 1,2 | Zeile der Eingabe |
Stelle 3,4 | Spalte der Eingabe |
Stelle 5,6 | minimale Länge der Eingabe |
Stelle 7,8 | maximale Länge der Eingabe |
Stelle 9 | Code (siehe weiter unten) |
Es ist darauf zu achten, daß einstellige Angaben (zum Beispiel: 3. Zeile) mit 03 angegeben werden, da sonst keine klare Trennung der einzelnen Parameter vorgenommen werden kann.
Die Routine sieht Standardwerte für die minimale und maximale Länge und für den Code der Eingabe vor (Zeile 60200). Diese können natürlich frei nach eigenem Bedarf eingerichtet werden. Entspricht die geforderte Eingabe den Standardwerten, so braucht der Programmierer beim Setzen des Parameterstrings diese Werte nicht anzugeben, sondern nur noch Zeile und Spalte. Dies führt natürlich zu einer weiteren Vereinfachung (Beispiel: pa$ = "0510", das heißt Eingabe in Zeile 5 ab Spalte 10 mit den Standardwerten).
Code (c)
Der Code dient dazu, die eingegebenen Zeichen sofort zu überprüfen. Selbstverständlich kann auch er frei programmiert werden. In Zeile 60490 wird entsprechend dem Code in die Unterprogramme verzweigt. Dort wird die gedrückte Taste überprüft. Entspricht sie nicht dem Code, wird f1 auf 1 gesetzt.
In der vorliegenden Routine sind Code 1 bis 4 schon programmiert, wobei
- 1 bedeutet, daß nur Zahlen
- 2 bedeutet, daß nur Buchstaben
- 3 bedeutet, daß alles
- 4 bedeutet, daß nur Kleinbuchstaben
zulässig sind.
Diese Codes oder auch neue Codes können spielend leicht geändert oder neu programmiert werden.
Funktionen der Sondertasten:
CRSR UP,CRSR DOWN | sind abgeschaltet |
INST,DEL | funktionieren innerhalb des Eingabefensters wie gewohnt (Rest der Maske wird nicht berührt) |
HOME | springt an Anfang des Eingabefensters |
CLR | löscht Eingabefenster und springt an den Anfang desselben |
CRSR LEFT,RIGHT | funktionieren wie gewohnt, nur Eingabefeld kann nicht verlassen werden. |
Variablenliste | |
---|---|
pa$ | Parameterstring; dient der Übergabe der Parameter |
bl$ | String, der nur aus Spaces besteht |
in$ | Eingabe |
n$ | gedrückte Taste |
ze | Zeile für die Eingabe |
sp | Spalte, ab der die Eingabe erfolgen soll |
mi | minimale Länge der Eingabe |
ma | maximale Länge der Eingabe |
c | Code, welchem die Eingabe entsprechen muß |
ss | aktuelle Cursorspalte |
fl | Flag, ob zuletzt gedrückte Taste Code entsprach |
0 rem input (demo) 1 rem input-routine fur vc 64 2 rem 3 rem copyright by 4 rem karlheinz boss 5 rem sylvester-jordan-str. 11 6 rem 3550 marburg 7 rem 06421/13509 8 poke53281,09:poke53280,09:poke646,07 9 print chr$(14) 10 rem input-routine 20 rem 30 rem pa$ ist aufgebaut wie folgt: 40 rem pa$ = zespmimac wobei 50 rem ze = zeile 60 rem sp = spalte 70 rem mi = mindestlaenge 80 rem ma = maximale laenge 90 rem c = code wobei 100 rem 1 = nur zahlen 110 rem 2 = nur buchstaben 120 rem 3 = alles 125 rem 4 = nur kleinbuchst. 130 rem 5-6 = frei programmierbar 132 rem ( zeile 60490 ) 140 rem pa$ muss die zeile und spalte 150 rem beinhalten,der rest ist hin- 160 rem reichend.es werden dann die 170 rem standardparameter in zeile 180 rem 60200 angenommen 190 rem z.b. pa$="0510" 200 : 1000 print"{clr}"; 1010 print"{rvon} Input-Routine copyright by K.Boss {rvof}" 1020 print "Ueber get wird eine Input-Routine simu-" 1030 print "liert, wobei saemtliche Sonderfunktions-"; 1040 print "tasten (inst,del,home,clr,cr,cl) noch " 1050 print "funktionieren, man aber das Eingabefeld" 1060 print "nicht verlassen kann. Ausserdem kann man"; 1070 print "beim Aufruf der Routine gleich Ort, min."; 1080 print "und max. Laenge und die zulaessigen Zei-"; 1090 print "chen der Eingabe angeben." 1100 print "{rvon}{gry2} Beisp.: "; 1105 print " "; 1110 print "Datum (TTMMJJ) : {rght}{rght}{rght}{rght}{rght}{rght} "; 1120 print " "; 1130 print "Name : {rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght} "; 1140 print " "; 1150 print "Kuerzel (mind 2 kl. Buchst.) : {rght}{rght}{rght} "; 1160 print " "; 1170 print "Computer : {rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght}{rght} "; 1180 print " {rvof}{yel}"; 1900 rem hier nun die 4 aufrufe aus 1910 rem vorangegangen beispiel 1920 rem 2000 pa$="121806061":gosub60000:a$=in$ 2010 pa$="140800202":gosub60000:b$=in$ 2020 pa$="163202034":gosub60000:c$=in$ 2030 pa$="1812":gosub60000:d$=in$ 2040 rem 2100 rem das war's 2110 rem 2120 rem ps: die reine input-routine 2130 rem in kompr. form heisst 2140 rem input (kurz) 3000 print:print "Die Eingaben waren : ";a$ 3010 print b$ 3020 print c$ 3030 print d$ 3040 print " {rvon} Taste druecken {rvof}"; 3050 get nj$ : if nj$="" then 3050 3995 print"{clr}" 4000 poke 211,0:poke 214,24:sys58640 4010 print"list1900-2140 " 4015 print"{home}" 4020 list30-190 29999 end 30000 : 31000 : 32000 : 33000 : 34000 : 60000 bl$=" " 60010 in$="" 60099 : 60100 ze=val(mid$(pa$,1,2)) 60110 sp=val(mid$(pa$,3,2)) 60120 if len(pa$)=4 then 60200 60130 mi=val(mid$(pa$,5,2)) 60140 ma=val(mid$(pa$,7,2)) 60150 co=val(mid$(pa$,9,1)) 60160 goto 60300 60190 rem****************************** 60200 mi=0:ma=15:co=3 60210 rem****************************** 60220 : 60300 gosub 60950 60310 poke 204,0 60320 get n$ : if n$="" then 60320 60330 ss=peek(211) 60340 if asc(n$)=13 and len(in$)>=mi then poke 204,1 : gosub 63890:return 60350 if asc(n$)=147 then gosub 61000 : goto 60320 60360 if asc(n$)=19 then gosub 63890 : gosub 60950:goto 60320 60370 if asc(n$)=20 and peek(211)>sp then gosub 61410 : goto 60320 60380 if asc(n$)=157 then gosub 61310:goto 60320 60390 if asc(n$)=148 and len(in$)<ma then gosub 61505:goto 60320 60400 if asc(n$)=29 then gosub 61210:goto 60320 60410 if asc(n$)=17 or asc(n$)=145 then 60320 60420 if asc(n$)=148 or asc(n$)=20 or asc(n$)=13 then goto 60320 60430 : 60485 fl=0 60490 on co gosub 63900,63910,63920,63930,63940,63950 60495 if fl=1 goto 60320 60500 : 60505 if len(in$)=ss-sp then in$=in$+n$:goto 60515 60510 in$=left$(in$,ss-sp)+n$+mid$(in$,ss-sp+2,len(in$)-ss+sp-1) 60515 print n$; 60520 if ss=sp+ma-1 then print chr$(157); 60530 goto 60320 60901 : 60902 : 60903 : 60950 poke211,sp:poke214,ze:sys58640:return 60999 : 61000 gosub 60950 61010 print left$(bl$,ma); 61020 gosub 60950 61030 in$="" 61040 return 61099 : 61210 if ss<sp+len(in$)and ss<sp+ma-1then ss=ss+1 61220 gosub 63890 61230 poke 211,ss:sys58640 61240 return 61250 : 61310 if ss>sp then ss=ss-1 61320 gosub 63890 61330 poke 211,ss : sys 58640 61340 return 61350 : 61410 in$=left$(in$,ss-sp-1)+mid$(in$,ss-sp+1,len(in$)-ss+sp) 61420 gosub 63890 61425 if len(in$)<ma-1 then print" "; 61430 poke 211,ss-1 : sys 58640 61440 return 61490 : 61505 if ss=sp+len(in$) then goto 61540 61510 in$=left$(in$,ss-sp)+" "+mid$(in$,ss-sp+1,len(in$)-ss+sp) 61520 gosub 63890 61530 poke 211,ss : sys 58640 61540 return 61590 : 63890 gosub 60950 63892 print in$;:if len(in$)<ma then print " "; 63898 return 63899 : 63900 if asc(n$)<48orasc(n$)>57 then fl=1 63909 return 63910 if asc(n$)=32 then return 63911 if(asc(n$)<65orasc(n$)>90)and(asc(n$)<193orasc(n$)>218) then fl=1 63919 return 63920 rem 63929 return 63930 if asc(n$)=32 then return 63931 if(asc(n$)<65orasc(n$)>90) then fl=1 63939 return 63940 rem 63949 return 63950 rem 63959 return
Synthetische Melodien
Das wahrscheinlich kürzeste und erstaunlichste Musiksynthesizer-Sequencer-Programm, das je veröffentlicht wurde. Es handelt sich um ein 47 Byte langes Assemblerprogramm, das im Listing 4, in Form eines DATA-Laders vorliegt. Die Melodie und die Klangfarbe kann man über die Speicherstellen 1022 und 1023 einstellen. Dabei kommt es allerdings nur auf die Differenz der beiden Byte an. Es empfiehlt sich also, die Speicherstelle 1022 mit 0 zu belegen und für 1023 alle Werte von 0 bis 128 auszuprobieren.
Melodische Tonfolgen erreicht man mit POKE 1023,7 + 8*n, wobei n eine ganze Zahl zwischen 0 und 16 sein darf. Effektvolle Klänge erreicht man zum Beispiel über folgende Werte (POKE 1023,…): 11, 28, 62, 96, 130.
Funktionsweise
Zuerst werden Kurven- und Wellenform festgelegt. Die beiden Speicherinhalte von 1022 und 1023 werden erhöht beziehungsweise erniedrigt. Dann werden sie miteinander durch die AND-Funktion verknüpft. Das Ergebnis kommt ins High-Byte des Tonhöhenregisters. Eine kleine Warteschleife macht die Komposition hörbar.
(Wolfgang Horak/tr)10 poke1022,0 20 input"parameter";a:poke1023,a 30 fort=0to46:readq:poket+832,q:next 40 sys832 50 data169,15,141,24,212,141,5,212,169,112,141,6,212,169,17,141,4,212,238 60 data255,3,206,254,3,162,0,16,0,200,208,253,232,224,7,208,246,173,255 70 data3,45,254,3,141,1,212,176,227
Die Super-POKEs
POKE 792,226: POKE 793,252
Sobald die RESTORE-Taste gedrückt wird, wird ein Reset ausgelöst.
POKE 774,226: POKE 775,252
Sobald der LIST-Befehl eingetippt wird, wird ein Reset ausgelöst.
POKE 818,226: POKE 819,252
Sobald der SAVE-Befehl eingetippt wird, wird ein RESET ausgelöst.
(tr)Tips & Tricks — Mischmasch
Und hier noch ein paar Kleinigkeiten für die Tips & Tricks-Sammlung:
- Neustart eines Basic-Programms nach Drücken von RUN-STOP-RESTORE:
1 DATA 169, 49, 141, 20, 3, 76, 113, 168 2 FOR I=700 T0 707: READ A: POKE I,A: NEXT 3 POKE 770,188: POKE 771,2
Einzige Bedingung ist, daß Ihr Programm eine Zeile 0 enthält, da der Interpreter einen RUN 0-Befehl ausführt.
- Nachladen von Datasette mit Autostart:
POKE 56335,2
Dem Betriebssystem wird vorgegaukelt, daß SHIFT-RUN-STOP gedrückt wäre.
- Nützliche SYS-Adressen:
- 43121: entspricht dem Befehl RUN 0
- 42039: Ausgabe von Fehlermeldungen. Im X-Register des Prozessors muß die Fehlernummer stehen (Speicherstelle Nummer 781).
- 64763: RESET, ohne Initialisierung der Vektoren (IRQ etc.).