OT: Neue C64 ASM/Basic Compo : Dreh' das Sprite [Alternative Systeme]

  • Und hier noch ein Beispiel auf die Schnelle in Loco Basic.

    20x20 Pixel Fantasie Bitmap gedreht.

    Die Verzerrung kommt durch mode 2 wo ja auch das 8x8 Zeichen Raster hochkant aussieht obwohl es quadratisch ist.

    Das Gute an Basic ist, dass ich mich hier wirklich nicht um den Hardware Aufbau des Screen RAM scheren muss.

    Es ist sozusagen das gedrehte Mühle Spiel von dem ich gesprochen habe.
    Bilder
    • drehcpc.JPG

      9,62 kB, 768×540, 9 mal angesehen
  • so oobdoo nu hast du die ersten 8x8bit richtig gedreht. nun nimmst du dieses und aenderst 1.das offset der zu drehenden bytes. 2. die zielbits.

    ich verstehe ehrlich gesagt nicht wo das problem liegt der Z80 bringt alles mit was der 6502/10 auch mitbringt. rol ror is das
    stichwort und natuerlich das carry flag. der Z80 hatt sogar noch mehr bitshifting/rolling optionen soweit ich das von hier
    jgmalcolm.com/z80/advanced/shif.htm aus beobachten kann.

    wenn das dann laeuft kann man sich gedanken um andrer loesungen machen.

    also oobdoo jetzt bitte ma butter bei die fische ;D

    hier mal mein versuch einer 1:1 uebersetzt von 6502/10 asm zu Z80 asm, ungetestet da ich kein Z80 fachmann bin.
    dabei geh ich davon aus das der spicher bei C genullt ist

    Quellcode

    1. 1: copy orginal to a helper memory
    2. 2: B=helper memory
    3. 3: C=rotated Memory
    4. ld b,#60
    5. l:
    6. - ld c,#60
    7. rl b+0
    8. rl b+1
    9. rl b+2
    10. rr c+2
    11. rr c+1
    12. rr c+0
    13. dec c
    14. dec c
    15. dec c
    16. jmp if positive to -
    17. dec b
    18. dec b
    19. dec b
    20. jump if positive to l:
    Alles anzeigen
    sicher das funkt nur in den ersten 256 bytes aber das schema sollte ungefaehr klar sein(hoffe ich).

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von Haubitze ()

  • Da ich glaube, dass die CPC Lösung mit der C64 Compo eigentlich zu wenig zu tun hat, auch vom Konzept her, finde ich kann ich die CPC Lösung hier auch vor Compo-Ende posten, und zwar als dsk Datei, die man selber laden muss und den Inhalt selber listen. Das ist denke ich genug "Kopierschutz" und der Inhalt hat wie gesagt mit der C64 Compo zu wenig zu tun als dass man Rückschlüsse ziehen könnte wie man am C64 ein Sprite gemäß Compo Regeln dreht.

    Gestartet wird mit run"dreh

    Menupunkt 1 zeigt die "toten" 48 Byte-Blöcke im Screen RAM, die immer direkt hinter dem letzen Byte des sichtbaren Bildschirmbereichs beginnen und sich alle 2000 Bytes wiederholen.

    Menupunkt 2 füllt den Bildschirm byteweise mit $ff. Immer ein weiteres Byte pro Tastendruck. Man erkennt gut das zeilenweise füllen mit "Zeilensprung". Immer wenn man unten angekommen ist, bemerkt man, dass das Füllen 48 Drücke lang nicht weitergeht, weil man wieder einen "toten Bereich" erwischt hat.

    Menupunkt 3 zeigt das Setzen einzelner Bits von links nach rechts mit jedem Tastendruck. Hier verhält sich der CPC in Mode 2 (HighRes) ähnlich wie ein C64 Sprite.

    Menupunkt 4 gibt das Dreh-Experiment in Post 42 wieder. Es wird dabei zuerst ein Data-Bereich ausgelesen und geplottet. Der Data-Bereich enthält die zu setzende Farbe, das Plotten selbst passiert per doppelter For-Next-Schleife. Dann wird mit Restore der Data-Bereich zurückgesetzt und der Data-Bereich erneut in ein Array eingelesen. Während des Einlesens wird bereits gedreht, so dass die Farbdaten am Ende "gedreht" im Array stehen. Das Array wird dann im Grunde genauso geplottet wie davor die Datas. Das "Drehen" erfolgt nach dem Prinzip "gedrehtes Mühlespiel" oder auch "um 90 Grad gedrehtes Opatkono-Spielfeld". Haubitze dreht um 180 Grad, das ist der einzige Unterschied. Hier braucht man kein AND,OR oder ROL. Es ist nur Umplatzieren von Steinen.

    In Assembler sieht das Ganze beim CPC völlig anders aus und da bin ich auch völlig überfragt. Nur muss man da eben die Hardware etwas stärker im Blick haben als in Basic, was ja bei oobdoo der Fall zu sein scheint. Vielleicht kann man am Ende mit MJs Hilfe eine ASM-Lösung hier posten. Ich selber bin da noch zu unerfahren, was die Hardware und den Z80 angeht.
    Bilder
    • 01.JPG

      22,56 kB, 768×540, 2 mal angesehen
    • 02.JPG

      37,61 kB, 768×540, 2 mal angesehen
    • 03.JPG

      45,53 kB, 768×540, 4 mal angesehen
    • 04.JPG

      7,38 kB, 768×540, 3 mal angesehen
    • 05.JPG

      8,37 kB, 768×540, 3 mal angesehen
    Dateien
    • dreh.dsk

      (194,82 kB, 1 mal heruntergeladen, zuletzt: )
  • oobdoo schrieb:

    Da ist es besser auf ne weitere Lösung von M.J. zu warten. Der schüttelt Z80 Code mal eben so aus dem Ärmel.
    Seit wann das denn?? Davon weiß ich ja gar nichts... 8|
    Okay, ich hab Dir mal eine Versuchslösung zugeschickt. Verglichen mit dem 6502 (also mit Header und Ladeadresse) käme sie auf 53 Bytes. Das hat folgende Gründe:
    1.) Ich bin kein Z80-Experte.
    2.) Die Zeiger müssen komplett initialisiert werden.
    3.) Es gibt kein vorhergehendes Löschen der Register in der Form A=X=Y=0.
    4.) Sprünge bezogen auf das Vorzeichen sind 1 Byte länger als beim 6502.
    5.) Man kann mangels Register-indizierter Adressierung nicht so gut mit dem Index tricksen.

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

  • Bytebreaker schrieb:

    Gestartet wird mit run"dreh
    Das schaue ich mir erst an wenn die Compo vorbei ist.

    Bytebreaker schrieb:

    Ich selber bin da noch zu unerfahren, was die Hardware und den Z80 angeht.
    Nö, das sehe ich anders. Du hast doch schon mehrfach bewiesen das Du den Aufbau vom Bildschirmspeicher verstanden hast.

    M. J. schrieb:

    oobdoo schrieb:

    Da ist es besser auf ne weitere Lösung von M.J. zu warten. Der schüttelt Z80 Code mal eben so aus dem Ärmel.
    Seit wann das denn?? Davon weiß ich ja gar nichts... 8| Okay, ich hab Dir mal eine Versuchslösung zugeschickt. Verglichen mit dem 6502 (also mit Header und Ladeadresse) käme sie auf 53 Bytes. Das hat folgende Gründe:
    1.) Ich bin kein Z80-Experte.
    :blah!

    Natürlich bist Du Experte. Und sag nicht das wäre anders. Das hast Du schon mehrfach hier im Forum bewiesen. ;)

    Wie schon in der Mail geschrieben, werde ich da erst reinschauen, wenn die Compo zuende ist. Noch ist mein kleiner Ehrgeiz nicht ganz verschwunden.
    Zumindest alleine hinbekommen wollte ich das schon, ohne auf die Größe zu achten.
    Mitwäre das nicht passiert! :prof:
    :syshack: Meine 3D-Drucker Teile auf thingiverse.com/oobdoo/designs :strom:
    Sammlung | 91 Bücher bzw. 25.261 Buchseiten mit Z80/8080 Power
  • Ich freue mich auf die CPC Versionen von oobdoo und MJ. Oder es wird eine gemeinsame Version.

    Der CPC ist ein feines Gerät. Gerade heute habe ich ein Mathe Buch für den CPC unverhofft ersteigert. Eigentlich total rar so etwas.

    Ist jetzt zwar etwas OT, musste ich mir aber von der Seele reden. :D
  • Hab mich über die 6809-Version her gemacht. Hab mich an meiner Version und an jener von Gewinner Acorn orientiert und versucht das mit all der "dirtyness" hinzubekommen. Ich hab eine 6809-Simulationsumgebung mit der ich auch für einen Dragon 32 programmiere.
    Ich hab's aber bislang nur im Simulator probiert bzw. laufen lassen. Das PRG-File das der Assembler generiert ist eingebettet in einer Simulator-Umgebung, die dem PRG vermittelt, es würde in einer BASIC-Umgebung aufgerufen werden, mit den gewissen Randbedingungen, wie sie in der Compo ausgenutzt wurde, so eine Mischung zwischen Dragon 32 ColorBASIC-Umgebung und einem fiktiven C64 (der mit einer 6809-CPU laufen würde).

    Assembler LST-File (hier sieht man den erzeugten Code und die Label-Werte (PRGSIZE!)

    Assembler Source-File

    Ergebnis: Das PRG hätte 48 Bytes (PRGSIZE $30), das sind als 5 Bytes mehr als die Gewinner-Lösung Acorns. Genauso die 3 BASIC-Ende-Bytes eingespart und von gewissen Voraussetzungen der Umgebung in der Zero-Page bzw. Direct-Page (wie es beim 6809 heißt) ausgegangen.

    Trotz gewisser Verwandschaft der 68xx-Linie zum 6502, schafft es auch ein 6809 mit dem komfortableren Befehlsatz nicht, für eine solche Aufgabe ganz so platzsparend zu sein. Oder gerade deswegen eigentlich nicht. :rolleyes: Eine Aufgabe, wo die Werte sich im Bereich <256 Bytes bewegen, da ist der 6502 kaum zu schlagen. Die Aufgabenstellung hat zudem den 6502 so begünstigt, dass man viele Flag-Zustände so nebenbei ausnützen kann.
    Anders beim 6809: Der plagt sich mit seinen 16-Bit-Index-Registern, die man auch mal laden muss, die Adressierungsarten sind mannigfaltig, aber nicht gerade so praktisch bzw. verbrauchen durch zusätzlich Postbytes im Opcode zusätzlich Platz. Schon alleine das CLC oder SEC ist je ein 2-Byte Opcode! Und bei Vergleichen und Substraktion ist die Carry-Bedeutung umgedreht, wodurch sich weniger Nebenwirkungen ausnutzen lassen. Damit gehen etliche Bytes an den 6502 verloren. Ein paar Goodies, wie Autoinkrement oder Subtraktion ohne Carry, Register auf 0 setzen und mehr Registerauswahl können nur den Schaden verkleinern, aber nicht wettmachen.
    Ich bin mit dem 6809 nicht so aufgewachsen, wie mit dem 6502, aber es ist denkbar, dass es noch etwas zum herausholen gibt. Aber die Nähe zur 6502-Lösung lassen für mich vermuten, dass da nicht mehr viel Spielraum ist. :D

    Eine 65816-Version hab ich mir noch nicht eingehend überlegt, aber da kann man m.M.n. nicht mehr viel gewinnen, wenn überhaupt. Die breiteren Register, zusätzliche Bit-Befehle und Adressierungsarten bringen hier überhaupt nichts. Ob STZ noch was bringt? Vielleicht noch eher der doppelte Akku (z.B. tauschen mit XBA) ...

    Hat jemand jetzt eine Z80-Variante?
  • Die 32-Bytes ohne Basiczeile sind schon eine Hausnummer.
    Da der 68K für jeden Befehl 16-Bit benötigt, glaube ich nicht das man damit den 65xx schlagen kann.

    Bin gespannt ob M.J. auf dem Z80 eine kürzere Routine schreiben kann (hat), vor allem da er fast die gleiche Routine mit der selben länge auf dem 65xx geschrieben hat.
  • Acorn schrieb:


    Bin gespannt ob M.J. auf dem Z80 eine kürzere Routine schreiben kann (hat), vor allem da er fast die gleiche Routine mit der selben länge auf dem 65xx geschrieben hat.
    Ich weiß es. :saint:
    Mitwäre das nicht passiert! :prof:
    :syshack: Meine 3D-Drucker Teile auf thingiverse.com/oobdoo/designs :strom:
    Sammlung | 91 Bücher bzw. 25.261 Buchseiten mit Z80/8080 Power
  • JeeK schrieb:

    Das PRG hätte 48 Byte
    Wow! Ihr seid alle wahnsinnig! :D

    oobdoo schrieb:

    M.J. hat eine, die soll er aber selber veröffentlichen.
    Hättest Du ruhig machen können. Hat kein Copyright. ^^

    Acorn schrieb:

    Bin gespannt ob M.J. auf dem Z80 eine kürzere Routine schreiben kann
    Nee, M. J. ist kein Z80-Experte. ^^ Der nachfolgende Code entspricht noch ungefähr einer alten Lösung. Nachteilig war, daß die Initialisierung hinzugenommen werden mußte.

    Quellcode

    1. drehen: ld de, $340 ; Zeiger auf Originaldaten
    2. ld hl, $380 + 60 ; Zeiger auf die unterste Zeile und Spalte links
    3. ?0: ld b, 8 ; Zähler für die 8 Bits pro Spaltenbyte
    4. ?1: push hl ; Zeiger auf unterste Zeile (+ Spalte!) sichern
    5. ?2: ld a, (de) ; Original Spritewert holen
    6. ld c, 9 ; Zähler für 8 Bits des Originalwertes (8 + 1, da einmal zuviel dekrementiert)
    7. inc e ; Erhöhr Zeiger auf Originaldaten
    8. jp P, ?3 ; Liegt der Zeiger bereits über $380 ==> nur noch 0 als Wert laden
    9. xor a ; Akku löschen für E >= $80 (Negativ!)
    10. ?3: dec c ; Bitzähler herunterzählen
    11. jr Z, ?2 ; Bei 0 neues Byte holen
    12. add a ; Shifte Bit nach links ins Carry (RLCA usw. funktionieren auch)
    13. rl (hl) ; übernehme Bit in die Zieldaten
    14. dec l ; Dekrementiere den Zeiger auf die Zieldaten um 3
    15. dec l ; Zeiger := Zeiger - 3
    16. dec l ; Dies setzt den Zeiger auf die nächst höhere Zeile
    17. jp M, ?3 ; Ist der Zeiger über $380 ==> weitermachen, ansonsten Ende der Schleife
    18. ld a, l ; sichere den aktuellen Stand des Zeigers
    19. pop hl ; Zeiger wiederherstellen
    20. djnz ?1 ; Alle 8 Bit der Zieldaten pro Spalte übernommen?
    21. inc l ; Erhöhe den Zeiger der Zieldaten auf die nächste Spalte
    22. inc a ; Erhöhe den alten Wert. Liegt er bei $7f, dann ist alles fertig. ($7f + 1 = $80 ==> kein Sprung)
    23. jp P, ?0 ; 1. Spalte: Wert bei $7d. 2. Spalte: Wert bei $7e. 3. Spalte: Wert bei $7f
    24. ret
    Alles anzeigen
    Ein weiterer Nachteil des Z80 ist, daß ein Sprungbefehl, der auf das Vorzeichen testet, 3 Bytes braucht. Die kurzen Sprungbefehle gibt es nur für C, Z und als unbedingter Sprung. Da ich dies nur recht schnell konvertiert habe, gehe ich davon aus, daß da noch was rauszuholen ist. So habe ich z. B. noch nicht durchgespielt, wie es wäre, wenn man wie beim 6502 den Akkumulator gleichzeitig als Datenpuffer und (unter Einbeziehung des Carry) als Bitzähler verwendet.

    Acorn schrieb:

    Da der 68K für jeden Befehl 16-Bit benötigt, glaube ich nicht das man damit den 65xx schlagen kann.
    Hmm... Interessanter Gedanke. Sollte man mal ausprobieren. Die Sprungbefehle wären ja gleich lang. Auch bei dem Dekrementieren könnte man ein Byte sparen (SUBQ #3, Ax), was man woanders verwenden könnte/müßte. Auch das Laden des Quellbytes dürfte kurz werden (MOVE.B (Ax)+, Dx). Problematisch bei alldem ist jedoch, daß Operationen auf ein Adreßregister keine Auswirkung haben auf CCR, um z. B. gleichzeitig das Vorzeichen des Lowbytes der Adresse zu testen. Daher würde man hier eher auf einen zusätzlichen Zähler ausweichen: SUBQ #1, Dx : BPL weiter : MOVEQ #0.
    Alles in allem könnte es vielleicht gar nicht so viel länger werden, mit Ausnahme der Initialiserung.

    P.S.: Ich sehe gerade, daß es wohl möglich wäre, im Z80-Code noch ein Byte zu sparen:

    Quellcode

    1. bit 7, l ; Ist das Lowbyte der Adresse jetzt $80 ==> kein Sprung
    2. jr Z, ?0
    Man sieht, wenn man sich nicht mehr sklavisch am 6502-Code orientiert, sondern mehr auf den Z80 einläßt, kann man noch besseren Code schreiben. ^^
  • oobdoo schrieb:

    Red nich.
    Übertreib nich. :schande: Am obigen Beispiel kann man ja schon ablesen, wie ich mich selber korrigieren mußte. ^^

    Acorn schrieb:

    vor allem da er fast die gleiche Routine mit der selben länge auf dem 65xx geschrieben hat.
    Das fand ich bei der letzten Compo besonders faszinierend: daß zwei Leute tatsächlich die gleiche Lösung hatten. Ich weiß ja nicht, wie das bei Dir war, ob Du sofort beim ersten Mal direkt auf die Lösung gekommen bist, aber ich habe dafür mehrere Schritte gebraucht. Und auch jeden dieser Schritte konnte ich in vergleichbaren Lösungsansätzen der anderen Beiträge wiedererkennen. So war auch der Algorithmus von thrust2600 mit dabei, aber anders als ihm war es mir nicht gelungen, diesen weiter zu optimieren. Nur deswegen hatte ich dann nach weiteren Möglichkeiten gesucht. Das wirft natürlich die Frage auf, ob es vielleicht auch möglich wäre, mit genetischer/evolutionärer Programmierung und viel Rechenpower die Aufgabe zu lösen. ^^
  • utz schrieb:

    Also bei dem Thema kann ich mitreden
    Super Lösung. Hier haben wir mal einen echten Experten. Dies ist wieder ein Beispiel, wie 6502-Denken eine gute Lösung für den Z80 blockiert. Der 6502 kennt ja nur den RTS-Befehl, was zu Folge hat, daß man als 6502-Programmierer nur selten überhaupt auf die Idee kommt, die anderen RET-Befehle einzusetzen.
    Frage: Findest Du vielleicht noch andere Stellen, die man optimieren könnte?
  • oobdoo: Ich guck mir das Ganze normalerweise lieber aus sicherer Entfernung an :D
    Konnt nur grad nicht widerstehen, obwohl M.J. ja erwähnte, das er die Routine nicht weiter optimiert hat.

    M.J.: Ich schau bei Gelegenheit noch mal nach. Bin jetzt aber auch kein Z80-Guru (und eine Vollniete wat 6502 angeht).