Falls auch BASIC Imperator Forum64 Zeit hat und sich die Mühe macht lerne ich gerne wieder von seiner Weisheit.
Ach Leute hört doch mal auf zu lästern. Der Arme hat hier keine Freunde, nichtmal Ace der ja sonst jeden (auch mich) nimmt. ![]()
Es gibt 66 Antworten in diesem Thema, welches 11.223 mal aufgerufen wurde. Der letzte Beitrag (
Falls auch BASIC Imperator Forum64 Zeit hat und sich die Mühe macht lerne ich gerne wieder von seiner Weisheit.
Ach Leute hört doch mal auf zu lästern. Der Arme hat hier keine Freunde, nichtmal Ace der ja sonst jeden (auch mich) nimmt. ![]()
Im BASIC-Code selber vermeide ich "Einrückungs"-Doppelpunkte, weil sie die Ausführung durch den Interpreter verlangsamen.
Absolut ok, das war auch eher ein BIF-Scherz...
Im Prinzip ist es recht einfach: der aktuelle DATA-Zeiger steht in den Speicherzellen 63-66. Man braucht nur beim ersten READ-Durchgang an interessanten Stellen die dortigen Werte zu speichern und sie bei Bedarf wieder zurückzuschreiben. Wahrscheinlich reicht in der Praxis sogar der Zeiger in 65/66 aus, in 63/64 steht nur die aktuelle Zeilennummer- die wird aber nur für allfällige Fehlermeldungen gebraucht.
Cool. Das wusste ich nicht. Ich hab nur gesehen es gibt keinen BASIC V2 Befehl, der diesen Zeiger anfasst.
Wenn man weiß wo der überhaupt ist, sieht die Sache wieder anders aus.
@ mc71
Ich habe nach Auslesen der Sprite-Daten in den Quelltext eingesetzt:
d1=peek(63)
d2=peek(64)
d3=peek(65)
d4=peek(66)
Denn hier fängt der "Scrolltext" an.
Wenn der DATA-Bereich zuende ist, springt das Pogramm eigentlich ganz an den Anfang und initialisiert vorher alle relevanten Variablen und resettet den DATA-Zeiger per Restore-Befehl.
Stattdessen initialisiere ich die relevanten Variablen und schreibe statt Restore
poke 63,d1
poke 64,d2
poke 65,d3
poke 66,d4
Und lasse dann nicht an den Anfang springen, sondern an den Beginn der Sprite-Abfrage. Das soll eine flüssige Dauer-Wiederholung bewirken ohne ruckeln und Neuzeichnen der "Rasterbars" durch den Komplett-Neustart bei DATA-Ende.
Ich bekomme aber eine "Out of Data" Meldung sobald sich das Programm an den "umgestellten" DATA-Zeigern bedienen soll.
Sind die Adressen 63-66 wirklich die richtigen? Wenn ja liegt es an mir und ich muss nochmal in den Code gucken.
Edit:
Oder aber das Programm verändert sich dynamisch im Speicher während der Ausführung und das Beschreiben mit den alten Zeiger-Adressen führt ins Leere weil da gar kein DATA-Bereich mehr ist (?!). Ein V3.5/V7 Basic-Befehl mit dem man den Zeiger beeinflussen kann, fängt diese "Dynamik" womöglich ab. Ist aber alles Spekulation meinerseits vielleicht hab ich auch nur Tomaten auf den Augen.
Zitat von BytebreakerIch bekomme [...] eine "Out of Data" Meldung sobald sich das Programm an den "umgestellten" DATA-Zeigern bedienen soll.
Sind die Adressen 63-66 wirklich die richtigen? Wenn ja liegt es an mir und ich muss nochmal in den Code gucken.
Ich hab' das gerade mal mit einem Minimal-Programm ausprobiert und es funktioniert.
ZitatOder aber das Programm verändert sich dynamisch im Speicher [...]
Das kannst Du ruhigen Gewissens ausschließen. Weder ändert der der Interpreter beim Programmlauf irgendetwas am (tokenisierten) Programmcode noch 'schaufelt' er etwa Programmzeilen wild durch die Gegend. Nur nach einem LOAD werden eventuell die Linkzeiger korrigiert, wenn das Programm an eine andere BASIC-Startadresse geladen wird, als von wo es gespeichert wurde.
Ich tippe eher mal darauf, daß Du zwischendrin aus Versehen D1..D4 noch für was anderes verwendest. ![]()
So geht's scheinbar:
Die Adressen 65/66 müssen nach dem allerersten READ gespeichert werden (davor geht's noch nicht).
Am besten als ersten DATA-Wert einen Dummy nehmen. Dann kann man das z. B. vor einer Schleife mit einem einzelnen READ X:Y=PEEK(65):Z=PEEK(66) machen und später damit wieder auf den echten Beginn der DATAs setzen (Dummy wird übersprungen). So könnte man dann auch noch weitere Einsprünge in den DATAs setzen.
Vielleicht geht's aber ja auch noch anders/besser.
Jetzt ist mir biffig... ![]()
Zitat von HexworxJetzt ist mir biffig...
Ja, echt. Wenn man ihn mal brauchen könnte, muß man doch alles selber machen... ![]()
10 FORT=0TO19:READA:POKE679+T,A:NEXT:POKE785,167:POKE786,2:GOTO17
11 DATA 32,247,183,32,19,166,144,7,164,95,165,96,76,145,179,162,17,76,55,164
12 :
13 REM ** RESTORE LI
14 AD=USR(LI)-1:POKE64,LI/256:POKE63,LI-256*PEEK(64)
15 POKE66,AD/256:POKE65,AD-256*PEEK(66):RETURN
16 :
17 LI=22:GOSUB14:READA$:PRINTA$;
18 LI=21:GOSUB14:READA$:PRINTA$
19 END
20 :
21 DATA"WORLD."
22 DATA"HELLO, "
Alles anzeigen
Das kleine Hilfsprogramm in Maschinensprache ermittelt die Adresse einer Zeile, deren Nummer als Argument in einer USR()-Funktion angegeben wird. Mit der Zeilennummer und der Adresse der Zeile werden dann die Werte in 63..66 gesetzt. Existiert die Zeile nicht, so gibt's einen ?UNDEF'D STATEMENT ERROR (leider ist die dort angegebene Zeilennummer zur Fehlersuche nicht brauchbar, wenn man RESTORE in das Unterprogramm packt ...):
@ Mike, Hexworx
Gröl! Ihr hattet recht!
Es geht um die richtigen Zeitpunkte wann man peekt und poked. Wenn ich gleich nach dem Sprite-Read peeke klappt es.
Bitte findet die korrekte PRG im Anhang. Mit Alt-W könnt ihr in VICE vorspulen bis zu dem Moment wo die blaue Schrift gleich verschwindet. Ab dann sieht man den flüssigen Übergang. Endlosschleife gelungen, Basic V2 überlistet.
![]()
![]()
@ Mike
Ähm, was ist denn der bevorzugte Weg, Assembler-Code zu verarbeiten? Prg-Dateien mit CBM Prg Studio generieren? Oder einen C64 Assembler nehmen wie TurboAssembler? Wie machen die Leute das außerdem, dass wenn man LIST eintippt, eine SYS-Anweisung steht mit einer Sprung-Adresse auf den Maschinencode?
Wollte nicht zu sehr OT werden und bin da thematisch auch noch gar nicht. Es war nur weil ich nicht weiß, wie ich den Assembler Code von Dir überhaupt benutzen kann.
Hi, Bytebreaker,
der Assemblercode in Post Bitte melde dich an, um diesen Link zu sehen. dient nur zur Doku. Er steht bereits komplett ausführbar in dem BASIC-Programm in der ersten DATA-Zeile drin, wird von da aus in den Speicher geschrieben und der Vektor von USR() geändert, so daß USR() auf diese Hilfsroutine verweist.
Für so eine kleine Routine geht sich noch ein Direktassembler (hier: der Monitor in VICE) aus.
Ein größeres Maschinenprogramm schreibt man sinnvollerweise in einem symbolischen (Cross-)Assembler der das Ergebnis dann als Datei ablegt, und wenn man diese von einem BASIC-Programm aus verwenden will, gibt's auch Methoden diese Datei in einen (geschützten) Bereich nachzuladen, kurz nachdem man das (BASIC-)Hauptprogramm gestartet hat.
Zitat von ByteBreakerWie machen die Leute das außerdem, dass wenn man LIST eintippt, eine SYS-Anweisung steht mit einer Sprung-Adresse auf den Maschinencode?
Da steht am Anfang tatsächlich dieses kurze BASIC-Programm im Speicher. Man schaut sich an, wie das ab $0801 aussieht (es endet irgendwann mit 3 Nullen) kopiert das mit .BYTE-Direktiven (oder so wie's der jeweilige Assembler unterstützt) in den Quellcode und schreibt direkt dahinter das Maschinenprogramm.
Weiteres dann gern in der Assemblerrubrik. ![]()
Man muß nicht immer mit Datas arbeiten. Wenn man Strings ausgibt, dann kann man auch mit Strings arbeiten.
Hier noch einmal die Funktion zur Ermittlung der Stringadresse.
Das heißt praktisch, daß man alle Stringzeichen nun mit peek lesen kann.
5 :a$="hallo, wie geht es euch"
10 :a=peek(34+(a$<""))+peek(35+(a$<""))*256
11 :printpeek(a),chr$(peek(a))
Natürlich läßt sich der Ausdruck auch in eine Funktion packen.
Schönen Gruß.
und unpraktisch heißt das dann, dass man jedes einzelne Zeichen eines Strings umständlich durch den gesamten Interpreteroverhead jagt, anstatt das auf ML-Ebene von den entsprechenden Routinen erledigen zu lassen ![]()
Mit PEEK/POKE kann man bestimmt auch ganz toll auf den Fließkomma-Akkumulator zugreifen. ![]()
[offtopic]
Schönen Gruß
Er kam, um durch Doppelpunkte sie zu knechten. Und obsiegte durch Obskurität in einem Kampf, der Kontrahenten vermissen ließ...[/offtopic]
Hier noch einmal die Funktion zur Ermittlung der Stringadresse.
Zugegebenerweise ein witziges Stück Code.
Aber um dann statt mit MID$ & Co. (GBC-Vermeidung?) den Kram zu lesen und zu POKEn (und ggf. noch Steuerzeichen zu filtern und umzufriemeln) hilft es nicht wirklich weiter. Jedes Zeichen mit PEEK holen und über CHR$ printen? Hmm... könnte etwas lahm werden... ![]()
Mir fällt jetzt jedenfalls keine sinnvolle Verwendung ein... ![]()
Er kam, um durch Doppelpunkte sie zu knechten. Und obsiegte durch Obskurität in einem Kampf, der Kontrahenten vermissen ließ...
Mich erinnert er eher an Bitte melde dich an, um diesen Link zu sehen..
10 POKE45,0:POKE46,64:CLR:PRINT"{CLR}";
11 A$="EINE VIERZIG ZEICHEN LANGE ZEICHENKETTE.":A=16387
12 P=8192
13 READN$:IFN$=""THEN17
14 POKEP,ASC(N$):P=P+1
15 N$=MID$(N$,2)
16 ON-(N$="")GOTO13:GOTO14
17 FORT=0TO38:POKEP+T,PEEK(8192+T):NEXT
18 FORT=8192TOP-1
19 POKEA+1,T/256:POKEA,T-256*PEEK(A+1)
20 PRINT"{HOME}"A$
21 NEXT:GOTO18
22 :
23 DATA "FUER EINEN KURZEN SCROLLER KOENNTE MAN NATUERLICH AUCH EINFACH "
24 DATA "MIT MID$(...,N,40) ARBEITEN. FALLS DER TEXT LAENGER ALS 255 ZEICHEN "
25 DATA "IST, KOENNTE MAN Z.B. DIE HIER VERWENDETE METHODE EINSETZEN: MAN "
26 DATA "KOPIERT DEN TEXT AUS DATAZEILEN IN EINEN GESCHUETZTEN BEREICH "
27 DATA "ZWISCHEN PROGRAMM UND VARIABLEN. WEITERHIN NIMMT MAN EINE VIERZIG "
28 DATA "ZEICHEN LANGE ZEICHENKETTE UND BIEGT DEREN POINTER EINFACH AUF DEN "
29 DATA "TEXT DES SCROLLERS AB (UND ERSCHLAEGT DABEI ZUGLEICH DAS "
30 DATA "MID$(...,40)). ZUM SCHLUSS MUSS MAN NUR NOCH DIE ERSTEN 39 ZEICHEN "
31 DATA "HINTENDRAN HAENGEN (SIEHE ZEILE 17), DAMIT DIE LAUFSCHRIFT AUCH "
32 DATA "SAUBER LOOPT, WIE HIER Z.B. MIT GENAU EINEM LEERZEICHEN HINTER DEM "
33 DATA "PUNKT. ",""
Alles anzeigen
Das Ganze geht auch ohne gepiekse und gepokse (der Einfachheit halber habe ich den Text unverändert gelassen, auch wenn er jetzt keinen Sinn mehr ergiebt). Dazu habe ich den ganzen Text in ein Array (N$(N)) geladen; das Scrollen überlasse ich dem {DEL} Steuerzeichen = CHR$(20); da das Ganze zu schnell läuft, gibt es jetzt eine Bremse in Zeile 18:
10 print"{clr}";:s$=chr$(29)+chr$(20)
11 a$="":dim n$(999):n=0
13 readn$:ifn$=""then17
14 fori=1tolen(n$)
15 n$(n)=mid$(n$,i,1):n=n+1
16 next:goto13
17 j=0:k=0:kk=0
18 forx=0to55:nextx:rem slow down
19 print"{home}"left$(s$,kk)spc(k)n$(j):ifk=39thenkk=2
20 k=k-(k<39):j=j+1:ifj=>nthenj=0
21 goto18
22 :
23 data "fuer einen kurzen scroller koennte man natuerlich auch einfach "
24 data "mit mid$(...,n,40) arbeiten. falls der text laenger als 255 zeichen "
25 data "ist, koennte man z.b. die hier verwendete methode einsetzen: man "
26 data "kopiert den text aus datazeilen in einen geschuetzten bereich "
27 data "zwischen programm und variablen. weiterhin nimmt man eine vierzig "
28 data "zeichen lange zeichenkette und biegt deren pointer einfach auf den "
29 data "text des scrollers ab (und erschlaegt dabei zugleich das "
30 data "mid$(...,40)). zum schluss muss man nur noch die ersten 39 zeichen "
31 data "hintendran haengen (siehe zeile 17), damit die laufschrift auch "
32 data "sauber loopt, wie hier z.b. mit genau einem leerzeichen hinter dem "
33 data "punkt. ",""
Alles anzeigen
@ BIF:
Danke für die info mit der String-Adresse.
Wozu aber die Wahr/Falsch-Abfrage ob a$>"", d.h. ob a$ nicht leer ist? Wenn es nicht der Fall ist, wird 0 hinzuaddiert und es passiert nichts. Wenn a$ aber leer ist, werden durch Subtraktion (-1) Hi-Byte und Low-Byte des String-Zeigers verändert und damit die Adresse, die wir bisher für den String Zeiger gehalten haben. Das bisherige Low byte wird zum Hi Byte und das neue Low Byte ist in Adresse 33 - gehört also gar nicht zum String-Zeiger, den Du als 34 und 35 beziffert hast. Nix verstehn. Help. ![]()
![]()
@ Mike:
Das ist ja geil. Klartext mit mehreren $DATAs. Hexworx' Ansatz fand ich zwar gut, ich hätte aber nur an String Variablen gedacht die ich irgendwie hätte durchnudeln müssen und nicht an $DATAs, was ja natürlich geht, ich aber vor lauter CHR$ nicht mehr im Kopf hatte. Die Routine braucht viel Initalisierungszeit durchs Kopieren in den geschützen Bereich und ist dann sehr schnell. Meine Routine rennt von Anfang an (Zwei Zeilen voller Leerzeichen am anfang sorgen für Verzögerung und die Sprite-Abfrage verlangsamt den Scroller zusätzlich für bessere Lesbarkeit), dafür kriegt man Augenkrebs bei der manuellen Erstellung der CHR$-Datas.
Ich versteh schon warum am Ende alle Assembler lernen..
Trotzdem sehr geil. Danke, viel gelernt.
@ WTE
Dem "Typer-Effekt" am Anfang der Scrollroutine beuge ich vor durch vorheriges Einschieben von Leerzeichen in den Scrolltext. Dann wirkt es optisch so als würde der Text wirklich rechts rein und links rauslaufen. Ich habe denselben Effekt auch in meinem Code.