Schleife - Denkfehler

  • Schleife - Denkfehler

    Hallo,

    ich wollte eine Schleife programmieren, die von 0 bis 319 zählt.
    Die funktioniert soweit, bis auf x=0 und y=1. Dann wird die Schleife doppelt ausgeführt, weil x dann zuerst den Wert $ff hat.
    Für alle anderen Werte funktioniert sie. Wie könnte man das am elegantesten lösen???

    Quellcode

    1. ldx el
    2. ldy el+1
    3. loop
    4. .
    5. .
    6. .
    7. dex
    8. bne loop
    9. dey
    10. bpl loop
  • Die Eleganz hängt hier auch von den Innereien der Schleife ab und was Du dort mit den Registern anstellst.
    Ist nur die Anzahl der Durchläufe wichtig? Dann zähl doch von 320 bis1, dann kannst Du beide mit bne benutzen.
    Oder zähl von 65536-320 an bis 0 aufwärts.

    Je nach Innereien in der Schleife könntest Du auch grad noch das Problem haben, dass 259, 258, 257, 0, 255, 254... gezählt wird.
    Vollmond war gestern!
  • el ist eine Adresse im Speicher, an der ein Zwei-Byte-Wert steht. Wir sind hier im 6502-Land, nicht im wilden Z80-Westen ;)

    Richtig laufen würde die Schleife mit 'bcs' in beiden Sprungbefehlen. (Oder bin ich jetzt beim Z80 gelandet und es muß bcc sein?)
  • mc71 schrieb:

    el ist eine Adresse im Speicher, an der ein Zwei-Byte-Wert steht.
    Wer soll das wissen, wenns es nicht explizit gesagt wird, was nicht getan wurde.


    mc71 schrieb:

    Wir sind hier im 6502-Land, nicht im wilden Z80-Westen ;)
    Was ist Z80? Ich denke nur in 6502-Sphären, weshalb ich genau so gefragt habe, wie ich es tat.
  • mc71 schrieb:

    el ist eine Adresse im Speicher, an der ein Zwei-Byte-Wert steht. Wir sind hier im 6502-Land, nicht im wilden Z80-Westen ;)

    Richtig laufen würde die Schleife mit 'bcs' in beiden Sprungbefehlen. (Oder bin ich jetzt beim Z80 gelandet und es muß bcc sein?)
    Dec/Inc und die Versionen für X und Y verändern bei Unter- und Überläufen (leider) das Carry nicht. DIr bleiben nur Prüfungen auf (Z)ero und (N)egativ..
    Vollmond war gestern!
  • Ingo schrieb:

    Wie könnte man das am elegantesten lösen???

    Hoogo schrieb:

    zähl von 65536-320 an bis 0 aufwärts.
    Genau so, mit

    Quellcode

    1. loop
    2. [whatever]
    3. INX
    4. BNE loop
    5. INY
    6. BNE loop

    Ingo schrieb:

    Quellcode

    1. ldx el
    2. ldy el+1

    flyppo schrieb:

    Bei el geht man von einer Variablen aus, die z.B. 5 enthält. Dann lädst du x mit 5 und y mit 6.
    Welcher Assembler macht denn sowas?
    Yes, I'm the guy responsible for the ACME cross assembler
  • Die Lösung ist relative einfach anstatt die Routine + Schleife laufen zu lassen, springt man direkt in die Schleife und zählt dann für X = 1 - 64.

    Dann sollte auch 256 kein Problem sein, wo sonst X=0 wäre.

    Hoogo hatte es schon geschrieben, das es mit 1 bis 320 einfacher ist.
  • Acorn schrieb:

    springt man direkt in die Schleife
    Was ist denn der Unterschied zu "springt" man in die Schleife versus "fällt man von oben" in die Schleife? ich kann mir momentan nichts drunter vorstellen ...
    Gesendet über das Bimetall Thermorelais meines Rowenta DW 4015 Dampfbügeleisens
  • Es kann Sinn machen, die Abbruch-Bedingung direkt zu prüfen, und wenn die am Ende der Schleife steht, dann springt man quasi in die Schleife hinein.

    Sowas zum Bleistift (nicht sinnvoll, dient zur Erläuterung):

    Quellcode

    1. lda PARAM1
    2. jmp .LoopCheck
    3. -
    4. ldx PARAM1
    5. lda SOURCE,x
    6. sta TARGET,x
    7. dec PARAM1
    8. .LoopCheck
    9. bne -
  • Aha .. sowas ähnliches wie "WHILE .... DO ..." auf Hochsprachenebene,

    Auch genannt "abweisende Schleife / Schleifenbedingung im Schleifen-Kopf prüfen" , oder?
    Gesendet über das Bimetall Thermorelais meines Rowenta DW 4015 Dampfbügeleisens
  • Um nochmal auf den OP zurückzukommen: das erste Beispiel soll von 0..319 zählen, macht aber schon vom Grundsatz her was anderes, indem von oben her herabgezählt wird. Wenn das schon nicht 1:1 umgesetzt wird (egal ob jetzt nur eine einfache Zählschleife gewollt ist, oder nicht) und dann noch das Verhalten der Flags unklar ist, kann nichts vernünftiges herauskommen.

    Umgekehrt, wenn jetzt *explizit* von 0 ab hoch gezählt werden soll, in X das Lowbyte des Index drinstehen soll, und in Y das Highbyte, fällt das ganze einfach so aus:

    Quellcode

    1. .Init
    2. LDX #$00
    3. LDY #$00
    4. .Body
    5. [... was auch immer mit X und Y gemacht werden soll ...]
    6. .Increment
    7. INX:BNE Compare:INY
    8. .Compare
    9. CPX #$40 ; Low-Byte von 320
    10. BNE Body
    11. CPY #$01 ; High-Byte von 320
    12. BNE Body
    Alles anzeigen
    ... wobei als erstes mit X und dann mit Y verglichen wird, damit letzterer Vergleich nur 2x insgesamt gemacht werden muß.

    Erreicht der Wert 320, dann wird das als Abbruchkriterium hergenommen und die Schleife beendet.

    Sieht zwar nur "straightforward" aus, ist es auch nur, hat aber einen echten Vorteil: es funktioniert!

    Falls beliebige Grenzen gewollt sind, können LDX/LDY/CPX/CPY problemlos Speicheradressen an Stelle von #imm hernehmen.


    ... ich *vermute* ja mal, daß der OP *eigentlich* alle X-Koordinaten eines Grafik-Objekts (z.B. einer Linie) ablaufen und im Body den Bresenham+Punktplot ausführen wollte. Bei so einer Implementierung ist der evtl. empfundene Overhead einer nicht-optimalen (da eben nur "straightforward"en Zählimplementierung) als eher vernachlässigbar zu bewerten. Der Bremsklotz liegt dann woanders. ^^

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

  • Mac Bacon schrieb:

    flyppo schrieb:

    Bei el geht man von einer Variablen aus, die z.B. 5 enthält. Dann lädst du x mit 5 und y mit 6.
    Welcher Assembler macht denn sowas?
    Ich stelle mir diese Frage nicht.

    LDA #$00 -> lädt eine Zahl, hier die Null in de Akku
    LDA $34 -> lädt den Inhalt der Speichezelle $34 in den Akku
    LDA el kenne ich nicht, gibt es nur, wenn ich eine Variable el vorher definiere.

    Aus meiner Kenntnis.
  • Neu

    Ingo schrieb:

    Hallo,

    ich wollte eine Schleife programmieren, die von 0 bis 319 zählt.
    Die funktioniert soweit, bis auf x=0 und y=1. Dann wird die Schleife doppelt ausgeführt, weil x dann zuerst den Wert $ff hat.
    Für alle anderen Werte funktioniert sie. Wie könnte man das am elegantesten lösen???

    Quellcode

    1. ldx el
    2. ldy el+1
    3. loop
    4. .
    5. .
    6. .
    7. dex
    8. bne loop
    9. dey
    10. bpl loop
    Ich bin Assembler-Anfänger und frage mich, ob vor einem bne nicht ein cmp kommen muss?

    DoReCo #54 (3-Tages-Party) 15.-17.09.2017!
  • Neu

    ThomBraxton schrieb:

    Ich bin Assembler-Anfänger und frage mich, ob vor einem bne nicht ein cmp kommen muss?
    Nein, muss nicht. Die Branch-Befehle reagieren auf den aktuellen Zustand der Prozessorflags, egal wovon diese zuletzt beeinflusst wurden.
    CMP beeinflusst die Flags C, Z und N. Etliche andere Instruktionen beeinflussen die Flags aber auch, z.B. LDA/LDX/LDY (Z und N), INX/INY/DEX/DEY (Z und N), PLP (alle), ASL/LSR/ROL/ROR (C, Z, N), ADC/SBC (C, Z, N, V) etc. pp.
    Sieh Dir mal bei einem beliebigen Assemblerkurs die Opcode-Tabelle an, meistens hat die auch eine Spalte für die beeinflussten Flags.
    Yes, I'm the guy responsible for the ACME cross assembler
  • Neu

    Besonders cmp #0 wird gerne vor bne/beq weggelassen, da überflüssig. Das zeigt schon, daß nicht grundsätzlich vor jedem Branch (direkt) ein Compare stehen muss.. Als Asm-Einsteiger würde ich es aber als Kommentar ;cmp vor jeden Branch schreiben :)
    "...please come again - when I´m not working!"
  • Neu

    Von der Logik des Befehlskürzels hast Du recht- branch if equal (bzw. branch if not equal) bezieht sich auf einen vorangehenden compare-Befehl. Andere Prozessoren würden so einen Befehl jump if zero-flag set 'jp z, adresse' nennen. Das ist allgemeingültiger, aber auch weniger übersichtlich. Und wieder andere Prozessoren haben für jede Sprungbedingung gleich mehrere Kürzel, je nachdem man das Ergebnis eines Vergleichs oder einer Berechnung prüft...

    (Ansonsten: Was Mac Bacon sagt...)