Angepinnt Basic-Scrollings

  • Basic-Scrollings

    Schönen guten zusammen!

    Die Frage ist für die echten Crax vielleicht ein wenig lächerlich, aber mich würde interessieren, wie man im Basic 2.0 eine beliebige Zeile scrollen lassen kann. In einer Dimension 64 Ausgabe habe ich da mal was gelesen, das war mit Variablen und Pokes und das Ergebnis war ein unglaublich hakeliges scrollen von rechts nach links. Gibt es auch eine "smooth" Lösung dafür? (Ziel: einigermaßen erträglicher Scrolltext irgendwo, entweder erste Zeile, Mitte oder unten - egal!)

    Schönen Dank
    Greetings, Starfighter. You have been recruited by the Star League to defend the frontier against Xur and the Ko-Dan armada.


    Kilobyte Magazine - The PDF-Mag for everything 8bit
    KBMag on Twitter
    KBMag on Facebook
  • "smooth scrolling" kriegst du nur mit assembler hin. aber das ist an sich kein problem, denn du kannst ja kleinere asm-routinen von basic aus aufrufen, und wenn der scroller noch im interrupt ist, läuft das basic-programm weiter.

    wenn du willst, kann ich dir eine kleinen 1x1-scroller basteln, oder sicher auch jemand anderes hier aus dem forum. da gibt's einige hier, die das können.
  • In Basic ist das leider nicht machbar.
    Einzige Möglichkeit wäre es mal mit dem Basic Boss zu probieren. Der hat glaube ein paar nette features. Die Demo Compiles von dem ding sind recht beachtlich! Es war zwar kein Scrolldemo dabei, aber in 50hz bewegte Sprites die im Sinus hin und her flogen. Für normales Basic undenkbar. Auch mit Austrospeed wohl nicht machbar.

    Das beste ist, sich ein wenig Assemblerkenntnisse anzueignen.

    Der erste Schritt ist, sich den Turbo Assembler zu ziehen. Der wird ("die meisten jedenfalls") mit SYS36864 gestartet. Oder sauge dir das Retro Replay für den Emu und type TASM, und schwupp... hast du ein Turbo Assembler vor dir. Läuft übrigens sehr gut im Vice Emu.

    Schon kannst du loslegen mit einem 6502 code.
    Schnell noch den Startbereich des Codes definieren.
    Gib einfach ein:

    *=4096 ; = SYS 4096 zum späteren starten. Ein Semikolon ist das gleiche wie ein Basic REM

    mit dieser Zeile sagst du dem Assembler, in welchen Speicher er das programm beim Assemblieren speichern soll.

    Darunter tippst du einfach

    lda #1 ; 1 a=1 (Basic Variable)
    sta 53280 ; 2 POKE 53280,a
    sta 53281 ; 3 POKE 53281,a
    rts ; 4 END

    schon wäre dein erstes echtes Assemblerprogramm fertig. Es ist dem Basic nichtmal sehr unähnlich aber rund 1000 fach schneller. Assembler ist nicht schwer.
    jetzt drück einfach "PFEIL LINKS" nun bist du im Command Mode des Turbo Assemblers. Wenn du nun deinen Assemblercode assemblieren willst, dann drück einfach "3". Nun parsed er dein geschriebenes durch. Wenn keine Fehlermeldung kommt, dann drück einfach "S" zum starten des Programms. Der Bildschirm sollte sich nun Weiß färben und der Cursor blinken. Wenn du wieder in den Editor willst, dann reicht ein Druck auf Restore.

    Noch ein paar dinge zum Command Mode.
    Pfeil Links danach
    "S" - Soucecode speichern
    "L" - Soucecode laden
    "*" - Directory
    "3" - Assemblieren
    "1" - Turbo Ass beenden - Restore bleibt aktiv

    Falls du mehr Infos willst, sag bescheid, dann gehen wir soweit, bis du deinen eigenen Scroller coden kannst. Bisher ist doch alles recht einfach, oder? Vielleicht macht es dir ja Mut, dich daran mal zu versuchen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von biguser ()

  • Hallo..

    Ich versuche ja auch seit neustem ASM zu lernen, syntaktisch verstehe ich es nun einigermaßen, nur die Bedienung der Assemblierprogramme fällt mir sehr schwer. Habe es mit Monitoren probiert, mit dem AssBlaster.. keiner wollte meinen Testcode ausführen.
    Ich weiß eben nicht, wie man die Programme bedient.
    Währe wünschenswert, wenn mir das auch einer erklären könnte..

    Bis dann, ............ ritti ;)
    Server-Uptime:
  • programmierst du auf einem echten c64 oder auf einem emulator?

    ich kann dir gerne den profi-assembler als d64 schicken. ist sehr gut, sehr einfach zu bedienen und ich habe auch noch die anleitung dafür...

    falls du auf emu programmierst, vielleicht hast du ja interesse an crossdevelopement? :)
  • Wenn also solch ein Interesse besteht, dann machen wir also einen kleinen Crashkurs, der als Ziel eine Scrollroutine hat.

    Anno 1992 war ich in der ähnlichen Lage wie ihr. Ich wollte irgendwas schickes machen, aber Basic war einfach zu lahm. Man hatte keine Ahnung von Assembler. Eines Tages dachte ich mir: "Jetzt nehm ich mir dieses dicke Data Becker Buch, und lern
    Assembler". Ok, woran ich mich noch entsinne, das ich zwei Minuten später das Buch wieder zuschlug und keine Peilung hatte. Dazu kam auch noch, das ich dieses Hexadezimal System nicht kannte. Es war sehr verwirrend, angebliche Zahlen als #$FA zu sehen. Basic Programmierer kennen meist nur das Dezimal System, was für unsere Zwecke eigentlich ausreichen sollte, da die Assembler diese auch akzeptieren.

    Wie einer meiner Vorredner schon sagte, die Bedienung so mancher Assembler ist ein graus! Einige sind wahrscheinlich im Suff erdacht & gecodet worden. Hier muss man sich etwas einfuchsen, aber es sind gar nicht so viele Tastencodes, die man sich merken muss. Den angesprochenen Assblaster hab ich auch 4 Jahre benutzt, aber wegen einiger Bugs und zu groß gewordener Projekte, bin ich dann letztendlich umgestiegen. Der Assblaster hat eine gute Menüführung, aber für die weitere Verwertbarkeit des Quellcodes, ist der Turbo Ass besser geeignet. Das Ding ist halt das Scene Coding Tool schlecht hin, und wir wollen doch keine Traditionen brechen.

    Wer probleme mit den ganzen Tastencodes des Turbo Ass hat, der sollte sich mal folgende Seite anschauen:

    old.c64.ch/programming/ta-docs.asp

    Hier findet man alles. Falls ihr fragen dazu habt, postet es einfach. Eines müßt ihr euch nur merken. In den Command Mode kommt man immer mit der Pfeil nach links Taste. Danach wird die Taste für die jeweilig gesuchte Funktion gedrückt.

    Ok. Dann nehmen wir doch nochmal das kleine Programm von vorhin genauer auseinander. Was heißen die Befehle eigentlich.
    Hier nochmal schnell der Code.
    -----------------------------------------
    * = 4096 ; ein SYS4096 aus dem Basic heraus ruft unser Programm auf.

    lda #1
    sta 53280
    sta 53281
    rts

    Zeilennummern wie in Basic gibt es hier nicht. Der erfahrene Basic Coder wird jetzt schon unruhig. Aber keine Sorge, das Programm wird von oben nach unten abgearbeitet, als ob Zeilennummern davorstehen würden.

    Wie euch sicher schonmal aufgefallen ist, sind alle 6502 Assemblerbefehle nur drei Buchstaben lang, welches schöne Abkürzungen für ihre eigentliche Funktionen sind. Der erste Befehl ist wohl einer der meist gebrauchtesten im 6502 Befehlssatz.

    Nehmen wir mal den "LDA" auseinander. Wofür stehen die Buchstaben? Das "LD" steht für LOAD. Hmmm... also wird hier schonmal was geladen. Nichts von Disk, aber ein Wert der von 0 bis 255 groß sein kann. Ok, aber ein Buchstabe fehlt noch. Und zwar das "A" vom "ldA". Dieses A ist die Abkürzung für Akku. Der Akku ist nichts weiter als eine 1Byte/8bit (0-255) große Speicherzelle. Also zusammengefasst, heißt nun "LDA" - LOAD AKKU(MULATOR). Hinter dem Befehl, übergibt man einfach den Wert, den der Akku annehmen soll. In unserem Fall die #1 ! Nun fragt sich vielleicht der eine oder andere, wofür dieses kryptischen dingens hier "#" steht. Dieses Gatter oder Doppelkreuz genannt, teilt dem Assembler mit, das nun eine DEZIMAL Zahl folgt, die DIREKT in den Akku geladen werden soll. Wer sich mit Hexadezimal auskennt, kann dann folgende Schreibweise nutzen "#$". Dies steht immer dafür, das ein HEXADEZIMAL Wert DIREKT geladen werden soll. Das ist ein feiner, aber wichtiger Unterschied!

    Ok, was haben wir nun erreicht. Mit "LDA #1" haben wir unseren Akku eine 1 aufgehalst. Die ist so schwer, das er die gerne loswerden will. Na dann schnell weiter.

    Kommen wir nun zum "STA". Wie auch der Laie unschwer erkennen kann, ist in diesem Befehl wieder ein "A" enthalten, und naheliegende Schlussfolgerungen führen uns unweigerlich auf einen Befehl zu, der etwas mit unserem Akku vor hat. Was heißt nun "ST" in "STa"? Mein Angebot an das Wissen wäre STORE! Also ist die komplette Bedeutung dieses Befehls "STA" - STORE AKKU(MULATOR). Da Store nun nichts weiter bedeutet wie SPEICHERN, ist der Sinn dieses Befehls nun super einfach. Speichere den Akku nach der gefolgten Speicheradresse. In unserem Fall, die Rahmenfarbe und Hintergrundfarbe.

    Nochmal zusammengefasst, haben wir bisher nichts weiter getan, als in unseren 1 Byte großen Akku eine #1 reinzuladen, und diese in die beiden Farbadressen zu pusten. Tja, eigentlich nicht schwer.

    Vielleicht wundert sich jemand, warum bei STA nicht auch ein # angefügt wird. Also Beispielsweise STA #53281 (<falsch), da es sich ja um eine Dezimaladresse handelt. Warum ist das anders gegenüber dem LDA. Wer genau auf die groß und klein Schreibung geachtet hat, wird bemerkt haben, das ich immer geschrieben habe: "das nun eine DEZIMAL Zahl folgt, die DIREKT in den Akku geladen...". Hierbei sollte das Augenmerk auf DIREKT gelegt werden. Um es mal in Basic Worte zu fassen, heißt direkt:

    A=1 - Variable a wird eine 1 zugeteilt.

    Das ist also direkt. Was passiert denn, wenn beim LDA das "#" einfach weglassen und es so schreiben "LDA 1"? Dann würde sich der Akku mit dem Wert der Speicherzelle 1 aus dem Ram befüllen. Je nachdem welcher Wert dort drinsteckt, verändert sich eure Hintergrundfarbe. Schreibt dort aber mit STA nicht rum. Denn ein STA 1 hat bei unsachgemäßer Benutzung Abstürze zur Folge, auf die wir hier nicht weiter eingehen. Beim auslesen passiert aber nichts.

    In Basic würde ein "LDA 1" einem
    A=Peek(1)
    entsprechen.

    Auf diese Art und Weise, könnt ihr auf den ganzen C64 Speichern zugreifen. Von Adresse 0 bis 65535. Allerdings lassen sich nicht alle Zellen lesen und Beschreiben, da an einigen sich das Kernal und Basic Rom breit machen.

    Nun gut. Noch schnell zum letzten Befehl, dem "RTS". Basic Programmierer könnten fast auf ein RETURN tippen. Wer das getan hat, liegt damit Gold richtig. Die Abkürzung steht nämlich für RETURN FROM SUBROUTINE". In unserem Fall, wird das Programm beendet und wir bekommen unseren Cursor wieder. Falls ihr den Befehl vergesst, kann euer Rechner auf die übelste Art und Weise Abstürzen!

    Alles verstanden? Bei fragen, posten! Besorgt euch mal den Turbo Ass und tippert mal los. Spielt etwas herum.

    BSP:

    * = 4096

    LDA #15
    STA 53280
    LDA #11
    STA 53281
    RTS

    Ihr braucht aber nicht folgendes versuchen wie:

    * = 4096

    LDA #1
    STA 53280
    STA 53281

    LDA #2
    STA 53280
    STA 53281

    LDA #3
    STA 53280
    STA 53281

    LDA #4
    STA 53280
    STA 53281
    RTS

    Ihr werdet immer nur Lila sehen :) Die Umschaltung passiert so schnell, das man davon nichts sieht. Na dann viel Spass, und verdaut die ersten Schritte. Eure Erfolge könnt ihr ruhig mitteilen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von biguser ()

  • mann biguser, Respekt vor Deinem kleinen Crashkurs hier, genau sowas hat mir vor ca. einem Jahr gefehlt, als ich anfing Assembler zu lernen und mühseluig Informationsschnipsel aus dem Netz gefiltert habe... Weiter so! Und an alle die lernen wollen: Es ist echt nicht besonders schwer, bringt's aber dafür wahnsinnig und es lohnt sich einfach. Also dranbleiben!
    Einen kleinen Fehler hab ich noch entdeckt: RTS steht für Return FROM subroutine, nicht TO subroutine. Diese Anweisung beendet also ein Unterprogramm, und ein von BASIC mit SYS aufgerufenes Maschinenprogramm ist eben ein solches, welches damit beendet wird. Auf gut deustch: Programmende, Kontrolle zurück an den BASIC Interpreter.
  • Respekt, Respekt.. das hab sogar ich verstanden :D
    Ich habe auf meinem SX ein wenig rumgehackt, wenn mans richtig anstellt, sehen die farbwechel aus wie diese Ladeprogramme Tape/Disk.. :)

    Mach nur weiter so, biguser.. ich warte auf die nächste Lektion :D

    @schergentoni:

    Eigentlich reizt mich beides irgendwie. Währe nett, wenn du mir was schicken würdest.

    Bis dann, ...... ritti ;)
    Server-Uptime:
  • Hey, diese Einführung ist echt gut, weil verständlich.
    Ich habe auch noch nie Assembler programmiert, habe aber aus Neugier schon ein oder mehrere ähnliche Anfängerkurse im Internet angelesen. Und das hier ist auf jeden Fall einer der Besten. Bin schon gespannt wie das hier weitergeht! :]

    Eine Frage hab ich aber schon:

    Wieso muss man in Assembler eigentlich die Speicherzellen immer über den Akku beschreiben, wieso geht das nicht direkt wie bei BASIC (POKE)?
    Zusammen können wir's schaffen! ;) C64-Wiki
  • Oh, Mann, wow! Da poste ich mal eine simple Frage nichtsahnend hier hin und es schlägt eine riesen Welle! :) Nein, ernsthaft: ich bin echt baff! Ich lade mir das alles mal schnell runter, inkl. dieser Seite hier und wenn ich zuhause bin, setze ich mich dran ein bißchen zu coden! Eine Einführung in Assembler - ich fass es nicht!

    Vor einiger Zeit hab ich mir mal aufm Flohmarkt das große C64 Buch gekauft und mich dann kurz mit dem Kapitel "auch Assembler ist nicht schwer" beschäftigt - aber auch nur ein paar Minuten. Man wird einfach überrannt :( Das hier ist aber super!

    Danke Biguser! :freude

    Aber um noch mal kurz auf mein eigentliches Anliegen zu kommen: ich hab mich vielleicht ein wenig zu übermütig und mißverständlich ausgedrückt. Smooth Scrolling wie ich es von Intros kenne etc. erwarte ich auch nicht vom Basic. Aber eben ein wenig mehr als daß ein Programm es gerade so schafft, jeden Buchstaben einer Zeile einzeln zu verschieben, so daß es aussieht als würde alle paar Sekunden jemand hektisch an der Zeile zerren ... :baby: ...Ihr versteht?

    Unabhängig davon aber nochmal: danke! Weiter so, bitte.
    Greetings, Starfighter. You have been recruited by the Star League to defend the frontier against Xur and the Ko-Dan armada.


    Kilobyte Magazine - The PDF-Mag for everything 8bit
    KBMag on Twitter
    KBMag on Facebook
  • Original von Pohli
    Wieso muss man in Assembler eigentlich die Speicherzellen immer über den Akku beschreiben, wieso geht das nicht direkt wie bei BASIC (POKE)?


    Moin!

    Muß man nicht. Es gibt schließlich noch die beiden Register X und Y. Mit LDX wird ein Wert ins X-Register geladen und mit STX in einen beliebigen Speicherbereich geschrieben. Mit LDY und STY genauso. Die X- und Y-Register werden aber meistens als Zähler bzw. Index verwendet die mit INX / INY und DEX / DEY manipuliert werden können. Außerdem gelten für's Laden und Speichern dieser Register etwas andere Regeln. LDX ($1300),Y geht zum Beispiel nicht. Der Akkumulator kann auch nicht als Zähler bzw. Index verwendet werden. Es sei denn man transferiert den Inhalt des Akku's in eines der beiden anderen Register (TAX, TAY). Das geht auch umgekehrt (TXA, TYA).

    BigUser kann das bestimmt besser erklären als ich. Ich habe seit langem nicht mehr Assembler gecodet.

    mfg

    Metalmorphosis
    Du glaubst, Du bist frei?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Metalmorphosis ()

  • Original von PohliWieso muss man in Assembler eigentlich die Speicherzellen immer über den Akku beschreiben, wieso geht das nicht direkt wie bei BASIC (POKE)?


    "nicht direkt" ist der falsche begriff. das ist eine rein syntaktische sache. daher darf man diese vergleiche nicht machen. basic hat halt andere befehle.

    der poke-befehl verlangt eine adresse und einen wert, der in diese adresse soll.
    das ist eben die basic-syntax.

    in asm sieht die syntax anders aus, daher auch eine andere befehlsfolge.
    der wert wird in den akkumulator geladen (oder x- oder y-register), und der wert, der im entsprechen register geladen ist, kann in eine speicherstelle geschrieben ( "gepoked" ) werden.

    also:

    lda #wert
    sta adresse


    wie gesagt, du darfst basic nicht mit asm vergleichen, weil die sprachen unterschiedliche syntax(en?) haben. genauso, wie sich c von turbopascal von basic von php unterscheidet usw.
  • a propos "poken": Leute, setzt euch kurz vor euren C64, haltet inne und macht den lezten Poke eures Lebens, denn wenn ihr das erste mal diese "Pokerei" in ML macht, werdet ihr garantiert nie wieder einen Poke benutzen ;)
    Bestes Beispiel zur Geschwindigkeitsdemonstration:

    ldy #$00
    lda #$2a ;screencode für "*", dezimal 42
    loop sta $0400,y ;store akku an Adresse $0400 plus Wert im y-Rehgister ($0400=1024 dezimal)
    sta $0500,y ;usw...
    sta $0600,y
    sta $0700,y
    iny ;erhöhe Wert im Y-Register um 1 (Inkrementieren)
    bne loop ;verzweige nach "loop" falls y-reg. ungleich null, heisst durchlaufe y von 0-255, dann kommt nämlich wieder die Null bei der nächsten iny-Anweisung
    rts

    Diese Routine entspricht der BASIC-Zeile: for i = 0to1000:poke1024+i,42:next und füllt also den Bildschirmspeicher mal eben mit Sternchen. Die Assemblerversion ist zwar im Quellcode um einiges länger aber schaut mal auf die Uhr dabei: das ganze dauert nicht mal so lange bis ihr den Finger von der Returntaste wieder runter habt. Und nun versucht mal das gleiche in BASIC ;) Unter 10 Sekunden schafft man es nicht.

    und übrigens: Allen Wissbegierigen möchte ich noch mal den Link zu meiner hp geben, wo ich auch ein bisschen was zum Einstieg zusammengeschrieben habe: people.freenet.de/hannenz
  • ich fand in diesem zusammenhang die speicheradressen an sich noch ganz interessant, weil selbst mir damit auch endgültig klar wurde (vermutet hatte ich es ja immerhin), was hinter 53280 und 53281 steckt. ein dokument dazu findet sich hier:

    asm.daper.net/asm/documentation/64map10.zip

    ich muss aber vielleicht dazu sagen, dass ich vom cevi bisher nicht allzu viel ahnung habe und mir alles irgendwie zusammenklaube. wobei ich zu meiner kiste noch nicht mal ein handbuch habe (vielleicht kann auch wer mal kurz die "farbnummern" hier posten). aber, biguser, du machst das super. ich hoffe wir halten alle noch eine ganze weile durch!


    ciao,

    villain
  • Hannenz hat gut aufgepasst und einen kleinen Fehler gefunden. RTS heißt natürlich RETURN FROM SUBROUTINE. Ich hab diesen Fehler im zweiten Teil korrigiert. Gut aufgepasst!

    Mich freut es zu hören, das die Basic geweihten meine Assembler Erklärungen gut verstanden haben. Das macht Mut, und legen gleich nach.

    Fragen:
    @Pohli:
    Du würdest also gerne einen Befehl haben, der so aufgebaut ist wie der Basic Poke.
    Quasie: POKE ADRESSE,WERT
    Ein entsprechender Assemblerbefehl könnte so aussehen:
    STA ADRESSE,WERT

    Leider gibt es diesen nicht im 6502 Befehlssatz (auch nicht im 65816). Du fragst dich, wie dann das Basic das macht? Grob erklärt: Der Basicinterpreter prüft Intern den Befehl POKE, und weiß das hinter dem Befehl eine Adresse und danach ein Wert kommt. Der Interpreter macht tausend sachen und baut aus dem Poke ein LDA, in den der Wert geladen wird, und speichert dann gefolgt von einem STA in die geforderte Adresse. Wie du siehst, kommt am Ende eine LDA & STA Sequenz heraus, wenn du einen Poke benutzt.

    Ich habe heute in 2 Minuten eine kleine Scrollroutine fertig geschrieben, die 55 Bytes gross ist. Diese sollte am Ende des kleinen Kurses, ganz oder teilweise verstanden werden. Aber bis wir uns davon erste Codebrocken anschauen, müssen wir noch ein paar andere dinge lernen.

    Wir wissen nun, wie wir Werte in den Akku laden, und an andere Stellen in den Speichern schreiben können. Das ist doch schonmal was! Als heutige Aufgaben trauen wir uns an eine Routine, welche die ersten 40 Spalten des Textscreens mit einem "A" füllt. In Basic würde unsere Umsetzung so aussehen, wenn diese Assembler nah geschrieben wäre.

    1 A=1 : REM Buchstabe A hat den Screencode 1.
    2 X=0
    3 Poke 1024+X,A
    4 X=X+1
    5 IF X<>40 then 3
    6 end

    Wie wir sehen, steckt im heutigen Teil eine Bedingung und eine neue Variable "X".

    Die Variable A in Zeile 1 steht wieder für unseren Akku. Diesen befüllen wir mit einer 1, doch nun soll noch ein zweiter Wert geladen werden. Wenn wir diesen auch gleich in den Akku laden, ist unsere 1 wieder futsch. Um dieses Problem zu lösen, holen wir einfach einen Kollegen von LDA heran. Dieser nennt sich LDX. Der Vollständigkeit halber erwähne ich schnell, das es noch einen gibt, und zwar LDY, das wir heute aber nicht brauchen.
    Wenn jemand sagt,
    ich lade etwas in den Akku, dann meint er - LDA #xx
    ich lade etwas ins X-Register, dann meint er - LDX #xx
    ich lade etwas ins Y-Register, dann meint er - LDY #xx

    Den Akku kennen wir ja schon. Das X-Register und Y-Register sind neu für uns. Was ist an denen anders?
    Gar nichts! Es sind auch 1 Byte grosse Speicherzellen, genau wie der Akku. Auch hier könnt ihr Werte von 0 bis 255 laden. Aber wie speichert man diese X & Y Register Werte in andere Speicherzellen? Die Lösung wird euch schon auf der Zunge liegen. Natürlich mit einem STX & STY Befehl, die ebenfalls sehr Identisch mit dem STA sind.
    Um nochmal auf unser kleines Hintergrundfarben Programm zu kommen, könnten wir es jetzt so schreiben:

    * = 4096

    LDX #10
    LDY #2
    STX 53280
    STY 53281
    RTS

    Wir sind nun in der Lage, gleich mehrere Werte zu laden, und diese dann hintereinander zu speichern. Vorher mussten wir immer einen Wert laden, dann speichern, dann wieder laden, dann nochmal speichern. Wir haben somit 3 Variablen zur Verfügung (AKKU, X-REG, Y-REG). Mehr gibt es leider nicht und wir müssen damit leben.

    Zusammengefasst kennen wir nun schon ganze 6 Befehle des 6502 Befehlssatzes:
    LDA - load Akku STA - store Akku
    LDX - load X-Reg STX - store X-Reg
    LDY - load Y-Reg STY - store Y-Reg

    Aber die reichen noch nicht aus, um das obige Basic Programm umzusetzen. Zeile 1 & 2 könnten wir problemlos in Assembler hinbekommen. Zeile 3 wird nun etwas kniffelig. Hier wird auf die Adresse 1024, die X Variable addiert, in welche dann Variable A geschrieben wird. Wie geht nun sowas in Assembler? Des Rätselslösung ist nicht schwer. Wie wir wissen, sollen wir den Wert von Variable A in eine Speicherzelle schreiben. Also handelt es sich schonmal um den "STA" Befehl. Doch leider reicht ein einfaches STA 1024 (STA Adresse) nicht aus. Wir wollen das X unsere Adresse beeinflusst. Der korrekte Befehl lautet: STA 1024,X
    Das ganze nennt sich "Absolut X Indiziert". Boah!

    Ein "STA 1024,X" ist also das gleiche wie ein POKE 1024+X,A. Interessant nicht war?
    Prüfen wir diese Erkenntniss doch einfach mal in der Praxis mit folgendem Beispielcode.

    * = 4096

    LDA #1 (1=Screencode für Buchstaben A)
    LDX #0
    STA 1024,X
    RTS

    So. Starten wir das ganze und sehen ganz oben in der linken Ecke ein "A" stehen, denn ab der Adresse 1024 fängt Standardmässig der Screenram an, der 1000 Bytes weiter endet. Da X=0 ist, wird null zu 1024 addiert. ALso ändert sich an der Adresse nichts.

    Versuchen wir nun, das "A" eine Spalte weiter darzustellen in Adresse 1025. Wir fassen aber den STA Befehl nicht an, und ändern nur den LDX #0 auf ein LDX #1 um. Unser Beispiel Code sieht dann so aus:

    * = 4096

    LDA #1 (1=Screencode für Buchstaben A)
    LDX #1
    STA 1024,X
    RTS

    Und tatsächlich ist das "A" um eine Spalte weiter gerückt. Also es funktioniert! Auf diese Weise kommen wir 255 Spalten weit, da unser X-Register nicht größere Werte annehmen kann! Schlaumeier würden jetzt vielleicht auf die Idee kommen, das Y-Register auch noch anzuhängen, aber solch einen Befehl gibt es nicht. Also ein STA Adresse,x,y steht nicht im 6502 Angebot. Basic Zeile 3 haben wir abgehakt und easy kapiert.

    Zeile 4 ist wieder ein neuer Assembler Befehl. Diesmal einer der ganz leichten. Im Basic Part haben wir hier ein: X=X+1 zu stehen, und wie der Zufall so will, gibt es genau dafür einen 1 Byte grossen ASS Befehl Namens: "INX". Was versteckt sich diesmal hinter der Abkürzung? "IN" steht für Inkrement, was nichts anderes bedeutet wie: Erhöhe! Das X in "inX" bezieht sich auf das X-Register. Der Befehl erhöht einfach den aktuell im X-Register befindlichen Wert im 1. Wer meint, das sowas auch für das Y-Register geben muss, liegt richtig! Ein INY existiert tatsächlich! Nun könnte man fast schon annehmen, das es sowas auch für den Akku gibt, aber leider enttäuscht uns hier der 6502 Befehlssatz. Ein "INA" finden wir nicht. Damit müssen wir leben, oder einen 65816 Prozessor (SuperCPU/COne) anschaffen. Dort gibt es jenen vermissten Befehl.
    Testen wir das doch mal wieder etwas aus:

    * = 4096

    LDX #0 ; Farbwert Schwarz
    STX 53280 ; als Rahmenfarbe setzen
    INX ; erhöht X um 1
    STX 53281 ; als Hintergrundfarbe setzen
    RTS

    Ich glaube das ganze benötigt keine weitere Erklärung. Also Basic Zeile 4 haben wir auch durchgekaut.



    Für Basic Zeile 5 müssen wir zwei neue Assemblerbefehle lernen. Zum besseren Verständnis, trennen wir mal die Basic Zeile in "WENN" UND "DANN". Es sind ja streng genommen zwei Aktionen. Einmal einen Vergleich durchführen (Wenn), und dann etwas tun, wenn diese erfüllt, oder nicht erfüllt wurde (Dann). Genauso ist das auch in Assembler. Wir benötigen also als erstes einen Befehl, mit dem wir unser X-Register auf #40 (40 Zeichen = 1 Bildschirmzeile) prüfen könnten. Da drängt sich der Befehl: "CPX" förmlich auf! Wie immer, nehmen wir die Abkürzung auseinander und schauen was genau dahinter steckt. "CP" steht für "Compare". Also ein Vergleichsbefehl. Das "X" steht natürlich wieder für den Register, der verglichen werden soll. Ich erwähne hier noch schnell, das auch der CPX, zwei Brüder hat. Und zwar gibt es zum einen noch "CPY" zum prüfen des Y-Registers, und "CMP" zum prüfen des Akkus. Das der Prüfbefehl für den Akku nicht, wie vielleicht angenommen, CPA sondern CMP heißt, müssen wir leider so akzeptieren!
    Wie bereiten wir nun den Prozessor auf eine Prüfung auf X = 40 genau vor?
    Mit einem: CPX #40 (<direkt, daher mit # davor).
    Vergleiche ob X Register gleich 40 ist. Er hat also nun verglichen, aber wo läßt er das Ergebniss seines Vergleichs? Das kann doch nicht weg sein! Irgendwo muss diese Information geblieben sein. Diese Compare Befehle haben eine tolle Eigenschaft. Sie
    setzen je nach Vergleichsergebnis, ein FLAG im Status Register. Um genau zu sein, das ZERO Flag in unserem Fall. Oh Gott werdet ihr jetzt denken, aber das ist ganz einfach. Man muss sich das Statusregister so vorstellen, das 7 Leute auf einem Tisch stehen und Fahnen in der Hand halten, die sie hoch (gesetzt) unter runter (gelöscht) halten. Eine Fahne davon ist für unseren nachfolgenden Sprungbefehl wichtig. Die Fahne, auf die wir später prüfen, heißt ZERO. Der Typ, der die ZERO Fahne hält, ist so cool drauf und hebt sie immer dann, wenn die beiden Zahlen auf die geprüft werden soll, Identisch sind. Angenommen X = 10, und wir prüfen X mit einem CPX #40. Tja, aber X ist nicht 40, sondern 10. Somit bleibt die ZERO Fahne unten (ZERO Flag gelöscht). Wenn X = 40 ist, und es wird auf 40 verglichen, dann hebt sich die ZERO Fahne. Das ZERO Flag ist gesetzt. Die Flags bleiben solange unverändert, bis wieder ein Befehl kommt, der sich darauf auswirkt. Hier ist eine Befehlsübersicht und ihre Einflüsse auf das Statusregister ratsam. Wir wissen nun, das Vergleichsbefehle die Flags im Statusregister setzen oder löschen, je nach Vergleichsergebnis. Auf diese gesetzten Flags, kann man mit BRANCH Befehle (=Verzweig Befehle) reagieren.

    (Weiter gehts im nächsten Posting, da ein Posting nicht länger wie 10000 Chars lang sein Darf :)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von biguser ()

  • Branchbefehle gibt es in Assembler einige (glaube 8 ). Den wir aber brauchen, nennt sich "BNE"! Das Kürzel steht für "BRANCH IF NOT EQUAL TO ZERO". Verzweige, wenn das Zero-flag ZERO (gelöscht) ist. Wenn das Zero Flag gelöscht ist, vollführt der BNE Befehl einen Sprung an eine vom Coder vorgegebene Stelle. Ist das Zero Flag gesetzt, dann springt er nicht und das Programm läuft unter dem BNE einfach weiter. In Basic würde man nun zu einer bestimmten Basic Zeile springen. In Assembler macht man das so ähnlich. Man gibt der Zeile auf die gesprungen werden soll einen Namen. Das ganze wird auch "LABELS". genannt. Diese Sprungnamen die man vergibt, dürfen aber nur einmal im gesamten Sourcecode vorkommen. Man darf nicht fünf mal "testjump" vergeben. Auf welchen sollte denn da gesprungen werden? Das ganze muss natürlich eindeutig sein. Wenn man öfters den gleichen begriff benutzen will, hängt man einfach eine Zahl an. Wie "testjump1" oder "testjump2"...


    Wie setze ich nun solch ein Label im Turbo Ass ein? Ganz einfach. Tippt einfach euren Begriff den ihr als Sprungnamen nehmen möchtet ein, und er wird ganz links vom Turbo Ass positioniert. Macht ihn aber nicht zu lang! Kurz und eindeutig ist die beste Wahl!
    Machen wir einen kleinen Sprungtest in der Praxis.

    * = 4096
    LDA # 1
    LDX # 10 ; X=10
    CPX # 40 ; Ist X=40? (nein, also Zeroflag gelöscht)
    BNE testjump ;wenn Zeroflag gelöscht, dann springt zu LABEL: testjump
    STA 53280
    testjump RTS

    Wenn wir dieses Programm ausführen, könnte man denken es ist nichts passiert! Da 10 einfach nicht 40 ist, bleibt das Zero Flag gelöscht, und der BNE überspringt unseren STA 53280, zum setzen der Farbe weiss!

    Dann machen wir es mal so, das unser Ergebniss stimmt.

    * = 4096
    LDA # 1
    LDX # 40 ; X=40
    CPX # 40 ; Ist X=40? (ja, also Zeroflag gesetzt)
    BNE testjump ;wenn Zeroflag gesetzt, dann wird nicht gesprungen, sondern einfach unterm BNE weitergemacht.
    STA 53280
    testjump RTS

    Cool, der Rahmen wird weiß!
    Als Beispielübung, könnten wir auch dieses Listing eintippen.

    * = 4096
    LDA # 1
    LDX # 39 ; X=39
    INX ; X=X+1 ; X ist jetzt 40
    CPX # 40 ; Ist X=40? (ja, also Zeroflag gesetzt)
    BNE testjump ;wenn Zeroflag gesetzt, dann wird nicht gesprungen, sondern einfach unterm BNE weitergemacht.
    STA 53280
    testjump RTS


    WOW! Nun sind wir in der Lage, das obige Basic Programm umzusetzen... aber ihr könntet euch daran mal selbst versuchen.

    Schaut euch genau das Basic Programm an, und versucht mit den gelernten ASS Befehlen es umzusetzen. Erfahrene Assembler Coder sollten hier aber nicht mit Wissen protzen und schnell die Lösung der Aufgabe posten, aber die Basic Coder die hier mitmachen, können gerne ihre Umsetzung ins Board stellen. Mal schaun wer am schnellsten ist. Falls es bis morgen Abend keiner geschafft hat, gebe ich dann die Auflösung bekannt.

    So, wer jetzt noch nicht eingeschlafen oder verzweifelt vorm Rechner sitzt, hat gute Chancen in einem Jahr sein erstes kleines Mega-Demo zu Coden!

    Übrigens, Hannenz!
    Deine Screen-Füllroutine zersägt auch die Spritepointer. Der Screen hört bei $07e7 auf, du schreibst aber fleissig bis $07ff weiter. Verschenkte Rechenzeit :) Aber gutes Beispiel, das in Ansätzen die Lösung zu unserer Aufgabe enthält.
    Die Scrollroutine ist nicht mehr Weit !!!

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von biguser ()

  • Wow, irgendjemand muß hier den richtigen Knopf gedrückt haben... :))

    @ biguser: Ich kann mich den Gratulationen nur anschließen! Ich sehe hier schon ein großartiges Assembler-Tutorial heranwachsen, das Du dann auch an eine feste Stelle im Netz stellen solltest!

    @ finchy: Möglicherweise verstehe ich die Frage nicht richtig. Wenn es Dir darum geht, mit einfachem Basic einen Text in einer Zeile von links nach rechts oder von rechts nach links laufen zu lassen, hätte ich folgenden Vorschlag:

    10 A$="LAUFTEXT"
    20 L$="                                         ": REM 40*LEERZEICHEN
    30 Z=10: REM ZEILE
    40 FOR I=1 TO 39+LEN(A$)
    50 POKE 214,Z: POKE 211,0: SYS 58640
    60 PRINT MID$(L$+A$+L$,I,40);
    70 FOR J=1 TO 50: NEXT J: REM VERZOEGERUNG
    80 NEXT I
    90 GOTO40


    (Um die Richtung umzukehren, muß nur der Loop mit i umgedreht werden)

    In einem "C64 Tips, Tricks & Tools"-Buch, das ich irgendwo habe, sind auch ein paar recht eindrucksvolle Einzeiler zum Scrollen in Basic. Das will ich jetzt nicht mehr raussuchen, aber bei Bedarf sehe ich gerne nach.

    @ villain: mein Favorit bezüglich Speicherbelegung ist MAPPING the Commodore 64 (.zip)
  • @biguser: ja, das mit den Spritepointern ist schon klar, aber der Einfachheit halber und zur Demonstration tuts die Routine, denk ich, vollauf ;). Will man natürlich bei einer solchen Routine den Berich $07f8-$07ff (2040-2047) schützen, müsste man sich ein bisschen was anderes ausdenken, z.B. mit den eben erlernten Vergleichsbefehlen arbeiten. Mal schauen wer der Klassenstreber ist und neben bigusers Hausaufgabe noch meine Routine umschreibt, die den besagten Bereich nicht überschreibt :) Viel Spass und nochmal mächtige 5 Kilo Rehspeck an Biguser für diesen einmaligen Asskurs, ich verfolge in selbst mit höchster Spannung und man lernt ja schliesslich auch nie aus!
  • Hi,

    ich bin hin und weg, bigusers Crashkurs topt an Einfachheit und Verständlichkeit alles, was ich bisher gelesen habe.
    Absoluter :respect:

    Ich glaube aber, hier ist ein kleiner Fehler in der Beschreibung:
    Wenn das Zero Flag gelöscht ist, vollführt der BNE Befehl einen Sprung an eine vom Coder vorgegebene Stelle. Ist das Zero Flag gelöscht, dann springt er nicht und das Programm läuft unter dem BNE einfach weiter

    Sollte das nicht heißen: Wenn das ZERO-Flag gelöscht ist, vollführt der BNE Befehl einen Sprung an eine vom Coder vorgegebene Stelle. Ist das ZERO-Flag gesetzt , dann springt er nicht und das Programm läuft unter dem BNE einfach weiter...

    So, und nun setze ich mich mal hin und schreibe eine Zeilenfüllroutine in Assembler :D
    Cool, vielleicht vertiefe ich mich nach 10 Jahren Abstinenz doch noch mal in Ass... *grins*
    Nochmals vielen Dank, biguser und weiter so.
    Gruß,
    Neefi.
    -------------------------------
    neef-online.de

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Neefi ()