Hallo Besucher, der Thread wurde 54k mal aufgerufen und enthält 88 Antworten

letzter Beitrag von BastetFurry am

Basic-Scrollings

  • Gestern gabs ganz schön viel Stuff zu lernen! Daher werde ich heute den Kurs etwas kürzer gestalten, es soll nicht gleich zu einem Brain-Overkill kommen. Sicher gibt es noch einige Code-Brocken von gestern zu verdauen.


    Aber erstmal schnell zur Auflösung der gestriegen Aufgabe. Neefi und Pohli lagen mit ihrer Umsetzung zu 100% richtig! Applaus!


    Hier nochmal das ganze:
    * = 4096


    LDA # 1
    LDX # 0
    loop STA 1024,X
    INX
    CPX #40
    BNE loop
    RTS


    Die sache ist also erledigt! Wenden wir uns neuen Aufregenden 6502 Befehlen zu.


    Für unsere geplante Scrollroutine, fehlen noch drei Befehle, die ich heute zum erlernen Anbiete. Der erste ist sehr leicht zu Handhaben. Es handelt sich dabei um den "JMP". Das Kürzel bedeutet soviel wie: "JUMP". Man kann es schon erraten, das es sich hier im einen Sprungbefehl handelt, der IMMER springt, egal wie die Flags gesetzt oder gelöscht sind. Wenn man ihn mit einem Basic Befehl vergleichen möchte, zieht man dazu das GOTO heran! Die Funktion ist identisch.
    Testen wir das doch schonmal aus:


    * = 4096


    LDX #0 ;in X eine 0, um mit farbe schwarz zu starten.
    loop STX 53280 ;den Wert in X als Rahmenfarbe nutzen
    INX ;X um 1 erhöhen.
    JMP loop ;Und nach "loop" springen.


    Nachdem die kleine Routine gestartet wurde, staunt man über einen kunterbunten Rahmen. Unser Programm hat dummerweise keine Abbruchbedingung, und ist in einer Endlosschleife gefangen. Trotzdem können wir es abbrechen, zwar nicht mit Run/Stop allein, aber mit Run/Stop + Restore. Falls der Turbo Ass vorher aktiviert war, reicht auch ein druck auf Restore, und wir sind wieder im Editor. Der JMP Befehl ist so Kinderleicht, das er keine weiteren Erklärungen benötigt.


    Fackeln wir nicht lange und gehen zum nächsten Befehl über. In dem gerade vorrangegeangenem Beispiel, zählen wir mit hilfe des X Registers, die Adresse 53280 (Rahmenfarbe) in jedem Durchlauf im einen Wert nach oben. Das können wir auch etwas kürzen, in dem wir wiedermal einen neuen Befehl lernen. Es ist möglich, Speicherzellen im Ram, direkt um 1 zu erhöhen, ohne den Akku, X-Reg oder Y-Reg zu benutzen. Ich spreche von dem Befehl "INC". Das Kürzel steht einfach für "INCREMENT", also Erhöhe! Das kennen wir doch schon irgendwoher? Genau! Das hatten wir gestern bei dem "INX" & "INY". Der unterschied ist, das man hinter dem INC, einfach die Speicherzelle angibt, die erhöht werden soll, welches bei INX & INY nicht möglich ist, da diese sich nur auf das X & Y Register auswirken.
    Schreiben wir doch mal das kleine Programm von vorhin um.


    * = 4096


    loop inc 53280 ; erhöhen 53280 um 1
    jmp loop ; springe zurück zum label: loop


    Wie man sieht, erscheinen wieder viele bunte Rahmenfarben. Also tut sich etwas in der Adresse 53280, aber erhöht sich der Wert wirklich immer um 1? Testen wirs doch mal anders. Daher schlage ich dieses kleine Programm vor, das die Funktion, für das Auge verfolgbar, demonstriert.


    * = 4096


    inc 1024 ;erhöhe 1024 im 1
    rts


    Nun startet das ganze einmal. Es erscheint oben links im Textschirm ein "!" Ausrufezeichen. Gehen wir diesmal nicht gleich wieder in den Turbo Assembler zurück, sondern tippern schnell ein SYS 64738 ein. Dieser eben genannte SYS bewirkt einen Softreset, aber keine Angst, unser Source und das assemblierte Programm, sind immer noch im Speicher. Diesen Reset machen wir nur zur Absturzvorbeugung des Basicinterpreters. Durch den Reset, bekommen wir wieder eine 100%tig lauffähige Basic Console. Der Turbo Assembler verändert einige Zeropageadressen (das sind die, die von $0000 bis $00ff gehen), die der Basicinterpreter zum normalen Arbeiten benutzt. Da diese Werte verändert worden sind, kann es passieren, das ein normaler PRINT Befehl schon einen Absturz verursacht. Daher Resetten wir (ein Resetschalter tuts auch), und tippen in die dritte Text Zeile:


    SYS 4096 : PRINT PEEK(1024)


    ...Und drücken Return
    Wie wir sehen, erscheint wieder ein "!" Zeichen, und der Peek teilt uns mit, das in der Adresse 1024 jetzt der Wert 33 gespeichert ist. Fahren wir mit den Cursor nochmals auf die Höhe unserer Basic Zeile, und drücken wieder Return. Diesmal bekommen wir ein >"< Anführungszeichen zu sehen, mit dem gepeekten Wert von 34.
    Der INC Befehl macht also genau das, wie wir es erwartet haben. Mit einen SYS 36864 landen wir im Turbo Ass und sehen unseren Source Code.
    Denken wir mal weiter. Was passiert, wenn wir so oft die Basic Zeile gestartet hätten, bis wir uns auf den Wert 255 genähert hätten? Bei der nächsten Wiederholung, würde die 256 ins Haus stehen, doch die passt nicht mehr in eine 8 Bit breite Speicherzelle! Bekommen wir einen Illegal Quantity Error zu sehen? Nein, natürlich nicht, denn die Zelle fällt zurück auf den Wert 0. Genauso verhält es sich auch mit INX & INY. Das Witzige ist nun, wenn die Werte vom 255 auf 0 zurückfallen, wird in diesem Moment, auch die ZERO Fahne gehoben, ganz ohne einen Compare Befehl zu benutzen. Der nächste INC Befehl, der von 0 auf 1 weiter hochzählt, löscht das ZERO flag wieder. Dies sei aber nur am Rande erwähnt. Da wir gerade so schön beim hochzählen sind, warum zählen wir dann nicht auch mal herunter? Es gibt natürlich auch die umgekehrte Methode:


    INX - Increment X (überschlägt sich X von 255 auf 0, dann ZERO Flag = gesetzt)
    DEX - Decrement X (überschlägt sich X von 1 auf 0, dann ZERO Flag = gesetzt)


    INY - Increment Y (... nur mit Y)
    DEY - Decrement Y (... nur mit Y)


    INC - Increment Speicherzelle (...nur mit einer Speicherzelle)
    DEC - Decrement Speicherzelle (...nur mit einer Speicherzelle)


    Aber das Wissen, über die ganzen DEX, DEY & DEC´s, sowie das diese auch Flags setzen können, brauchen wir für unsere Scrollroutine nicht. Es kann aber nicht schaden, davon schonmal etwas erfahren zu haben.



    Uns fehlt jetzt nur noch EIN (!!!) einziger Befehl, um eine anständige Scrollroutine zu schreiben. Um genau zu sein, der AND Befehl. Mit jenem welchem ist es möglich, einzelne Bits in einem Byte zu löschen! Hört sich schwierig an, oder? Ist aber nicht so dramatisch. Fragen wir uns doch erstmal, warum in eine Speicherzelle gerade dieser dumme Wert 255, die Höchstgrenze ist. Eine Runde Zahl wäre doch viel schöner gewesen. Nun das ganze stark mit den BITS zusammen. Wir wissen auch als Basic Coder, das 1 Byte ganze 8Bits enthält. Nicht mehr, nicht weniger! Jedes BIT in einem Byte, hat einen genau festgelegten Wert, der immer gleich ist. Schauen wir uns die Wertigkeit der 8 BITs mal an.


    BIT 0 = Wert 1
    BIT 1 = Wert +2
    BIT 2 = Wert +4
    BIT 3 = Wert +8
    BIT 4 = Wert +16
    BIT 5 = Wert +32
    BIT 6 = Wert +64
    BIT 7 = Wert +128
    -----------------
    1 BYTE = #255


    Es sieht so aus, als steckt da ein System hinter. Die Wertigkeit von BIT 0 bis zu BIT 7, steigt immer in Zweierpotenzen auf. Rechnen wir schnell mit einem Taschenrechner: 1+2+4+8+16+32+64+128 ! Unser Ergebniss ist eine 255. So ergibt sich diese Zahl. Wir haben also ein Byte ausgerechnet, in dem alle BITs gesetzt sind, um den maximal mit 8BIT erreichbaren Wert zu bekommen.


    Ich weiß es ist ein ätzender und trockener Stoff, aber da müssen wir schnell durch. Diesmal nehmen wir ein Byte, in dem nicht alle BITs gesetzt sind.
    Mein Beispiel-Byte sieht folgendermassen aus.


    7 6 5 4 3 2 1 0 : Die 8 Bits von rechts nach links (!!!)
    0 1 0 0 1 1 0 1 : Ist das Bit gesetzt=1 (addieren wir es) gelöscht=0, lassen wir es aus.


    Schauen wir uns BIT0 an. Das BIT ist gesetzt und hat eine Wertigkeit von 1. Das merken wir uns!
    BIT 1 gelöscht- also Ignorieren wir es
    BIT 2 gesetzt - Wertigkeit von 4, die wir zu unserer 1 dazu addieren = 5
    BIT 3 gesetzt - Wertigkeit von 8. Die addieren wir auf unsere 5 = 13
    BIT 4 gelöscht - wieder Ignorieren
    BIT 5 gelöscht - wieder Ignorieren
    BIT 6 Wertigkeit von 64. Die addieren wir auf unsere 13 = 77
    BIT 7 gelöscht - wieder Ignorieren


    Unser Byte, hat bei diesen gesetzten BITs, eine Wertigkeit von insgesamt 77 ! Was wir jetzt hier gemacht haben, ist schlicht und einfach eine Umwandlung einer Binärzahl, in eine Dezimalzahl per Brainpower.


    Überprüfen wirs doch schnell an einem Beispiel, ob das System bestand hat:


    * = 4096


    LDA #%00000000 ; (= einem LDA #0)
    STA 1024
    RTS


    Man staunt nicht schlecht, denn der Turboass kann sogar BITweise eingegebene Werte verarbeiten. Man bereitet ihn mit einem "%" Prozentzeichen darauf vor, das ein Wert in Binär folgt. Nach dem Start dieses Programms, sehen wir oben links im Textfeld einen Klammeraffen, welcher den Screencode #0 besitzt. Testen wir weiter.


    * = 4096


    LDA #%00000001 ; (= einem LDA #1)
    STA 1024
    RTS


    Welches Zeichen werden wir wohl sehen? Es wird ein "A" nach dem starten erscheinen, da es den Screencode 1 hat. Warum? BIT0 ist gesetzt und hat die Wertigkeit 1. Alle anderen sind BITs sind gelöscht, daher bleibt es bei der 1.


    * = 4096


    LDA #%10000000 ; (= einem LDA #128)
    STA 1024
    RTS


    Wir können ein reversen Klammeraffen erspähen = Screencode 128!
    Es sieht also danach aus, das alles seine Richtigkeit hat. Doch was hat das alles mit unserem AND Befehl zu tun, den ich gaaaaanz weit oben erwähnt habe? Es wurde schon gesagt, das dieser Befehl, einzelne BITS löschen kann.


    Nehmen wir einfach mal ein Byte, in dem alle BITs gesetzt sind und löschen danach die Bits 7, 6, 5, 4 mit einem AND!


    7 6 5 4 3 2 1 0 : (BITS)
    ---------------
    1 1 1 1 1 1 1 1 : Anfangswert #255
    0 0 0 0 1 1 1 1 : AND (0=löscht das BIT. 1=lässt es wie es war.)
    ===============
    0 0 0 0 1 1 1 1 : Ist unser Ergebniss #15


    Wie man sieht, gibt man beim AND Befehl die jenigen BITs mit 0 an, die gelöscht werden sollen. Wo eine 1 steht, bleiben die BITs unangestastet. Verrückt, nicht war? Dann einfach nochmal lesen. Ich führe noch schnell ein weiteres Beispiel auf, an dem ihr testen könnt, ob es verstanden wurde.


    Im nächsten Posting gehts weiter.

  • 7 6 5 4 3 2 1 0 : (BITS)
    ---------------
    0 0 1 1 1 1 0 0 : Anfangswert #60
    1 0 0 1 1 0 0 1 : AND (0=löscht das BIT. 1=lässt es wie es war.)
    ===============
    0 0 0 1 1 0 0 0 : Ist unser Ergebniss #24


    Na? Verstanden? Wenn nicht, dann fragt nochmal nach.


    Überprüfen wir die letzte Auflistung schnell mit ein paar Zeilen Code.


    * = 4096


    LDA #%00111100 ; Wert #60 in Akku holen
    STA 1024 ; Anfangswert in Screen Position 1 pusten
    AND #%10011001 ; and #153
    STA 1025 ; Ergebnis (#24) in Screen Position 2 pusten
    RTS


    Assembliert mal das ganze (Pfeil links dann 3) und drückt Reset, oder gebt SYS64738 ein. Starten wir nun unser Programm mit SYS4096, und es erscheinen zwei Zeichen oben links im Screen. Es handelt sich dabei um "<x" zeichen. Dann peekt die Werte doch mal mit Basic heraus.
    ?peek(1024): ?Peek(1025)
    Na? Stimmt das ganze? Ihr werdet es sehen.


    Übrigens: Ist BIT 0 gelöscht, hat man es immer mit gerade Zahlen zu tun, ist es gesetzt, dann sind es ungerade!


    Morgen erfahrt ihr, warum wir diesen ganzen kram verstehen sollten, denn morgen ist der große Tag! Unsere Scrollroutine kann gecodet werden! Yippie!


    PS: Bitte achtet wieder auf Fehler!

  • @ biguser: Kleine Korrektur zum DEX: Zero-Flag wird automatisch gesetzt, wenn von 1 auf 0 runtergezählt wird (so wie bei INX: wenn Ergebnis 0, dann Zero-Flag).


    @ Pohli: ganz einfach, ich habe Courier New benutzt :)


    @ finchy: Die erwähnten Tips & Tricks Einzeiler habe ich mir eben mal angesehen: lohnt sich nicht. Feinscrolling geht zwar prinzipiell auch in Basic, aber das Ruckeln und Flackern kriegt man nie raus. Also entweder ganz plump zeichenweise verschieben, oder eine Assembler-Routine einbauen.


    Womit wir ja wieder beim Thema Assembler-Kurs wären :) .

  • Jeder der die letzten Tage den Crashkurs mitgemacht hat, sollte heute zum krönenden Abschluss seine heiß begehrte Scrollroutine schreiben können. Nur wie funktioniert diese überhaupt? Machen wir also ein paar theoretische Überlegungen.


    Wie ist es möglich, den Screen Pixel für Pixel auf der X-Achse zu verschieben? Das ganze klingt doch sehr nach einem optischen Effekt, ergo hat der VIC (unser Grafikchip im 64´er) etwas damit zu tun. Im Verlauf des Kurses, haben wir ihn schon des öfteren ganz unbewusst mit Daten zugeschüttet, denn die beiden Adressen 53280 & 53281 gehören mit zu seinem Herrschaftsbereich. Schauen wir doch mal in eine Dokumentation über die Register des VIC's. Wir sollten die Augen nach einen Register offen halten, mit dem es möglich ist, den Screen "Smooth" in X Richtung zu scrollen. Wir schauen und schauen, und finden im Register 53270 ($d016hex), die Lösung des ersten Problems. Hier ist die genaue Belegung:


    $D016 #53270 BITS VIC Control Register
    7-6 Unused
    5 ALWAYS SET THIS BIT TO 0 !
    4 Multi-Color Mode: 1 = Enable (Text or
    Bit-Map)
    3 Select 38/40 Column Text Display: 1 = 40 Cols
    2-0 Smooth Scroll to X Pos


    Wir stellen mit erstaunen fest, das nur Bit 0-2 für das Scrolling benutzt worden sind, und einige andere noch weitere Funktionen haben, die das Register 53270 in sich vereint.
    Gestern haben wir gelernt, das Bits eine Wertigkeit besitzen. Rechnen wir schnell mal die Wertigkeit der BITs zusammen, die für das X Scrolling zuständig sind. Da wären
    BIT0 - Wertigkeit 1
    BIT1 - Wertigkeit +2
    BIT2 - Wertigkeit +4
    --------------------
    Ergibt eine Wertigkeit von maximal 7! Wir können also den Screen um genau 8 (die null nicht vergessen) Pixel verschieben, wenn alle BITs gesetzt sind!


    %000 #0 - Standard Einstellung
    %001 #1 - 1 Pixel nach rechts
    %010 #2 - 2 Pixel nach rechts
    %011 #3 - 3 Pixel nach rechts
    %100 #4 - 4 Pixel nach rechts
    %101 #5 - 5 Pixel nach rechts
    %110 #6 - 6 Pixel nach rechts
    %111 #7 - 7 Pixel nach rechts


    Was passiert, wenn wir eine #8 nach 53270 schreiben? Nun, eine #8 ist mit 3 BITs nicht mehr darstellbar, und man benötigt ein viertes (BIT3). Das würde dann so aussehen:
    %1000 #8 - Standard Einstellung, aber BIT3 gesetzt


    Wir sehen das unsere unteren 3 Bits wieder alle gelöscht sind, und wir somit auf die Standardeinstellung der Pixelverschiebung zurückgesprungen sind. Nur BIT3 ist durch unsere #8 gesetzt worden. Schauen wir doch mal in die obige Liste, welche Bedeutung Bit3 hat.


    >>>"Select 38/40 Column Text Display: 1 = 40 Cols"
    Aha. Hier geht es um eine 38 Spalten und 40 Spalten Umschaltung unseres Screens. Aber wie wird denn der Screen um seine 2 spalten beschnitten? Der Rahmen, links und rechts, dehnt sich einfach zur mitte hin um 8 Pixel aus. Schon verdeckt er die ganz rechten, und ganz linken Spalten des Screens. Trotzdem können wir dort mit dem Cursor hinfahren, und Zeichen setzen, die nun Unsichtbar (vom Rand verdeckt) bleiben. Das ist eine sehr interessante Eigenschaft, die wir später zu nutzen wissen.


    Schauen wir uns aber nochmal die Erklärung von BIT3 an:
    >>>"Select 38/40 Column Text Display: 1 = 40 Cols"
    Wir legen unser Augenmerk auf den letzten Teil. 1 = 40 Cols ! Wenn das BIT3 also gesetzt ist, haben wir den 40 Zeichenmode aktiviert, wie er auch nach dem Einschalten des C64 zur Verfügung steht. Wenn BIT3 gelöscht ist, schalten wir um auf den 38 Zeichenmodus.


    Zusammengefasst, wissen wir nun, das mit Hilfe von BIT0-BIT2, im Register 53270 ($d016), der Screen um 8 Pixel sanft bewegt werden kann, sowie das BIT3 ein umschalter für den 38 & 40 Zeichenmodus ist. Die anderen BITs interessieren uns nicht.
    Coden wir nun erstmal das erste Stück der Scrollroutine


    * = 4096


    DEC counter ;Speicherzelle COUNTER um einen runterzählen. (umgekehrter INC)
    LDA counter ;Speicherzelle COunter in den Akku laden
    AND #%00000111 ;Alle Bits auf 0 setzen, bis auf BIT0-2. Diese unangestastet lassen.
    STA 53270 ;Den Wert in das "Scroll-Register" schreiben
    STA 1025 ;beim testen mit einem Peek auslesen zum Vergleich.
    RTS


    COUNTER .byte 0 ;Unsere Zählervariable, die gleich hinter dem RTS Befehl liegt.


    Hier sehen wir eine neue Eigenschaft vom Turbo Ass. Wie es aussieht, ist es möglich, Labels nicht nur als Sprungmarken zu nutzen, sondern auch um Variablen zu definieren. Unser Label COUNTER weißt nun auf eine 1 Byte grosse Speicherzelle (=Variable), die bei jedem Aufruf um 1 erniedrigt wird. Nach der Erniedrigung, wird diese Variable ausgelesen und mit dem AND Befehl zugeschnitten. Wir brauchen nur die Werte von BIT0-2 und löschen daher alle von BIT3-7. Dadurch bekommen wir nie Werte, die größer sind als 7. Dieser beschnittene Zählerwert wird nun in unser Scrollregister gepustet. Als Veranschaulichung der korrekten Werte, geben wir diesen noch in den Screen aus. Assemblieren wir das gute Stück schnell, und führen ein Reset aus.


    Wir gehen in die dritte Basiczeile und tippen wieder unseren Start SYS4096. Nach dem Entern, verengt sich plötzlich der Screen und verschiebt sich nach rechts. Warum? Gehen wir dem geschehen nochmal nach.
    Der erste Effekt (die Verengung) tritt durch unseren AND Befehl auf, denn wir löschen permanent BIT3 (38/40Zeichen), sowie nebenbei auch BIT4,5,6,7. Unbeeinflusst bleiben BITs0-2.


    Woher kommt nun diese Verschiebung nach rechts?
    Zur Zeit des Assemblierens, wurde unsere COUNTER Variable mit einer #0 Initialisiert. Durch den ersten Programmdurchlauf, wurde diese gleich auf #255 gesetzt! Da bei dem Wert #255 (%11111111) alle BITs gesetzt sind (auch die unteren 3), wurde der Bildschirm nach seinem maximal verschiebaren Rechtsbereich gerückt. Wir haben oben davon gelesen, das höhere Werte, den Bildschirm nach rechts rücken. Soweit die Erklärung dazu.


    Peeken wir doch mal den Wert aus der Speicherzelle 1025 in der das "G" dargestellt ist.
    Wir erhalten den Wert 7 und der AND Befehl arbeitet richtig. Entern wir nun noch ein paar mal unseren Start SYS4096! Wir können beobachten wie sich bei jedem druck auf enter, der Screen Sanft nach links verschiebt, und unsere Speicherzelle in 1025 heruntergezählt wird. Wir sind nun bei #0 angekommen, und entern noch einmal. Der Bildschirm rückt mit einem mal wieder ganz nach rechts, da wir wieder den Wert #7 haben, und alle Scroll BITs gesetzt sind. Ich hoffe ihr habt es verstanden. Das zu erklären ist gar nicht so leicht. Falls es noch probleme gibt, lest am besten noch ein paar mal den Abschnitt. Es ist keine Zauberei. Wir Speichern dieses kleine Programm jetzt, da wir hier später wieder ansetzen.


    Der ersten Teil unserer Scrollroutine ist fertig. Es handelte sich dabei um die Smooth verschiebung. Nur allein bringt diese uns nicht viel, ausser einen Screen, der sich immer 8 Pixel nach links bewegt, und dann wieder zurück nach rechts springt. Was ist nun zu tun? In dem Moment, in dem das Smooth-Scrolling um 8 Pixel zurückspringt, klinken wir uns mit einem HARDscrolling ein. Dieses Hardscrolling ist nichts weiter, als eine Abwandelung unserer Screenfüllroutine von vorgestern. Bei einem Aufruf dieser HARDscrollroutine sollen alle Zeichen der oberste Textzeile im Screen um eine Cursorstelle nach links verrückt werden.
    Nichts leichter als das! Üben wir diesen Part separat und löschen den alten Code von eben mit einem Pfeil nach links, gefolgt von einem "C". Der Turbo Ass fragt uns, ob er wirklich einen Kaltstart durchführen soll. Diese Frage bestätigen wir mit "y"-yes. Wir erhalten wieder einen leeren Editor. Und tippern nun unsere HARDscroll Routine ein.


    * = 4096


    LDX #0 ;X Register mit #0 initen
    loop LDA 1025,x ;Zeichen aus 1025 (+x) auslesen
    STA 1024,x ;und nach 1024 (+x) schreiben
    INX ;X erhöhen
    CPX #40 ;das ganze 40mal, für 40 Textzeichen = 1 Textzeile!
    BNE loop ;alle 40 durch, wenn nicht dann nochal zu Label: LOOP
    RTS


    Diese Routine, zieht die Zeichen in Textzeile 1 um eine Cursorstelle nach links. Na... stimmt das auch. Assemblieren und mal starten. Zu sehen ist erstmal nichts! Wahrscheinlich ist unsere Textzeile 1 gerade leer gewesen. Dackeln wir schnell mal mit dem Cursor hoch, und schreiben rein. "BEWEG DICH!"...
    Nun schubbern wir raus aus diese Zeile und starten den Code wieder mit einem SYS4096 und kommen aus dem staunen nicht raus, das "BEWEG DICH!" hat sich tatsächlich bewegt hat, um genau eine Cursorstelle nach links.
    Entern wir einfach öfter mal unseren Start SYS4096, und beobachten wie "BEWEG DICH!" am linken Rand verschwindet. Somit haben wir schon den zweiten Teil unserer Scrollroutine fertig. Das dumme ist nur, das wir diesen mit dem ersten kombinieren müssen. Also nichts wie ran, und den gespeicherten Quellcode von vorhin geladen, der das sanfte X-scrolling enthielt.


    Vielleicht erinnert man sich noch daran, das die HARDscrollroutine nur aktivert werden muss, wenn die Smoothverschiebung sein maximum erreicht hat. Da wir schon wissen, das die Maximale Verschiebung mit dem Wert #7 erreicht ist (alle 3 Scroll-BITS gesetzt), müssen wir auf diesen Wert prüfen (vergleichen). Das tun wir mit einem Compare Befehl. Zum besseren Verständnis, gebe ich hier schonmal den Quellcode vor. Die einzelnen Unterbereiche habe ich zur besseren Wiedererkennung getrennt markiert.
    Weiter gehts in Teil 5b

  • * = 4096


    ;---- Softscroll Bereich
    DEC counter ;Speicherzelle COUNTER um einen runterzählen. (umgekehrter INC)
    LDA counter ;Speicherzelle COunter in den Akku laden
    AND #%00000111 ;Alle Bits3-7 auf 0, BIT0-2 unangestastet lassen.
    STA 53270 ;Den Wert in das "Scroll-Register" schreiben

    ;----- maximale Verschiebungsprüfung
    CMP #7 ;Wert im Akku =7 und maximal Smoothverschiebung erreicht?
    BNE nohard ;Wenn nein, dann überspringe das Hardscrolling


    ;----- Hardscrolling
    LDX #0 ;X Register mit #0 initen
    loop LDA 1025,x ;Zeichen aus 1025 (+x) auslesen
    STA 1024,x ;und nach 1024 (+x) schreiben
    INX ;X erhöhen
    CPX #40 ;das ganze 40mal, für 40 Textzeichen = 1 Textzeile!
    BNE loop ;alle 40 durch, wenn nicht dann nochal zu Label: LOOP

    ;------ Programm Ende
    nohard RTS


    COUNTER .byte 0 ;Unsere Zählervariable, für das Softscrolling


    Wir betrachten uns diesen Code-Brocken mal genau. Wir finden unser Softscroll Code von vorhin wieder, genau wie das Hardscrolling. Die "maximale Verschiebungsprüfung" schaut nun in den Akku rein, ob sich dort bei einem Durchlauf mal ne 7 drin aufhält. Diese ist ja der maximal Verschiebungsbereich vom Softscrolling. Wenn eine 7 sich im Akku befindet, wird unsere gesamte Textzeile 1 um eine Cursorstelle nach links verschoben. Falls sich andere Werte im Akku befinden, wird der Code vom Hardscrolling einfach übersprungen und die Routine wird beendet. Jetzt wirds spannend! Wir testen es aus. Schnell wieder Assemblieren, resetten.


    Gehen wir gleich mal in die obere Textzeile und tippen "BEWEG DICH SOFT!". Mal schaun, ob der Rechner auf unseren Befehl hört. Wir hüpfen mit unseren Cursor in die dritte Textzeile und tippen unseren Start SYS4096. Der screen zuckt wieder, aber bisher ist noch nichts passiert, was wir nicht vorhin beim ersten Softscroll Test schon gesehen haben. Entern wir unseren start SYS doch ein paar mal, und beobachten wie sich der Screen wieder langsam nach links verschiebt. Nachdem wir das ganze 8 mal getan haben, sehen unsere Scrollregister BITs wie folgt aus: %000. Beim nächsten Enter, müßten dann wieder alle gesetzt sein (Wir zählen Rückwärts!). Also sehen unsere BITs dann so: %111 aus, welche zusammen den Wert #7 ergeben. Also müßte nun beim neuntem Entern des Start SYS unsere HARDscrollroutine aktiviert werden, und der Screen wieder ganz nach rechts springen. Entern wir also und beobachten es ganz genau. UND? Wie es scheint, haben wir es hinbekommen. Unsere Textzeile 1 ist nicht wie die anderen zurückgesprungen, sondern hat sich um einen Pixel weiter bewegt. Machen wir das ganze doch etwas schneller, und schreiben ein kleines Basic Programm.


    1 PRINT "{clrhome}SUPER, ICH KANN SCROLLEN! JUHUUU!"
    2 FOR I=0 TO 15: NEXT I : REM NICHT SO SCHNELL
    3 SYS 4096 : REM SCROLLING AUFRUFEN
    4 GOTO 2 : REM IMMER WIEDER DAS GANZE


    Wir sehen unseren Text in der obersten Zeile langsam nach links herausscrollen. Das ist doch schon fett!!! Nur irgendwie fehlt was. Achja! Es kommt gar kein neuer Text nach. Basteln wir noch etwas an unserer scrollroutine umher. Nun, wir sehen das der Bildschirm scrollt, aber warum wir diesen 38 Spalten Modus benutzen, ist bisher immer noch ein Geheimnis geblieben, das jetzt zu seiner Auflösung kommt. Immer wenn ein Hardscroll durchgeführt wird, sollte im gleichen durchgang ein neues Zeichen aus dem Ram gefischt, und in die rechte verdeckte Cursorspalte geschrieben. Wenn diese nicht verdeckt wäre, würde man es sehen, das hier ständig neue Buchstaben gesetzt werden, und diese nicht aus dem Rand hervorscrollen würden, wie es sonst den anschein hätte. Bauen wir nun unseren Textnachschieber ein. Dazu brauchen wir noch einen neuen Zähler, der immer auf den zu holenden Buchstaben zeigt. Diesen geben wir einfach mal das Label: TEXTPOS


    * = 4096


    ;---- Softscroll Bereich
    DEC counter ;Speicherzelle COUNTER um einen runterzählen. (umgekehrter INC)
    LDA counter ;Speicherzelle COunter in den Akku laden
    AND #%00000111 ;Alle Bits3-7 auf 0, BIT0-2 unangestastet lassen.
    STA 53270 ;Den Wert in das "Scroll-Register" schreiben

    ;----- maximale Verschiebungsprüfung
    CMP #7 ;Wert im Akku =7 und maximal Smoothverschiebung erreicht?
    BNE nohard ;Wenn nein, dann überspringe das Hardscrolling


    ;----- Hardscrolling
    LDX #0 ;X Register mit #0 initen
    loop LDA 1025,x ;Zeichen aus 1025 (+x) auslesen
    STA 1024,x ;und nach 1024 (+x) schreiben
    INX ;X erhöhen
    CPX #40 ;das ganze 40mal, für 40 Textzeichen = 1 Textzeile!
    BNE loop ;alle 40 durch, wenn nicht dann nochal zu Label: LOOP


    ;------ neuen Buchstaben holen nach Hardscroll
    LDX TEXTPOS ;aktuelle TEXTPOSition aus Variable holen
    INC TEXTPOS ;TEXTPOS um 1 erhöhen, für den nächsten Buchstaben
    LDA TEXT,X ;TEXT+X ergibt den aktuellen Buchstaben
    STA 1063 ;diesen in letzte Cursorspalte von Textzeile 1 (1024+39=1063)


    ;------ Programm Ende
    nohard RTS


    COUNTER .byte 0 ;Unsere Zählervariable, für das Softscrolling
    TEXTPOS .byte 0 ;TEXT von Position 0 auslesen.
    TEXT .text "dies ist also "
    .text "softscrolling "
    .text "in 6502 Assembler! "


    Als erstes ist es sicher Interessant für uns, das der Turbo Ass die Möglichkeit bietet, ganze Texte ins Ram zu Assemblieren. Der Befehl ".text" leitet eine Textsequenz ein,
    die genau wie der Basic Print mit zwei Anführungszeichen eingeschlossen wird. Den Rest können wir uns alle mittlerweile selbst denken und benötigt keine weitere Erklärung. Hoff ich jedenfalls :)
    Also testen wir unsere neue Errungenschaft. Assemblieren, dann resetten und wir geben folgende Basic Zeile ein:


    1 sys 4096 : for i=0 to 2 : next i : goto 1



    Starten wir das ganze, und beobachten wie der Text, der im Turbo Ass eingeben wurde, aus dem rechten Rand hervorgescrollt kommt. Doch irgendwie sind es geshiftete Buchstaben. Schalten wir schnell auf die kleine Schrift mit den Tasten C= + SHIFT um. Woran liegt das? Der .TEXT Befehl des Turbo Ass Assembliert die Texte nicht als Screencode, sondern als ASCII Werte. Also merken wir uns, bevor das Scrolling starten soll, auf den Kleinschriftmodus wechseln. Der Assblaster beherrscht auch die Screencodes. Der Turbo Ass leider nicht.
    Nachdem unser Text vorbeigescrollt ist, erscheinen nur noch wirre Zeichen. Nicht gerade schön. Warten wir mal noch ein Weilchen, denn nach einiger Zeit, kommt wieder unser Text vorbeigescrollt. Woran liegt das? Schauen wir uns folgendes Stück aus unserem Code an:


    ;------ neuen Buchstaben holen nach Hardscroll
    LDX TEXTPOS ;aktuelle TEXTPOSition aus Variable holen
    INC TEXTPOS ;TEXTPOS um 1 erhöhen, für den nächsten Buchstaben
    LDA TEXT,X ;TEXT+X ergibt den aktuellen Buchstaben
    STA 1063 ;diesen in letzte Cursorspalte von Textzeile 1 (1024+39=1063)


    Wir benutzen einen 1 Byte grossen Zähler, mit dem wir unseren Buchstaben aus dem Ram fischen. Zähler die sowas machen, nennt man auch OFFSET Werte. Jedenfalls klappt dieser Zähler nach 256 durchläufen wieder auf #0 zurück, und fängt von vorne an zu zählen, und somit erscheint auch wieder unser Text. Also ist es uns möglich, auf diese Art und Weise, einen Scrolltext zu schreiben, der maximal 256 Zeichen lang ist, da er danach von vorn beginnt. Was ist aber, wenn wir einen kürzeren schreiben wollen, und dieser sich sofort danach wiederholen soll. Wir brauchen sowas wie eine Endmarkierung des Textes. Legen wir einfach mal die #255 als Endmarkierung fest. Wenn nun unser Text soweit vorrangeschritten ist, das er auf die #255 trifft, müßte unser Zähler TEXTPOS wieder auf #0 zurückgesetzt werden. Setzen wir die Theorie mal praktisch um.


    ;---- Kleinschrift Modus setzen
    LDA #23
    STA 53272


    ;---- Softscroll Bereich
    DEC counter ;Speicherzelle COUNTER um einen runterzählen. (umgekehrter INC)
    LDA counter ;Speicherzelle COUNTER in den Akku laden
    AND #%00000111 ;Alle Bits3-7 auf 0, BIT0-2 unangestastet lassen.
    STA 53270 ;Den Wert in das "Scroll-Register" schreiben

    ;----- maximale Verschiebungsprüfung
    CMP #7 ;Wert im Akku =7 und maximal Smoothverschiebung erreicht?
    BNE nohard ;Wenn nein, dann überspringe das Hardscrolling


    ;----- Hardscrolling
    LDX #0 ;X Register mit #0 initen
    loop LDA 1025,x ;Zeichen aus 1025 (+x) auslesen
    STA 1024,x ;und nach 1024 (+x) schreiben
    INX ;X erhöhen
    CPX #40 ;das ganze 40mal, für 40 Textzeichen = 1 Textzeile!
    BNE loop ;alle 40 durch, wenn nicht dann nochal zu Label: LOOP


    ;------ neuen Buchstaben holen nach Hardscroll
    texread LDX TEXTPOS ;aktuelle TEXTPOSition aus Variable holen
    INC TEXTPOS ;TEXTPOS um 1 erhöhen, für den nächsten Buchstaben
    LDA TEXT,X ;TEXT+X ergibt den aktuellen Buchstaben
    CMP #255 ;War das Byte gerade die Endmarkierung ?
    BNE nomark ;wenn nicht, dann setze den Buchstaben.
    LDA #0 ;War es doch die Endmarkierung, dann setze den
    STA TEXTPOS ;TEXTPOS auf #0 (=Anfang) zurück.
    JMP texread ;UND hole sofort den nächsten Buchstaben von Anfang.
    nomark STA 1063 ;Zeichen in letzte Cursorspalte pusten (1024+39=1063)


    ;------ Programm Ende
    nohard RTS


    COUNTER .byte 0 ;Unsere Zählervariable, für das Softscrolling
    TEXTPOS .byte 0 ;TEXT von Position 0 anfangen auszulesen.
    TEXT .text "dies ist also "
    .text "softscrolling "
    .text "in 6502 Assembler! "
    .byte 255 ; die Endmarkierung des Textes, leitet den Neubegin ein.


    Vergesst nicht, unten am Text, unsere Endmarkierung anzufügen (byte 255)! Ansonsten klappt es nicht mit dem Neustart. Assemblieren wir nun unsere Veränderungen, und resetten. Tippern schnell folgende Basic Line.


    1 SYS 4096 : for i = 0 to 2 : next i : goto 1


    Enorm nicht war! Das ganze funktioniert !!! Wir können nun einen Scrolltext schreiben, der kürzer ist als 255 Zeichen, und der durch die Endmarkierung neu gestartet wird. Wer gerne längere Scrolltexte schreiben will, muss die Routine etwas verändert, aber das wollen wir hier nicht mehr tun, da es sonst wohl zu unübersichtlich wird.
    Wir haben also nun unser Kursziel erreicht, und einen grandiosen Start in die 6502 Era hingelegt.

  • Also die Textdatei würde mich natürlich interessieren, aber das nur nebenbei.


    Ich bin jetzt gerade mit Teil 4 durch und es sind wieder ein paar Fragen aufgekommen, die ersten beiden sind aber nicht so wichtig:
    1.


    Ich sehe das doch richtig, dass man bei diesem Programm das loop Label auch weglassen kann, oder?


    2.

    Zitat

    ...Daher Resetten wir (ein Resetschalter tuts auch), und tippen in die dritte Basic Zeile:


    SYS 4096 : PRINT PEEK(1024)


    ...Und drücken Return
    Wie wir sehen, erscheint wieder ein "!" Zeichen, und der Peek teilt uns mit, das in der Adresse 1024 jetzt der Wert 33 gespeichert ist. Fahren wir mit den Cursor nochmals auf die Höhe unserer Basic Zeile, und drücken wieder Return...


    Hier wollte ich nur wissen, was du mit dritter BASIC Zeile meinst? Nach dem Reset kommt ja die Einschaltmeldung und da kann man das Ganze doch auch einfach unter die READY. Meldung schreiben, oder?
    Ich weiß, ist eine pingelige Frage! :D


    Aber jetzt:


    3.
    Der AND Befehl!


    Das Addieren ist mir schon klar. Vielleicht hätte man den anderen das Prinzip des logischen ANDs noch genauer erklären sollen, aber nun zu meiner Frage:
    Alle bisherigen Befehle außer dem rts, jmp und bne bezogen sich immer auf ein Register und das war ja eindeutig festgelegt. Entweder auf den Akku, auf das x- bzw. y-Register oder auf irgendeine andere Speicherzelle im C64 (z.B. 1024).
    Aber, woher weiß der Computer das richtige Register (im Beispiel 1024), auf dessen Wert (im Beispiel 60) er den AND Befehl anwenden soll? Das ist ja nicht im AND Befehl enthalten, sondern nur der Wert, den er per Logik-UND addieren soll (im Beispiel 153). Muss das entsprechende Register dann halt in der vorherigen Zeile erwähnt werden oder wie geht das?
    Und was ist, wenn in der vorigen Zeile ein bne steht, also kein Register?
    Ich hoffe ihr versteht, was ich meine! :)


    4. Wo im Speicher des C64 befinden sich eigentlich der Akku, das x-Register und das y-Register? Oder wird das vom Assembler-Programm festgelegt und ist von Assembler zu Assembler unterschiedlich? Oder sind die irgendwie in der CPU selbst und belegen gar keines der Register von 0 bis 65535?

  • Pohli:


    Die Textdatei bekommst du nacher.


    Schnell zu deinen fragen:
    -------------------------


    Frage 1: Du hast recht, das Label LOOP, kann man sich sparen. Das kommt davon, wenn man Copy / Paste und dann nur verändert :) Ich hab es im Kursteil korrigiert.


    Frage 2: "BASIC ZEILE" ist natürlich Quatsch! Es muss heißen, >TEXTZEILE<. Hab ich ebenfalls korrigiert.


    Frage 3: Eine gute Frage, mit der ich nicht gerechnet habe! Der AND Befehl kann auf zwei Arten benutzt werden. Entweder man teilt ihm den Wert direkt zu (wie im Beispiel AND #%10011001), oder man holt sich den zu ANDenden Wert aus einer Speicherzelle. Beispielsweise so AND $xxxx. Dabei erhält man das Ergebniss immer im AKKU! X & Y lassen sich nicht als AND Werte benutzen, oder können AND Funktionen ausführen. Das ist allein eine Domäne des Akkus! Am besten besorg dir die komplette 6502 Befehlsübersicht, dort sind alle möglichen Varianten der Befehle aufgelistet. Kennt jemand im Web eine gute Seite?


    Frage 4: Die 3 Register (auch das Statusregister), sind nicht im Ram des C64 untergebracht. Diese befinden sich direkt im 6502 Prozessor. Die Assemblerprogramme haben damit nichts zu tun, da sie einfach nur die 6502 Befehle aus deinem Quellcode erzeugen, und es sind immer dieselben. Also der Assblaster beherrscht nicht mehr Assemblerbefehle, als der Turbo Ass. Wenn du mehr und bessere Befehle brauchst, muss man sich nach einem neuerem Prozessormodell umschauen, wie den 65816 in der SuperCPU & COne. Mit die Virtual Ass, kann man die neuen Befehle dieses Prozessor voll ausnutzen. Wenn man dann aber so ein 65816 Programm auf einem 6502 laufen läßt, stürzt es ab. Glaub aber nicht das noch neuere Prozessoren einem es immer leichter machen. X86 bis Pentium 4, sind ein grausig üble Assembler Befehlssätze.

  • villain: probier mal "true drive emulation" beim vice??! vielleicht liegts daran.... dann dauerts zwar ein bisschen länger (original) aber es gibt ja noch Alt-W (warp)
    @all: im Programmer's Reference Guide (bei project64 zu haben) findet man eine gute Übersicht über alle Befehle, Register, Adressierungsarten usw. Nachteil: Gibts im Netz wohl nur auf Englisch und da das Buch/ Text sehr umfangreich ist und der ML-Teil nur einen kleinen Teil beansprucht muss man wahrscheinlich erst mal nen halben Tag suchen, die entsprechenedn Seiten zu finden ;). Ansonsten bin ich ja (noch) dabei das ML Buch von Lothar Englisch abzutippen, gibts dann auf meiner hp, ich bin zwar schon mit dem Teil Übersicht aller Befehle fertig, aber habs noch nicht upgeloadet; wird demnächst geschehen.

  • Tirili, wirklich faszinierend. Ich habe aber noch ein paar Ungereimtheiten (Fehler?) im Text gefunden:


    Zitat

    Unser Label COUNTER weißt nun auf eine 1 Byte grosse Speicherzelle (=Variable), die bei jedem Aufruf um 1 erniedrigt wird. Nach der Erhöhung , wird diese Variable ausgelesen und mit dem AND Befehl zugeschnitten.


    Sollte sicher Erniedrigung heißen, auch wenn der Sprung von 0 auf 255 erst mal eine Erhöhung ist... 8o


    Zitat

    Diese Routine, zieht die Zeichen in Textzeile 1 um eine Cursorstelle nach rechts . Na... stimmt das auch.


    Nein, stimmt nicht! Die Textzeite wird doch wohl nach links gezogen, oder?


    Zitat

    Also sehen unsere BITs dann so: %111 aus, welche zusammen den Wert #7 ergeben. Also müßte nun beim neuntem Entern des Start SYS unsere Scrollroutine aktiviert werden, und der Screen wieder ganz nach rechts springen.


    Um genau zu sein, die Hardscrollroutine, nicht wahr?


    Ansonsten glaube ich, ist das alles so korrekt und vor allem auch verständlich.
    Wann geht´s weiter und vor allem wie??? Ich fiebere schon dem Jahresende und damit meinem erstem selbstgecodetem Demo entgegen :D

  • Ich hab das mit dem AND Befehl wohl immer noch nicht richtig gepeilt.


    Aber vorher nochmal zu meiner Frage 2:
    Ich hatte mich wohl nicht so richtig ausgedrückt. Ich meinte nicht wieso BASIC Zeile, sondern wieso die dritte Zeile.


    Und nun zu Frage 3, also zum AND Befehl:
    Ich versuch's nochmal anders:

    Zitat

    7 6 5 4 3 2 1 0 : (BITS)
    ---------------
    0 0 1 1 1 1 0 0 : Anfangswert #60
    1 0 0 1 1 0 0 1 : AND (0=löscht das BIT. 1=lässt es wie es war.)
    ===============
    0 0 0 1 1 0 0 0 : Ist unser Ergebniss #24


    Wir haben hier doch drei Werte:
    1. Den von dir bezeichneten Anfangswert.
    2. Den Wert, den man mit dem Anfangswert verrechnet und den man hinter den AND Befehl schreibt, egal ob man ihn nun direkt hinschreibt oder ob man ihn aus einer Speicherzelle nimmt.
    3. Und das Ergebnis.

    Zitat

    AND #%10011001


    Und das ist die zugehörige Zeile, wenn man sie mal alleine betrachtet. Hier sehe ich aber nur einen Wert und zwar den 2.
    Also wo bleibt z.B. das Ergebnis?
    Du schriebst ja schon, das Ergebnis wird in den Akku geschrieben. Gilt das denn für jeden AND Befehl, unabhängig vom Rest des Programms?


    Also bleibt noch ein Wert übrig, der Anfangswert. Woher holt sich der AND Befehl den Anfangswert, auch aus dem Akku oder aus der im Programm zuletzt genannten Speicherzelle?
    Das ist es, was mir noch unklar ist.

  • Zitat

    Woher holt sich der AND Befehl den Anfangswert, auch aus dem Akku oder aus der im Programm zuletzt genannten Speicherzelle?


    Biguser hat ja schon mal geschrieben, der AND-Befehl bezieht sich nur auf den Akku. Das heißt, der aktuelle Wert des Akkus wird mit dem Wert hinter dem AND-Befehl UND-Verknüpft und das Ergebnis wieder im Akku gespeichert. Also ist der Akku sowohl Quelle des Startwertes als auch Ziel des Ergebnisses.

  • Neefi: Wiedermal gut aufgepasst! Es ist doch erstaunlich, wieviel Fehler man selbst nach drei mal durchlesen nicht mitbekommt! Die neugefundenen Fehler von Neefi habe ich korrigiert.


    Pohli: Der Grund, warum man in die dritte Zeile soll, ist schlicht und einfach, das du deinen Start Sys nicht in die erste Zeile tippern sollst, und dieser durch das scrollen kaputt gemacht wird. Mehr steckt nicht dahinter. Du hättest auch alle anderen Zeilen nehmen können, ausser der ersten.