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?
Hallo Besucher, der Thread wurde 4,3k mal aufgerufen und enthält 26 Antworten
letzter Beitrag von Fröhn am
-
-
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: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.
-
wens interessiert der soll mal im floppy rom guckn, da wird der relativ häufig benutzt.
-
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.
-
Interessant
Wird ein paar mal benutzt, um gezielt NV-Flag zu setzen oder zu löschen. $DFB0 ist interessant, $EFF1 oder $D37F nutzen auch mal die AND-Funktion, hätte man aber ohne BIT besser machen können. -
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 GoDot
GoDots Konvertierungsroutinen benutzen das oft. Man muss halt dauernd eine Menge Zeiger im Blick halten.Arndthast Du dafür mal ein Code-Beispiel?
-
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.:
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, $89abDort 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):
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):Code
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.Code- ;------------------------------------------------------------------
- ;
- ; rendering 4Bit Area to 6 sprites
- ;
- ;------------------------------------------------------------------
- makeit:
- ldx #$00 ; ist immer $00!
- ldy #$14 ; 20 Kachelzeilen abwärts zählen
- prloop:
- tya ; hier geht's los
- pha
- lda #$40 ; Flag: %0100 0000, zählt 2 Durchgänge pro Kachel
- sta lflag
- dzloop:
- lda #$03 ; Flag: 1 Sprite ist 3 Bytes breit
- sta brttmp
- zloop:
- ldy #$60 ; 4 Kacheln von rechts nach links
- lda lflag ; beim 2. Kacheldurchgang...
- bpl bloop
- ldy #$70 ; ... 4 Pixel tiefer ansetzen
- bloop:
- lda (src),y ; Hole 4Bit-Daten
- lsr
- lsr
- lsr
- ror crttmp ; (grob) rendern
- lsr
- ror crttmp
- tya ; nächste Kachel links davon anpeilen
- sec
- sbc #$20
- tay
- bpl bloop ; 4 Mal (für 1 gerendertes Byte)
- lda crttmp ; 1 Byte fertig gerendert, ab ins Sprite
- sta (dst,x) ; VORINDIZIERUNG!
- skip64:
- inc dst ; Zeiger ins Sprite erhöhen
- bne s1
- inc dst+1
- s1:
- inc spcnt ; Byte 64 überspringen
- lda spcnt
- cmp #$3f
- beq skip64
- lda src ; Zeiger 4 Kacheln weiter setzen
- clc ; (zuletzt 12 Kacheln durch)
- adc #$80
- sta src
- bcc skip
- inc src+1
- skip:
- ror brttmp ; zählt Spritebreite (Carry ist zweimal an)
- bcs zloop
- lda src ; dann: nächste Spritezeile anpeilen, dafür...
- sec
- sbc #$80 ; ... zurück an den Anfang (12 Kacheln zurück)
- sta src
- lda src+1
- sbc #$01
- sta src+1
- rol lflag ; 2. Durchgang 4 Pixel tiefer
- bcc dzloop
- clc ; dann: nächste Kachelzeile anpeilen
- lda src+1 ; $500 weiter in den Quelldaten
- adc #$05
- sta src+1
- pla ; Zähler vom Stack holen
- tay ; (zählt 20 Kachelzeilen)
- dey
- bpl prloop ; von vorne...
- rts ; ... bis alles fertig ist
- ;-------------------------------------------------------------
-
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.ZitatOder 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.ZitatIch hätte eine Selbstmodifikation genommen.
Das vermeidet GoDot. Kommt höchstens 2 oder 3 Mal in all den Modulen vor. Ich hasse Selbstmodifikationen.ZitatJedenfalls 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:
Zitatvom 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