Hallo Besucher, der Thread wurde 4,4k mal aufgerufen und enthält 26 Antworten

letzter Beitrag von Fröhn am

bit

  • Hallo erstmal, ich bin der gleiche der schon die Frage zu den Sprite-Kollisionen hatte. Vielen Dank für die Antworten, ich weiß daß ich diesen Dank vielleicht dorthin plazieren hätte müssen, aber die Leute die antworten schauen sich sowieso alles an was neu kommt,oder? Also, meine Frage: Was macht man mit dem Bit-Befehl? Es wird also irgendeine AND-Verknüpfung mit dem Akku durchgeführt und ausserdem kann man das Bit 6 abfragen. Soweit mein Kenntnis?stand. Und was kann man dann praktisch damit anfangen? In sämtlichen Assembler-Kursen oder Büchern wird nur sehr wenig oder garnichts zu diesem Befehl gesagt. Wer kennt sich aus?

  • Ja, also mit dem BIT Befehl alleine kannst du einfach Bit 7 und 6 einer Speicherstelle abfragen, ohne irgendwelche Registerinhalte zu ändern, das kann schon mal ganz nützlich sein. Entsprechend werden für Bit 7 das Negative-Flag und für Bit 6 das Overflow-Flag gesetzt bzw. gelöscht.
    Mit dem BIT Befehl lässt sich aber auch unverschämt tricksen. Schau dir mal folgendes an:


    Code
    1. ...
    2. printa lda #65
    3. .byte $2c
    4. printb lda #66
    5. jsr $ffd2
    6. ...


    Durch das ".byte $2c" ($2c ist der OP-Code für BIT $xxxx) kann man einen folgenden Zwei-Byte-Befehl ausblenden, d.h. eigentlich steht da, wenn man von "printa" her einspringt LDA #65 BIT $???? JSR $FFD2.; da der BIT Befehl ja keine Register beeinflußt ist er einfach wirkungslos in diesem Fall. Springt man dagegen zu printb, klar dann steht da einfach LDA #66 JSR $FFD2.
    Wenn man diese Tricks ein bisschen anzuwenden weiß, kann man ganz schön Platz sparen. Sogar im KERNAL-ROM findet man diese Art des Codings.

  • Wenn ich den benutzt habe, dann meistens, um Ereignisse aus Interrupt-Registern auszulesen oder wenn ich in Speicherstellen Bit7 als Boolean benutze. Halt, weil ich unabhängig von irgendwelchen Registern 2 Bits aus der Speicherstelle in Flaggen übertragen kann. Weiß gar nicht, ob mir die AND-Verknüpfung jemals einen Nutzen gebracht hat.

  • Ich hab den BIT-Befehl bisher hauptsächlich zu Timingzwecken benutzt. Und wo wir schon dabei sind - verwendet eigentlich jemand die indiziert-indirekte Adressierung ($00,x)? Ich kann mich erinnern sie tatsächlich einmal eingesetzt zu haben, aber das war in einer Routine die nachher nicht lief.

  • Zitat

    Original von Dow JonesUnd wo wir schon dabei sind - verwendet eigentlich jemand die indiziert-indirekte Adressierung ($00,x)?


    GoDots Konvertierungsroutinen benutzen das oft. Man muss halt dauernd eine Menge Zeiger im Blick halten.


    Arndt

  • Zitat

    Original von hoogo


    hast Du dafür mal ein Code-Beispiel?


    Ich hatte hier ein voll auskommentiertes Beispiel reingetippt...


    und dann ist mir der Browser abgekackt.


    Für heute hab ich keine Lust mehr. Morgen, ok?


    Arndt

  • Zitat

    Original von hoogo
    hast Du dafür mal ein Code-Beispiel?


    So, und jetzt ein zweiter Versuch, diesmal "gepuffert" (ich schreibe mit
    meinem Code-Editor und kopier das dann ins Forum).


    Achtung, dies ist ein längerer Beitrag!


    Erstmal zur Erklärung der Adressierungsweise "vorindiziert mit X"
    (ind,x). Jeder kennt und nutzt die Nachindizierung, meist mit Y, z.B.:


    Code
    1. lda (zp1),y ; hier wird umgelagert, aus einer Tabelle...
    2. sta (zp2),y ; ... unverändert in eine andere


    Dabei hat man in der Zeropage einen Zeiger definiert (hier zp1 und zp2),
    der auf eine bestimmte Speicheradresse verweist. Diese Speicheradresse
    ist die Basisadresse für eine Tabelle, die man auslesen (lda) oder
    anlegen (sta) will. Das Y-Register ist dabei der Hilfszeiger in diese
    Tabelle hinein. Sie kann somit nicht umfangreicher werden als 256 Bytes,
    da Y ja ein einzelner Bytewert ist.


    Bei der Vorindizierung hast du eine Tabelle von Zeigern (!) und du wählst
    mit dem X-Register den Zeiger aus, den du benutzen willst. Also es ist
    genau umgekehrt wie bei der Nachindizierung. Deine Zeiger verweisen alle
    jeweils auf eine einzelne Speicherstelle (die daher keinen
    Tabellenanfang darstellt). Die angebene Zeropageadresse ist vielmehr
    selber ein Anfang einer Tabelle von ebendiesen Zeigern. X kann
    sinnvollerweise nur in Zweierschritten erhöht werden, sonst kriegst du
    deine Zieladressen nicht heraus, also x=0, 2, 4, ... Sagen wir mal ab
    $b0 liegt eine Tabelle von 2 Zeigern, die z.B. auf zwei Laufwerksnummern
    zeigen (die variabel dort abgelegt werden, sonst wär das ein blödes
    Beispiel, du willst meinetwegen mal von Drive 8 in Drive 9 kopieren, mal
    andersherum oder woanders hin, ohne groß überlegen zu müssen):


    $b0:
    .wo $8678, $89ab


    Dort steht am Anfang z.B. $08 (in $8678 ) und $09 (in $89ab). Mit dem
    vorindizierten Vektor kannst du nun diese beiden Adressen ganz einfach
    auslesen (obwohl deren Inhalte meilenwert voneinander entfernt im
    Speicher stehen):


    Code
    1. ldx #0
    2. lda ($b0,x) ; liest $8678 aus
    3. ...
    4. ldx #2
    5. lda ($b0,x) ; liest $89ab aus


    Verstehst du jetzt den Sinn der Vorindizierung?


    Wenn du die Vorindizierung verwenden willst wie die Nachindizierung
    (also du hast einen Zeiger auf eine Tabelle und willst dort was machen),
    dann MUSS das X-Register immer $00 bleiben (!) und du MUSST die
    Zieladresse im Zeiger verändern, z.B. so (in $b0/$b1 steht wieder $8678
    als Zieladresse):



    Und jetzt eine Stelle aus GoDot, wo das so verwendet wird. GoDot
    braucht oft viele Zeiger und Zähler gleichzeitig, daher muss ich
    bisweilen zur Vorindizierung greifen, damit der Code noch überschaubar
    bleibt und halbwegs kompakt. Diese Stelle hier rendert das 4Bit-Bild in
    GoDots Datenspeicher in das kleine Previewfenster rechts in der Mitte
    des Hauptbildschirms. Dieses Preview besteht aus 6 Multisprites, die das
    Originalbild vierfach verkleinert in vier Graustufen (schwarz und die
    drei Graus) darstellen. Drei Sprites liegen dafür nebeneinander, was
    aber nicht für 40 Kacheln ausreicht (drei Sprites sind dreimal drei
    Bytes nebeneinander, also 9 Bytes, ein Viertel des Screens wären aber 10
    Bytes). Senkrecht ist das genauso, statt 25 Kacheln passen nur 20. GoDot
    rendert daher einen Ausschnitt von 36x20 Kacheln in das Preview.


    Vor der folgenden Renderroutine wurden bereits die 6 Sprites
    initialisiert (am Ende des 1. VIC-Bereichs an $3e80), der Zähler gesetzt
    für 3x12 Kacheln waagerecht (Stack), die beiden Zeiger in die Quelldaten
    (4Bitbild) bzw. Zieldaten (Sprites) definiert (SRC und DST) und der
    Zähler für die Länge eines Sprites (SPCNT) auf $00 gesetzt.


  • Danke für die Mühe :) In Deinem Besipiel wärst Du also mit einem sta (dst) glücklicher geworden, wenn es diese Adressierung gegeben hätte. Oder Du hättest mit einem ldy#0: sta (dst),y das Gleiche erreicht und das X-Register für anderes verwenden können. Ich hätte eine Selbstmodifikation genommen. Jedenfalls hast Du mich noch nicht von der Nützlichkeit dieser Adressierungsart überzeugt.

  • Zitat

    Original von hoogo
    In Deinem Besipiel wärst Du also mit einem sta (dst) glücklicher geworden, wenn es diese Adressierung gegeben hätte.


    Jepp.


    Zitat

    Oder Du hättest mit einem ldy#0: sta (dst),y das Gleiche erreicht und das X-Register für anderes verwenden können.


    Nein, außerhalb dieser Subroutine wird mit Y herumhantiert. Irgendwann kommst du dann durcheinander, welcher Wert für Y denn jetzt gerade zugrunde liegt.


    Zitat

    Ich hätte eine Selbstmodifikation genommen.


    Das vermeidet GoDot. Kommt höchstens 2 oder 3 Mal in all den Modulen vor. Ich hasse Selbstmodifikationen.


    Zitat

    Jedenfalls hast Du mich noch nicht von der Nützlichkeit dieser Adressierungsart überzeugt.


    Das wollte ich gar nicht. Du schriebst nur, du hätttest es verwendet und es hätte nicht geklappt. Vielleicht haben dir meine Bemerkungen ja weitergeholfen. ;) Ach nein, das war Dow Jones...


    Arndt

  • Zitat


    Ich hasse Selbstmodifikationen.


    warum? grade so kann man doch oft schnelleren UND kürzeren coder fabrizieren...oder wss hab ich verpasst? vom rom soll godot doch nicht laufen, oder was gibts sonst noch für gründe die dagegen sprechen?


    lda(zp,x) hab ich auch noch NIE benutzt, imho total sinnlos...hab noch kein beispiel gesehen das man nicht anders genauso oder gar besser hätte lösen können :)

  • Selbstmodifikation hasse ich im Prinzip ja auch, wenn ich so lese, was sich moderne Prozessoren so an Schwiergkeiten anfangen, nur damit sowas läuft... Ärgert mich ja auch, wenn mein 4 Prozessor-650ZwoIum mit je 64KB 1stLvl... nicht auf Höchstgeschwindigkeit läuft ;)
    Ne, nun im Ernst. Man kann mit Selbstmodifikation tollen Spaghetticode schreiben, der nach dem Ändern eines Befehls nur noch Mist macht. Man kann damit aber auch Adressierungsarten simulieren, die der 6502 nicht hat, und sich damit manche Sachen (zumindest im Quelltext) einfacher und verständlicher machen. Ganz ganz selten gehts sogar nicht ohne. Nur meine Meinung dazu.

  • Hallo Arndt,
    danke füer deine ausführliche Antwort. Die funktionsweise des Befehls war mir schon klar, auch wenn ich an die Verwendung als sta (dst) gar nicht gedacht habe (gute Idee, btw). Der Nutzen des ,x dabei bleibt mir indes immer noch verborgen. Eine Tabelle von Zeigern... *grübel*. Ich muss mich Sauhund anschließen, mir fällt kein Anwendungsbeispiel ein das man nicht auch anders bzw besser lösen könnte. Gibt's diese Adressierungsart bei anderen Prozessoren auch?

  • Zitat

    Original von hoogo
    Ganz ganz selten gehts sogar nicht ohne. Nur meine Meinung dazu.


    Darum sind Selbstmodifikationen ja auch ein paarmal in GoDot zu finden (z.B. im Test, welche Peripherie angeschlossen ist, im mod..FileCopy und wo noch...? Ah ja, in der REU-Unterstützung muss am GoDot-Kernel gepatcht werden).


    @Sauhund:

    Zitat

    vom rom soll godot doch nicht laufen, oder was gibts sonst noch für gründe die dagegen sprechen?


    Das liegt nicht an selbstmodifizierendem Code, sondern daran, dass GoDot das ganze System dauernd ummodifiziert (ist halt modular, das Ganze, selbst während des Betriebs). Ein GoDot auf Eprom ist wie eine Sahnetorte im Kino, völlig nutzlos und daneben.


    Arndt

  • Zitat


    Das liegt nicht an selbstmodifizierendem Code, sondern daran, dass GoDot das ganze System dauernd ummodifiziert (ist halt modular, das Ganze, selbst während des Betriebs). Ein GoDot auf Eprom ist wie eine Sahnetorte im Kino, völlig nutzlos und daneben.


    äh ja, die frage war eigentlich was du gegen selbstmodifizierenden code hast... denn wie du ja schon sagst soll godot ja nicht ausm rom laufen (was ein grund dagegen wäre).


    das es situtationen gibt die NUR mit selbstmodifikationen lösbar sind halte ich allerdings auch für ein gerücht :)

  • Zitat

    Original von sauhunddas es situtationen gibt die NUR mit selbstmodifikationen lösbar sind halte ich allerdings auch für ein gerücht :)


    Hab auch nur ein einziges Beispiel: Beim Multitasking eine Routine sicher davor zu schützen, zweimal gleichzeitig zu laufen.

  • Zitat

    Original von sauhund
    äh ja, die frage war eigentlich was du gegen selbstmodifizierenden code hast... denn wie du ja schon sagst soll godot ja nicht ausm rom laufen (was ein grund dagegen wäre).


    Selbstmodifizierender Code ist wie als wenn ich mir die Nase abbeißen muss, damit mein Kopf durchs Bullauge passt, nur damit ich die schöne Aussicht auf meinem Dampfer genießen kann. ;)


    GoDot läuft schon aus dem ROM, aber wer packt schon (nicht mal) 4 KB in ein ROM, das hinterher weitere 16 KB nachlädt... (Kernel von $800 bis $1fff, nachgeladen - abhängig vom INI-File - wird der Lader $c000, der Saver $d000, der Modifier $e000 und die Renderroutinen $f000, wenn REU angeschlossen ist, noch die REU-Routinen, in die REU). Das lohnt sich nicht. Im Betrieb läuft alles Modulare (also alles außer dem Kernel) an $c000 ab, es wird also ständig umgeschichtet. Selbst die Daten für die Grafikanzeige sind im System verteilt (die Farben).


    Was anderes: Hoogo, du solltest Sauhund deinen Avatar abgeben... ;)


    Arndt

  • Zitat


    Hab auch nur ein einziges Beispiel: Beim Multitasking eine Routine sicher davor zu schützen, zweimal gleichzeitig zu laufen.


    1) poste das mal in ner form die man auch lesen kann (wenn du glaubst DAS ist einfacher zu lesen als selbstmodifizierender code will ich auch was von dem zeug das du rauchst bitte :=))
    2) spinlocks kann man ganz einfach mit flags in der zeropage machen, und etwas ineffizienter auch mit flags überall sonst, da brauchts nun wirklich nicht zwingend selbstmodifizierten code :) das selbstmodifikation an der stelle vielleicht (warscheinlich) effizienter ist kann wohl sein :)