Maggi-Fix für SNES Programmierung
Moderator: Perikles
- ikari_01
- snesfreaks.com-Team

- Beiträge: 441
- Registriert: 15. Juni 2010, 23:19
- +Positive Tradingpoints+: 6 von 6
- Wohnort: Wunstorf
Re: Maggi-Fix für SNES Programmierung
Hab ich noch nie ausprobiert, unwahrscheinlich ist das aber nicht. 
sd2snes news: https://sd2snes.de
- lytron
- Code Bro

- Beiträge: 2664
- Registriert: 12. August 2012, 20:18
- +Positive Tradingpoints+: 12 von 12
- Wohnort: ハノーファー区
- Kontaktdaten:
Re: Maggi-Fix für SNES Programmierung
lolzn.
Habe gerade in meinem Textbox-Shakalaka nachgeschaut, wo ich wusste, dass ich dort auch über $7FFF hinaus das genutzt habe.
Klasse, was? Im Falle des Falls, dass es in der Tat eine Spiegelung ist, habe ich unwissendlich die Sachen genau so abgelegt, dass sie nicht kollidieren.
Aber dann habe ich zumindest eine Testumgebung, wo ich es einfach überprüfen kann. Heute abend. Oder demnächst. Oder so.
Habe gerade in meinem Textbox-Shakalaka nachgeschaut, wo ich wusste, dass ich dort auch über $7FFF hinaus das genutzt habe.
Code: Alles auswählen
;===================================================================================================================
; VRAM CONTENT:
; $0000-$07FF - Sprite
; $9000-$93FF - Landscape Tiles
; $A000-$A4FF - Textbox Tiles
; $F000-$F7FF - Tilemap BG1 (Landscape) Isn't set yet - happens further down
; $F800-$FFFF - Tilemap BG3 (Textbox) Isn't set yet - happens further down
;===================================================================================================================
Aber dann habe ich zumindest eine Testumgebung, wo ich es einfach überprüfen kann. Heute abend. Oder demnächst. Oder so.
pantalytron: ルトロンはくそのディスアセンブラだよ!
Perikles hat geschrieben:Man muss sich das mal reinziehen: die Idee ist scheiße, die theoretische Ausarbeitung ist scheiße, die praktische Umsetzung ist scheiße und der so entstehende Anspruch noch beschissener.
- ikari_01
- snesfreaks.com-Team

- Beiträge: 441
- Registriert: 15. Juni 2010, 23:19
- +Positive Tradingpoints+: 6 von 6
- Wohnort: Wunstorf
Re: Maggi-Fix für SNES Programmierung
Das sind einfach Byteadressen da in der Tabelle. Wenn die tatsächlich so in die Register geschrieben werden, funktioniert die Spiegelung wohl wirklich. Überschneidungen gibt es ja glücklicherweise keine 
sd2snes news: https://sd2snes.de
Re: Maggi-Fix für SNES Programmierung
Hallo lytron,
ich habe mich exklusiv wegen des Artikels, welchen du hier im Forum verfasst, registriert. Ein großes Lob für die Mühe, die du dir dabei machst. Das Verfolgen macht sehr viel Spaß und ich versuche, dran zu bleiben, denn das Entwickeln in Assembler ist sehr interessant.
Ich warte gebannt auf deinen nächsten Post und wünsche dir viel Energie, dass du dies durchziehst.
Gruß
Fredward
ich habe mich exklusiv wegen des Artikels, welchen du hier im Forum verfasst, registriert. Ein großes Lob für die Mühe, die du dir dabei machst. Das Verfolgen macht sehr viel Spaß und ich versuche, dran zu bleiben, denn das Entwickeln in Assembler ist sehr interessant.
Ich warte gebannt auf deinen nächsten Post und wünsche dir viel Energie, dass du dies durchziehst.
Gruß
Fredward
Re: Maggi-Fix für SNES Programmierung
(...dieser Mann wird sich hier noch bis ganz nach oben schlafen.)
- lytron
- Code Bro

- Beiträge: 2664
- Registriert: 12. August 2012, 20:18
- +Positive Tradingpoints+: 12 von 12
- Wohnort: ハノーファー区
- Kontaktdaten:
Re: Maggi-Fix für SNES Programmierung
Keine Panik, solange du niemanden beleidigst, wirst du auch weiter ein User dieses Boards bleiben.Fredward hat geschrieben:Ich warte gebannt auf deinen nächsten Post (...)
Moin Fredward,
danke für das Feedback! Und - wowy, ich hätte nicht gedacht, dass sich deshalb jemand hier extra für Registrieren wird!
Den nächsten Post sollte ich auf jeden Fall demnächst mal zusammenschreiben; mit dem "Grundkurs" werde ich bald durchsein und ab dann kommen wohl Einzelartikel, die in keiner festen Reihenfolge zu lesen sind und die dann auch nicht regelmäßig geschrieben werden. Wohl eher nach Bedarf, nach Laune und/oder Nachfrage.
Aber viel von dem Zeug müsste ich wahrscheinlich eh nochmal korrigieren... :/
Whatever! Danke dir für deine aufmunternden Worte und ein "Herzlich Willkommen!" bei uns!
Sei doch nicht so gemein zu einem neuregistrierten User!Moi-Même hat geschrieben:(...dieser Mann wird sich hier noch bis ganz nach oben schlafen.)
pantalytron: ルトロンはくそのディスアセンブラだよ!
Perikles hat geschrieben:Man muss sich das mal reinziehen: die Idee ist scheiße, die theoretische Ausarbeitung ist scheiße, die praktische Umsetzung ist scheiße und der so entstehende Anspruch noch beschissener.
- ChronoMoogle
- snesfreaks.com-Team

- Beiträge: 9895
- Registriert: 26. Februar 2007, 14:56
- +Positive Tradingpoints+: 98 von 98
- Wohnort: Nippon
- Kontaktdaten:
Re: Maggi-Fix für SNES Programmierung
Ich glaube nicht, dass er dem neuen User vorwirft unheimlich schlaefrig und auf hohe Ziele bedacht zu sein, sondern dir :DDD

| Mein YT Channel | Mein Twitter | Ich suche | Ich verkaufe | Foren SuFu |
...weil Terranigma einfach das Größte ist!
- lytron
- Code Bro

- Beiträge: 2664
- Registriert: 12. August 2012, 20:18
- +Positive Tradingpoints+: 12 von 12
- Wohnort: ハノーファー区
- Kontaktdaten:
Re: Maggi-Fix für SNES Programmierung
Ich denke gerade eher die ganze Zeit darüber nach, ob er beim Thema "hochschlafen" darauf abzielt, dass er dann in dem Falle meine "letzte Hürde" ist.ChronoMoogle hat geschrieben:Ich glaube nicht, dass er dem neuen User vorwirft unheimlich schlaefrig und auf hohe Ziele bedacht zu sein, sondern dir :DDD
pantalytron: ルトロンはくそのディスアセンブラだよ!
Perikles hat geschrieben:Man muss sich das mal reinziehen: die Idee ist scheiße, die theoretische Ausarbeitung ist scheiße, die praktische Umsetzung ist scheiße und der so entstehende Anspruch noch beschissener.
Re: Maggi-Fix für SNES Programmierung
Nein, ich habe dich im Chat schon mehrfach herzlich zum Sex mit mir eingeladen. Erinnere dich da bitte genau.
- ChronoMoogle
- snesfreaks.com-Team

- Beiträge: 9895
- Registriert: 26. Februar 2007, 14:56
- +Positive Tradingpoints+: 98 von 98
- Wohnort: Nippon
- Kontaktdaten:
Re: Maggi-Fix für SNES Programmierung
Ich glaube mir wird schlecht.

| Mein YT Channel | Mein Twitter | Ich suche | Ich verkaufe | Foren SuFu |
...weil Terranigma einfach das Größte ist!
- lytron
- Code Bro

- Beiträge: 2664
- Registriert: 12. August 2012, 20:18
- +Positive Tradingpoints+: 12 von 12
- Wohnort: ハノーファー区
- Kontaktdaten:
Re: Maggi-Fix für SNES Programmierung
Jaaa, jaaa... verdammt, ja. ~_~Moi-Même hat geschrieben:Nein, ich habe dich im Chat schon mehrfach herzlich zum Sex mit mir eingeladen. Erinnere dich da bitte genau.
pantalytron: ルトロンはくそのディスアセンブラだよ!
Perikles hat geschrieben:Man muss sich das mal reinziehen: die Idee ist scheiße, die theoretische Ausarbeitung ist scheiße, die praktische Umsetzung ist scheiße und der so entstehende Anspruch noch beschissener.
- lytron
- Code Bro

- Beiträge: 2664
- Registriert: 12. August 2012, 20:18
- +Positive Tradingpoints+: 12 von 12
- Wohnort: ハノーファー区
- Kontaktdaten:
Re: Maggi-Fix für SNES Programmierung
DJ Svam-Bobo! Nice to see you again!Svambo hat geschrieben:Mal so als Anregung / Idee: Hast Du Lust, in deinem Maggi-Fix Thread die unterschiedlichen Steuergeräte zu erläutern (mit Codebeispiel)? Also Steuerung über Pad, Maus, Justifier, Super Scope ... Kam mir grad so in den Kopf, als du von der Maus schriebst.
Ansonsten: Weiter so. Find deine beiden Coding Threads immer wieder spannend.
Danke für die warmen Worte!
An derlei habe ich auch schon gedacht. Den Controller würde ich definitiv machen, das wird auch im Rahmen des normalen "Grundkurses" auftauchen. Die anderen Sachen würde ich auch machen, wobei ich mich da erst selbst reinfuchsen müsste, weil ich das (noch) nicht kann. Der Vorteil ist, dass die gesamte Sonderperipherie (also alles außer dem Controller) über dieselbe Schiene läuft (Register $4016/7), das heißt, ich muss dann nur noch einmal genau heraussuchen, wie die Daten in diese Register übertragen werden.
Das einzige Problem wird nur die Hardware zum Testen sein, da ich niemals-nicht einen Justifier oder SuperScope besessen habe, und gerade auch kein Mario Paint zur Hand habe, aber das wird wohl das Geringste aller Probleme sein.
Falls du es eilig wegen der Maus hast:
Auf der Seite, die duoGS aufgetan hat, die ich auch schon unter den Development-Ressources gepostet habe, gibt es ein Maus-Tutorial; das habe ich mir bisher nur flüchtig angesehen. Wenn du demnächst einen direkten Anwendungsbereich hast, kann dir das vielleicht schon weiterhelfen.
pantalytron: ルトロンはくそのディスアセンブラだよ!
Perikles hat geschrieben:Man muss sich das mal reinziehen: die Idee ist scheiße, die theoretische Ausarbeitung ist scheiße, die praktische Umsetzung ist scheiße und der so entstehende Anspruch noch beschissener.
- lytron
- Code Bro

- Beiträge: 2664
- Registriert: 12. August 2012, 20:18
- +Positive Tradingpoints+: 12 von 12
- Wohnort: ハノーファー区
- Kontaktdaten:
Re: Maggi-Fix für SNES Programmierung
Kurze Info vorab: Ich habe bei dem letzten langen Beitrag, in dem die Grafikdemo erstellt wurde, jetzt auch das komplette Projekt gezippt eingefügt.
Kategorie: SNES-Programmierung
Projekttage: DMA
Liebe Schüler! Es sind Projekttage!
Wir werden im Kommenden einiges an unserer Grafikdemo herumschrauben. Dabei werden wir viel Neues sehen, viel Spaß haben, viel neue Erkenntnisse machen… nur Private wird wohl dabei draufgehen.
Zunächst betrachten wir noch einmal den wichtigen Teil (d. h. nach dem Aufruf des InitSNES bis zum forever-Loop) des Programms. Als Auffrischung.
Im Ganzen ist das:
Trotzdem machen wir das jetzt hier. Erstens bringen wir mit dem Programm den Prozessor nicht an die Grenzen seiner Belastbarkeit, insofern können wir uns diesen Schlendrian leisten, und zweitens haben wirs dann einheitlich, und das ist für Tutorials immer chic.
Wir löschen den dritten Absatz und setzen dort folgendes ein (um nicht immer wieder dasselbe zweimal zu schreiben, setze ich jetzt die Adressen der Register immer als Kommentar hinter die Bezeichnung aus d4s‘ define-Datei):
Sprechen wir das im Einzelnen durch:
Da du nur immer ein Register beschreiben willst, speichern wir null in DMAP0. Das Ziel des DMAs ist Register $2122 (CGDATA), folglich schreiben wir in DMADEST0 #$22 (wir erinnern uns: Wir können immer nur auf Register „zielen“, die mit $21xx anfangen).
Im nächsten Schritt wird die Source-Adresse gesetzt. Dabei schreiben wir beim Laden-Befehl zunächst „#Palette“. Zur Erklärung: „Palette“ ist ein Label und wird von WLA-DX durch eine Zahl setzt. Das ist dasselbe wie die Labels, die wir benutzt haben, als wir die Schleife geschrieben haben. Dort schrieben wir ja zum Beispiel auch „BNE TransferCycle0“. WLA DX, wie bereits schon einmal beschrieben, schaut, vor welchem Befehl „TransferCycle0:“ steht, nimmt die Adresse von diesem Befehl und setzt sie dann anstelle des Labels überall im Progamm ein. Wenn TransferCycle0 irgendwo ganz am Anfang einer Bank steht, steht da dann „$8000“ (weil, in diesem Fall, Bankadressen ab $8000 erst anfangen. Frag nich. Isso. - Oder doch, frag. Aber später.).
Wir wollen jetzt an dieser Stelle nicht den Inhalt einer Adresse laden, sondern die Adresse selbst. Würden wir mit Adressen statt mit Labels arbeiten, würden wir ja auch schreiben:
Ein einfaches „LDX $8000“ würde den Inhalt von Register $8000 und $8001 laden (die ersten beiden Bytes einer Palette, in diesem Fall) und die im DMA-Source-Register speichern. Wenn man den DMA jetzt starten würde, würde er diese Paletten-Bytes als Startadresse für seinen Transfer interpretieren. Ich denke, es ist klar, dass das nichts werden wird.
Also. Folglich schreibt man „#$8000“ statt „$8000“. Und logischerweise schreibt man auch „#Palette“ statt „Palette“.
Beim nächsten Ladebefehl ist das eine besondere Besonderheit von WLA DX. „#:Palette“ nimmt nicht die Adresse innerhalb einer Bank, sondern die Bank-Nummer. In diesem Fall ergibt „#:Palette“ übrigens „#$00“, da wie die Grafikdaten ebenfalls auf Bank $00 gelassen haben.
Abschließend setzen wir die Menge der zu übertragenden Daten auf #$0080 und aktivieren DMA-Channel 0 via Register MDMAEN ($420B).
Okay. Das war die Erklärung. Und jetzt macht ihr den DMA anstelle des TransferLoop1 allein, während ich rumgehe und die Hausaufgaben kontrolliere.
Aber, bevor ihr anfangt, löse ich mal drei Hinweismünzen ein:
So. Kurz vor Schluss verschlanken wir das Ding nämlich noch einmal. Als Erstes löscht ihr den ersten „LDA #DMA_CHANNEL0_ENABLE.b“ und „STA MDMAEN.w“.
Dann geht ihr zum zweiten und DMA-Befehl und weist ihm Channel 1 zu. (Die Adressnamen sind glücklicher- wie logischerweise dieselben, nur die Nullen müssen in Einsen geändert werden).
Als letztes ersetzt ihr das vormals zweite, jetzt erste „LDA #DMA_CHANNEL0_ENABLE.b“ (= „LDA #$01.b“) mit „LDA #DMA_CHANNEL0_ENABLE|DMA_CHANNEL1_ENABLE.b“ (= „LDA #$03.b“).
Jetzt werden die ersten beiden DMAs direkt nacheinander ausgeführt.
Den dritten können wir leider nicht mit in die Runde aufnehmen, weil wir nach dem zweiten und vor dem dritten DMA noch die VRAM-Zieladresse ändern müssen.
Diese letzte Fassung findet ihr in der Zip. Viel Spaß noch mit euren Projekttagen, liebe Klasse!
Kategorie: SNES-Programmierung
Projekttage: DMA
Liebe Schüler! Es sind Projekttage!
Wir werden im Kommenden einiges an unserer Grafikdemo herumschrauben. Dabei werden wir viel Neues sehen, viel Spaß haben, viel neue Erkenntnisse machen… nur Private wird wohl dabei draufgehen.
Zunächst betrachten wir noch einmal den wichtigen Teil (d. h. nach dem Aufruf des InitSNES bis zum forever-Loop) des Programms. Als Auffrischung.
Code: Alles auswählen
LDA #INIDSP_FORCE_BLANK.b
STA INIDSP.w
LDA #BGMODE_MODE_1.b
STA BGMODE.w
LDA #T_BG1_ENABLE.b
STA TMAIN.w
LDA #$10.b
STA BG1SC.w
STZ BG12NBA.w
STZ CGADD.w
LDX #$0000.w
TransferCycle0:
LDA Palette.w, X
STA CGDATA.w
INX
LDA Palette.w, X
STA CGDATA.w
INX
CPX #$0080.w
BNE TransferCycle0
LDA #VMAIN_INCREMENT_MODE.b
STA VMAIN.w
LDX #$0000.w
STX VMADDL.w
TransferCycle1:
LDY Tileset.w, X
STY VMDATAL.w
INX
INX
CPX #$0200.w
BNE TransferCycle1
LDX #$1000.w
STX VMADDL.w
LDX #$0000.w
TransferCycle2:
LDY Tilemap.w, X
STY VMDATAL.w
INX
INX
CPX #$0800.w
BNE TransferCycle2
LDA #$0F.b
STA INIDSP.w
- Erster Absatz: Bildschirmeinstellungen; Forced Blank, BG-Mode, BG1 an und „wo finde ich die Daten für BG1 im VRAM?“.
- „STZ CGADD“: Vorbereitung für die Farbübertragungsschleife.
- Dritter Absatz: Farbübertragungsschleife.
- „VMAIN“-Absatz: Vorbereitung für die Tileset-Übertragungsschleife.
- Fünfter Absatz: Tileset-Übertragungsschleife.
- Sechster Absatz: Tilemap-Übertragungsschleife.
- Siebter Absatz: Anschalten des Bildschirms
Trotzdem machen wir das jetzt hier. Erstens bringen wir mit dem Programm den Prozessor nicht an die Grenzen seiner Belastbarkeit, insofern können wir uns diesen Schlendrian leisten, und zweitens haben wirs dann einheitlich, und das ist für Tutorials immer chic.
Wir löschen den dritten Absatz und setzen dort folgendes ein (um nicht immer wieder dasselbe zweimal zu schreiben, setze ich jetzt die Adressen der Register immer als Kommentar hinter die Bezeichnung aus d4s‘ define-Datei):
Code: Alles auswählen
STZ DMAP0.w ; $4300
LDA #$22.b ; für $2122
STA DMADEST0.w ; $4301
LDX #Palette.w
STX DMASRC0L.w ; $4302 (indirekt auchDMASRC0H/ $4303)
LDA #:Palette.b
STA DMASRC0B.w ; $4304
LDX #$0080.w
STX DMALEN0L.w ; $4305 (indirekt auch DMALEN0H / $4306)
LDA #DMA_CHANNEL0_ENABLE.b ; #$01.b
STA MDMAEN.w ; $420BDa du nur immer ein Register beschreiben willst, speichern wir null in DMAP0. Das Ziel des DMAs ist Register $2122 (CGDATA), folglich schreiben wir in DMADEST0 #$22 (wir erinnern uns: Wir können immer nur auf Register „zielen“, die mit $21xx anfangen).
Im nächsten Schritt wird die Source-Adresse gesetzt. Dabei schreiben wir beim Laden-Befehl zunächst „#Palette“. Zur Erklärung: „Palette“ ist ein Label und wird von WLA-DX durch eine Zahl setzt. Das ist dasselbe wie die Labels, die wir benutzt haben, als wir die Schleife geschrieben haben. Dort schrieben wir ja zum Beispiel auch „BNE TransferCycle0“. WLA DX, wie bereits schon einmal beschrieben, schaut, vor welchem Befehl „TransferCycle0:“ steht, nimmt die Adresse von diesem Befehl und setzt sie dann anstelle des Labels überall im Progamm ein. Wenn TransferCycle0 irgendwo ganz am Anfang einer Bank steht, steht da dann „$8000“ (weil, in diesem Fall, Bankadressen ab $8000 erst anfangen. Frag nich. Isso. - Oder doch, frag. Aber später.).
Wir wollen jetzt an dieser Stelle nicht den Inhalt einer Adresse laden, sondern die Adresse selbst. Würden wir mit Adressen statt mit Labels arbeiten, würden wir ja auch schreiben:
Code: Alles auswählen
LDX #$8000.w
STX DMASRC0L.wAlso. Folglich schreibt man „#$8000“ statt „$8000“. Und logischerweise schreibt man auch „#Palette“ statt „Palette“.
Beim nächsten Ladebefehl ist das eine besondere Besonderheit von WLA DX. „#:Palette“ nimmt nicht die Adresse innerhalb einer Bank, sondern die Bank-Nummer. In diesem Fall ergibt „#:Palette“ übrigens „#$00“, da wie die Grafikdaten ebenfalls auf Bank $00 gelassen haben.
Abschließend setzen wir die Menge der zu übertragenden Daten auf #$0080 und aktivieren DMA-Channel 0 via Register MDMAEN ($420B).
Okay. Das war die Erklärung. Und jetzt macht ihr den DMA anstelle des TransferLoop1 allein, während ich rumgehe und die Hausaufgaben kontrolliere.
Aber, bevor ihr anfangt, löse ich mal drei Hinweismünzen ein:
- HINWEIS 1: Du musst den Wert DMAP_2_REG_WRITE_ONCE (#$01) in DMAP ($4300) speichern.
- HINWEIS 2: Lösch nicht die Befehle, wo in VMADDL gespeichert wird.
- HINWEIS 3: Falls du es vergessen haben solltest: VMDATAL ist $2118.
versteckter Inhalt:
Dann geht ihr zum zweiten und DMA-Befehl und weist ihm Channel 1 zu. (Die Adressnamen sind glücklicher- wie logischerweise dieselben, nur die Nullen müssen in Einsen geändert werden).
Als letztes ersetzt ihr das vormals zweite, jetzt erste „LDA #DMA_CHANNEL0_ENABLE.b“ (= „LDA #$01.b“) mit „LDA #DMA_CHANNEL0_ENABLE|DMA_CHANNEL1_ENABLE.b“ (= „LDA #$03.b“).
Jetzt werden die ersten beiden DMAs direkt nacheinander ausgeführt.
Den dritten können wir leider nicht mit in die Runde aufnehmen, weil wir nach dem zweiten und vor dem dritten DMA noch die VRAM-Zieladresse ändern müssen.
Diese letzte Fassung findet ihr in der Zip. Viel Spaß noch mit euren Projekttagen, liebe Klasse!
- Dateianhänge
-
- Grafik-Demo.rar
- (117.15 KiB) 1075-mal heruntergeladen
pantalytron: ルトロンはくそのディスアセンブラだよ!
Perikles hat geschrieben:Man muss sich das mal reinziehen: die Idee ist scheiße, die theoretische Ausarbeitung ist scheiße, die praktische Umsetzung ist scheiße und der so entstehende Anspruch noch beschissener.
- lytron
- Code Bro

- Beiträge: 2664
- Registriert: 12. August 2012, 20:18
- +Positive Tradingpoints+: 12 von 12
- Wohnort: ハノーファー区
- Kontaktdaten:
Re: Maggi-Fix für SNES Programmierung
Kategorie: SNES-Programmierung
Projekttage: Subroutinen und Stack
Liebe Schüler! Es sind immer noch Projekttage!
Heute machen wir einen kleinen theoretischen Kunststich in Aspik, während wir ein wenig über Subroutinen lernen. Wir gliedern es in drei Teile: Die Trockenübung, die Anwendung, die Erklärung. Die geneigten Schüler können dann früher oder später abspringen, sobald ihnen das alles bekannt ist.
Die Trockenübung:
Erklärung des Ablaufs und der einzelnen Befehle:
Es wird der Wert #$08 geladen. Dann erfolgt ein Jump zur Subroutine (JSR), die vielsagend „DieSubroutine“ heißt. Dort wird der Inhalt von A viermal inkrementiert, dann wird erfolgt der Return from Subroutine (RTS) und es geht im Hauptprogramm da weiter, wo wir aufgehört haben. In diesem Falle wird A dann in die Adresse $1000 gespeichert (das ist RAM).
Wir machen noch eine zweite Variante der Trockenübung:
Was ist hier der Unterschied? Wir verwenden JSL statt JSR und RTL statt RTS. Das „L“ in beiden Begriffen steht für „Long“, und hier geht es darum, dass Subroutinen, die sich auf einer anderen Bank befinden, nur mit den Long-Befehlen aufrufen lassen. Dazu später mehr.
Es folgt die Direktanwendung in unserer Beispieldatei. Wir wollen jetzt den kompletten siebten Absatz, das ist der Tilemap-DMA, in eine Subroutine auslagern. Diese Subroutine nennen wir „TilemapDMA“, und wir definieren sie unter dem Forever-Loop. Benutze keine Long-Befehle.
Die Lösung:
Die Erklärung: (Darauf haben wir alle schon gewartet)
Als wir unsere Daten noch mit der Schleife übertragen haben, hatten wir einen „Branch“-Befehl (also eine Abzweigung), in diesem Fall Springen wir. Es gibt ein paar Jump-Befehle und einen ganzen Stapel Branch-Befehle. Wann benutzt man was?
Zunächst muss man wissen:
Wird ein Jump-Befehl ausgeführt, notiert sich der Prozessor zuvor, wo er „stehengeblieben“ ist, als er jumpen sollte. Wenn er an ein „RTS“ oder „RTL“ kommt, bedeutet das für ihn, dass er mit der Ausführung der Subroutine fertig ist, und wieder an den Ausgangspunkt zurückkehrt, also schaut er in seine „Notizen“ und springt an die Stelle zurück. Beim Branchen ist das nicht der Fall.
Wo schreibt er sich das auf? Er legt das im Stack ab. Der Stack (englisch für Stapel) ist ein Bestimmter gekennzeichneter Bereich im RAM, der vom Prozessor als eigener Notizblock genutzt wird. Wenn du Lust hast, kannst du in die InitSNES.asm schauen, dort findest du ganz weit oben den Text:
Dabei wird der Anfang vom Stack auf $1FFF gesetzt. Das heißt: Wenn du einen JSR-Befehl benutzt, also ein Subroutinenaufruf auf derselben Bank durchgeführt wird, dann wird die Rückkehradresse in Register $1FFF und $1FFE abgelegt. Jaaa, genau, er zählt rück-, bzw. abwärts. Der Prozessor hat einen Pointer (also einen (An)zeiger), der ihm verrät, wo der „Pegelstand“ des Stacks sich beläuft. Welches Register er als nächstes Beschreiben kann. Dementsprechend kann er dann zurückrechnen, wo er die einzelnen Werte für seine Rucksprungadresse findet.
Obacht: Die RAM-Register, die für den Stack benutzt werden, sind in keinster Weise besonders geschützt. Das heißt: Wenn du eine Subroutine aufrufst und dabei deine Rücksprungadresse in $1FFF und aus Jux dasselbe Register als Zwischenspeicher für Rechenergebnisse nutzt... dann wird dein Programm ab dem RTS sicherlich sehr faszinierende Resultate zu Tage fördern. Allerdings rechne ich nicht damit, dass es eine besondere Augenweide sein wird.
Folglich nimmt man für soetwas eigentlich immer einen Recht abgeschotteten Bereich. Ich denke, mit $100 Byte wäre der Stack gut bedient (mich wundert, weshalb er hier mit #$1FFF bemessen wird). Einfache Empfehlung: Setz ihn auf #$01FF. Dann werden $0100 bis $01FF für Stack, du hast ab $0200 absolut freie Hand, und außerdem kommt er nicht mit den Direct Page Registern ins Gehege (Register $00FF kannst du z. B. auch einfach als $FF ansprechen).
Gut. Soweit, so, äh…
Also:
Wann verwendet man nun Branch-Befehle, wann macht man Jump to Subroutine? Exakt in Abhängigkeit davon, ob man an den Ausgangspunkt zurückkehren möchte oder nicht.
Subroutinen haben den Vorteil, dass du sie von überall aufrufen kannst und mit Hilfe des „RTS“/„RTL“ den Prozessor wieder dahin zurückschicken kannst, wo er herkam. Bei Branchbefehlen kannst du am Ende nur wiederum branchen, und das hieße: Egal, von wo du kommst, durch diese hohle Gasse musst du gehen, und den Branch am Ende musst du nehmen. Da dann mit unterschiedlichen Branchbefehlen in Abhängigkeit von Werten in bestimmmten Registern zu hantieren wäre vergleichsweise kompliziert.
Andererseits würdest du dir deinen schönen, schönen Stack mit Rücksprungadressen zukleistern, wenn du diese Rücksprungadressen auch nie nutzt.
Abschließend die Frage:
Wenn du eine Subroutine so aufbereitet hast, dass du sie von überall aus dem Programm heraus aufrufen kannst, was steht dann am Ende der Subroutine? Und wie rufst du sie auf, wenn du dich auf derselben Bank befindest?
Lösung 1:
Lösung 2:
So. Und hier haste auch noch den Sourcecode von heute.
Projekttage: Subroutinen und Stack
Liebe Schüler! Es sind immer noch Projekttage!
Heute machen wir einen kleinen theoretischen Kunststich in Aspik, während wir ein wenig über Subroutinen lernen. Wir gliedern es in drei Teile: Die Trockenübung, die Anwendung, die Erklärung. Die geneigten Schüler können dann früher oder später abspringen, sobald ihnen das alles bekannt ist.
Die Trockenübung:
Code: Alles auswählen
DasHauptProgramm:
LDA #$08.b
JSR DieSubroutine
STA $1000.w
(…)
DieSubroutine:
INC a
INC a
INC a
INC a
RTSEs wird der Wert #$08 geladen. Dann erfolgt ein Jump zur Subroutine (JSR), die vielsagend „DieSubroutine“ heißt. Dort wird der Inhalt von A viermal inkrementiert, dann wird erfolgt der Return from Subroutine (RTS) und es geht im Hauptprogramm da weiter, wo wir aufgehört haben. In diesem Falle wird A dann in die Adresse $1000 gespeichert (das ist RAM).
Wir machen noch eine zweite Variante der Trockenübung:
Code: Alles auswählen
DasHauptProgramm:
LDA #$08.b
JSL DieSubroutine
STA $1000.w
(…)
DieSubroutine:
INC a
INC a
INC a
INC a
RTLEs folgt die Direktanwendung in unserer Beispieldatei. Wir wollen jetzt den kompletten siebten Absatz, das ist der Tilemap-DMA, in eine Subroutine auslagern. Diese Subroutine nennen wir „TilemapDMA“, und wir definieren sie unter dem Forever-Loop. Benutze keine Long-Befehle.
Die Lösung:
versteckter Inhalt:
Als wir unsere Daten noch mit der Schleife übertragen haben, hatten wir einen „Branch“-Befehl (also eine Abzweigung), in diesem Fall Springen wir. Es gibt ein paar Jump-Befehle und einen ganzen Stapel Branch-Befehle. Wann benutzt man was?
Zunächst muss man wissen:
Wird ein Jump-Befehl ausgeführt, notiert sich der Prozessor zuvor, wo er „stehengeblieben“ ist, als er jumpen sollte. Wenn er an ein „RTS“ oder „RTL“ kommt, bedeutet das für ihn, dass er mit der Ausführung der Subroutine fertig ist, und wieder an den Ausgangspunkt zurückkehrt, also schaut er in seine „Notizen“ und springt an die Stelle zurück. Beim Branchen ist das nicht der Fall.
Wo schreibt er sich das auf? Er legt das im Stack ab. Der Stack (englisch für Stapel) ist ein Bestimmter gekennzeichneter Bereich im RAM, der vom Prozessor als eigener Notizblock genutzt wird. Wenn du Lust hast, kannst du in die InitSNES.asm schauen, dort findest du ganz weit oben den Text:
Code: Alles auswählen
LDX #$1FFF ;Setup the stack
TXS ;Transfer Index X to Stack Pointer RegisterObacht: Die RAM-Register, die für den Stack benutzt werden, sind in keinster Weise besonders geschützt. Das heißt: Wenn du eine Subroutine aufrufst und dabei deine Rücksprungadresse in $1FFF und aus Jux dasselbe Register als Zwischenspeicher für Rechenergebnisse nutzt... dann wird dein Programm ab dem RTS sicherlich sehr faszinierende Resultate zu Tage fördern. Allerdings rechne ich nicht damit, dass es eine besondere Augenweide sein wird.
Folglich nimmt man für soetwas eigentlich immer einen Recht abgeschotteten Bereich. Ich denke, mit $100 Byte wäre der Stack gut bedient (mich wundert, weshalb er hier mit #$1FFF bemessen wird). Einfache Empfehlung: Setz ihn auf #$01FF. Dann werden $0100 bis $01FF für Stack, du hast ab $0200 absolut freie Hand, und außerdem kommt er nicht mit den Direct Page Registern ins Gehege (Register $00FF kannst du z. B. auch einfach als $FF ansprechen).
Gut. Soweit, so, äh…
Also:
Wann verwendet man nun Branch-Befehle, wann macht man Jump to Subroutine? Exakt in Abhängigkeit davon, ob man an den Ausgangspunkt zurückkehren möchte oder nicht.
Subroutinen haben den Vorteil, dass du sie von überall aufrufen kannst und mit Hilfe des „RTS“/„RTL“ den Prozessor wieder dahin zurückschicken kannst, wo er herkam. Bei Branchbefehlen kannst du am Ende nur wiederum branchen, und das hieße: Egal, von wo du kommst, durch diese hohle Gasse musst du gehen, und den Branch am Ende musst du nehmen. Da dann mit unterschiedlichen Branchbefehlen in Abhängigkeit von Werten in bestimmmten Registern zu hantieren wäre vergleichsweise kompliziert.
Andererseits würdest du dir deinen schönen, schönen Stack mit Rücksprungadressen zukleistern, wenn du diese Rücksprungadressen auch nie nutzt.
Abschließend die Frage:
Wenn du eine Subroutine so aufbereitet hast, dass du sie von überall aus dem Programm heraus aufrufen kannst, was steht dann am Ende der Subroutine? Und wie rufst du sie auf, wenn du dich auf derselben Bank befindest?
Lösung 1:
versteckter Inhalt:
versteckter Inhalt:
- Dateianhänge
-
- subroutine.zip
- (118.36 KiB) 1064-mal heruntergeladen
pantalytron: ルトロンはくそのディスアセンブラだよ!
Perikles hat geschrieben:Man muss sich das mal reinziehen: die Idee ist scheiße, die theoretische Ausarbeitung ist scheiße, die praktische Umsetzung ist scheiße und der so entstehende Anspruch noch beschissener.
- lytron
- Code Bro

- Beiträge: 2664
- Registriert: 12. August 2012, 20:18
- +Positive Tradingpoints+: 12 von 12
- Wohnort: ハノーファー区
- Kontaktdaten:
Re: Maggi-Fix für SNES Programmierung
Kategorie: SNES-Programmierung
Projekttage: Stack-Befehle (Push/Pull) und CPU-Register
Morgen back ich, übermorgen (heim)brau ich,
heute erschlag ich eine Menge an ASM-Befehlen.
Erklärung von Push- und Pull-Befehlen in einem Satz: Man kann einiges an Registern direkt auf den Stack schmeißen oder von selbigem ziehen. Nachfolgend eine Liste, was alles geht.
Für die nächsten drei Befehle nenne ich die Bedeutung der Register (beim vierten Weise ich einfach nur noch einmal darauf hin, dass das das Flag-Register ist). Es handelt sich dabei um Register, in denen „Einstellungen“ vorgenommen werden.
Das Data Bank Register enthält einen Byte. Dieser Byte sagt, wenn man 16-Bit-Adressen benutzt, welche Bank gemeint ist. Das heißt: Wenn du irgendwann einmal so viel gecodet hast, dass du eine kompette Bank voll hast und auf die nächste wechselst, solltest du den Byte im Data Bank Register der aktuellen Bank anpassen. Denn sonst springst du mit den Labels (die dann in 16-Bit-Registeradressen umgewandelt werden) wieder auf die alte Bank zurück.
Übrigens, fällt mir ein, wird hier auch schön ersichtlich, weshalb der Code einer Bank erst ab Register $8000 adressiert wird: Die anderen Adressen dadrunter sind ja anderweitig reserviert ($0 - $1FFF RAM, $2000-$7FFF für Memory-Mapped-Input/Output-Register).
Das Direct Page Register setzt fest, wo die Direct Page Register sitzen. Direct-Page-Register meint: Die Register, die man mit 8-Bit-Adressen anspricht. Also $00 bis $FF. Der Inhalt des Direct Page Register ist 16-Bit groß und wird normalerweise auf $0000 gesetzt, somit sind die Register $0000 bis $00FF ansprechbar als $00 bis $FF. Setzt du $0021 in Direct Page Register, ist $00 = $0021, $01 = $0022 usw.
Das heißt, wenn es dich nervös macht, dass dein Stack potenziell deine Direct Page Register beschreiben könnte, kannst du mit diesem Wissen das jetzt ändern.
Das Program Bank Register ist… ach, fangen wir anders an.
Es gibt einen Counter. Der sagt dem Prozessor, was der nächste Byte ist, die er zu bearbeiten hat. Das Ding wird zum Beispiel durch den Reset-Vektor ganz am Anfang der ROM gesetzt (du erinnerst dich? Das Ding im SNES-Header, das auf das Label „Start“ zeigt).
Du erinnerst dich an die Geschichte mit den Subroutinen vom letzten Mal, wo ich sagte, der Prozessor macht sich eine Notiz auf dem Stack, wo er hin muss, wenn die Subroutine fertig ist? Die „Notiz“ ist, um genau zu sein, der Inhalt dieses Counters. Er schubst den auf den Stack und nimmt die Adresse der Subroutine in diesen Counter; wenn er fertig ist, lädt er einfach den alten Wert vom Stack in besagten Counter.
Das Program Bank Register wiederum enthält wiederum nicht den gesamten Counter (das wären 24 Bit für eine Long-Adresse), sondern nur die Bank. Normalerweise lässt man da den Prozessor sein eigenes Ding machen. Aber wenn man mal da herummanipulieren will, kann man das mit diesen Befehlen machen.
So. Bevor ich mit den letzten drei Befehlen weitermache, noch ein kleiner Auszug aus unserer InitSNES.asm. Ich möchte nochmal zeigen, wo diese Register oben in der Initialisierung „bedient“ werden:
Wie der Kommentar es bereits treffend beschreibt, wird die Data Bank der Program Bank gleichgesetzt, indem der Wert des Program Bank Registers auf den Stack geschmissen wird und sofort in das Data Bank Register gezogen wird.
Und damit kommen wir zu einem wichtigen Teil (der ist so wichtig, dass ich ihn am besten hier gelegentlich noch einmal wiederholen sollte): Push kopiert. Wenn du aus einem beliebigen Register auf den Stack pushst, ist der Ausgangswert immer noch im Ausgangsregister vorhanden. Du hast nur eine „Sicherheitskopie“ auf dem Stack abgelegt. Ebenso ist der Wert, den du vom Stack ziehst, immer noch da (bis er überschrieben wird), aber an den ranzukommen, ist ein bisschen mühselig (man müsste erst den Stack Pointer in den Akkumulator (Befehl TSC) oder das Register X (Befehl TSX) laden, die Adresse anpassen und dann laden).
Der zweite Teil ist: Es wird #$0000 in den Akkumulator geladen und dann mit TCD in das Direct Page Register übertragen. T steht für Transfer, D ist das Kürzel des Direct Page Register, C ist die Bezeichnung für den 16-Bit-Akkumulator. A ist eigentlich die Abkürzung für den 8-Bit-Akkumulator, B steht für den „ausgeblendeten“ Teil des Akkumulators (also die „versteckten“ 8 Bit), C ist der „große“ Akkumulator. Sollte man mal gehört haben, wobei dieses Wissen nur unregelmäßig von Nöten ist (zum Beispiel beim Befehl XBA, der die Inhalte von A und B austauscht).
Die letzten drei Befehle sind schon was für den Fortgeschrittenen-Bereich:
Mit PEA und einem nachfolgenden 16-Bit-Wert schmeißt man besagten Wert auf den Stack. Da es „Push Effective Absolute Address“ heißt, impliziert das schon, dass dieser Befehl dazu genutzt wird, Adressen auf den Stack zu schmeißen.
Mit PEI und einer nachfolgenden Direct-Page-Adresse wird der Inhalt des angegebenen DP-Registers (und dessen Nachbarn) auf den Stack gehauen. Beispiel: $1A enthält $80, $1B enthält $00. Ein „PEI $1A“ und ein anschließendes „RTS“ lassen einen zu $8000, also den Bankanfang zurückspringen.
Wie man sieht, wir hier der High Byte zuerst genannt. Aber das kann einem egal sein, weil man diesen Befehl selten nutzen wird.
Ach ja, übrigens, beim Push bleibt der Wert in den ursprünglichen Registern erhalten. Alle diese Dinge musst du nicht behalten, wenn du lieber mit dem Game Maker Spiele machen möchtest.
Mit PER (Push Effective PC Relative Indirect Address) kann man eine Adresse auf den Stack werfen, die aus einem Wert, den man mit dem Befehl übergibt, und dem aktuellen Programmcounter-Wert besteht. Mehr will ich mich damit nicht befassen, weil das definitiv zu sehr Special Case ist; wer Interesse hat, kann es im Handbuch nachlesen, Seite 374. Dort steht auch etwas über den Verwendungszweck:
Soweit dazu. Jetzt mal Anwendungsbeispiele:
Das macht man, wenn man nicht weiß, wie groß die A, X und Y sind, wenn die Subroutine aufgerufen wird. Es wird eine „Sicherheitskopie“ der Flags auf dem Stack abgelegt, danach kann man die Flags nach Belieben anpassen. Am Ende zieht man vor dem RTS noch den alten Status in das Flag-Register, und alles geht wieder seinen gewohnten Gang.
Der Lehrpunkt ist: Hier benutze ich für zwei ineinander verschachtelte Schleifen dasselbe Register als Counter. Zunächst setze ich X auf 0, dann beginnt „Aussen“: X wird auf den Stack geschoben, X noch einmal als Counter für „Innen“ geleert. „Innen“ wird viermal durchlaufen. Nach Abschluss von „Innen“ wird bei „Aussen“ der alte Counterwert wieder vom Stack gezogen, um acht erhöht, und mit $40 (als Endwert der „Aussen“-Schleife) verglichen.
Zum Abschluss, ein Mini, der super nützlich ist:
Es gibt keine Möglichkeit, X- und Y-Register noch schneller zu tauschen.
Projekttage: Stack-Befehle (Push/Pull) und CPU-Register
Morgen back ich, übermorgen (heim)brau ich,
heute erschlag ich eine Menge an ASM-Befehlen.
Erklärung von Push- und Pull-Befehlen in einem Satz: Man kann einiges an Registern direkt auf den Stack schmeißen oder von selbigem ziehen. Nachfolgend eine Liste, was alles geht.
- PHA/PLA – Akkumulator auf den Stack / Stackwert in den Akkumulator
- PHX/PLX – X auf den Stack / Stackwert in X
- PHY/PLY – Y auf den Stack / Stackwert in Y
- PHB/PLB – Data Bank Register auf den Stack / Stackwert in das Data Bank Register
- PHD/PLD – Direct Page Register auf den Stack / Stackwert in das Direct Page Register
- PHK/PLK – Program Bank Register auf den Stack / Stackwert in das Program Bank Register
- PHP/PLP – Status Register auf den Stack / Stackwert in das Status Register
- PEA – „Push Effective Absolute Address“
- PEI – „Push Effective Indirect Adress“
- PER – „Push Effective PC Relative Indirect Address“
Für die nächsten drei Befehle nenne ich die Bedeutung der Register (beim vierten Weise ich einfach nur noch einmal darauf hin, dass das das Flag-Register ist). Es handelt sich dabei um Register, in denen „Einstellungen“ vorgenommen werden.
Das Data Bank Register enthält einen Byte. Dieser Byte sagt, wenn man 16-Bit-Adressen benutzt, welche Bank gemeint ist. Das heißt: Wenn du irgendwann einmal so viel gecodet hast, dass du eine kompette Bank voll hast und auf die nächste wechselst, solltest du den Byte im Data Bank Register der aktuellen Bank anpassen. Denn sonst springst du mit den Labels (die dann in 16-Bit-Registeradressen umgewandelt werden) wieder auf die alte Bank zurück.
Übrigens, fällt mir ein, wird hier auch schön ersichtlich, weshalb der Code einer Bank erst ab Register $8000 adressiert wird: Die anderen Adressen dadrunter sind ja anderweitig reserviert ($0 - $1FFF RAM, $2000-$7FFF für Memory-Mapped-Input/Output-Register).
Das Direct Page Register setzt fest, wo die Direct Page Register sitzen. Direct-Page-Register meint: Die Register, die man mit 8-Bit-Adressen anspricht. Also $00 bis $FF. Der Inhalt des Direct Page Register ist 16-Bit groß und wird normalerweise auf $0000 gesetzt, somit sind die Register $0000 bis $00FF ansprechbar als $00 bis $FF. Setzt du $0021 in Direct Page Register, ist $00 = $0021, $01 = $0022 usw.
Das heißt, wenn es dich nervös macht, dass dein Stack potenziell deine Direct Page Register beschreiben könnte, kannst du mit diesem Wissen das jetzt ändern.
Das Program Bank Register ist… ach, fangen wir anders an.
Es gibt einen Counter. Der sagt dem Prozessor, was der nächste Byte ist, die er zu bearbeiten hat. Das Ding wird zum Beispiel durch den Reset-Vektor ganz am Anfang der ROM gesetzt (du erinnerst dich? Das Ding im SNES-Header, das auf das Label „Start“ zeigt).
Du erinnerst dich an die Geschichte mit den Subroutinen vom letzten Mal, wo ich sagte, der Prozessor macht sich eine Notiz auf dem Stack, wo er hin muss, wenn die Subroutine fertig ist? Die „Notiz“ ist, um genau zu sein, der Inhalt dieses Counters. Er schubst den auf den Stack und nimmt die Adresse der Subroutine in diesen Counter; wenn er fertig ist, lädt er einfach den alten Wert vom Stack in besagten Counter.
Das Program Bank Register wiederum enthält wiederum nicht den gesamten Counter (das wären 24 Bit für eine Long-Adresse), sondern nur die Bank. Normalerweise lässt man da den Prozessor sein eigenes Ding machen. Aber wenn man mal da herummanipulieren will, kann man das mit diesen Befehlen machen.
So. Bevor ich mit den letzten drei Befehlen weitermache, noch ein kleiner Auszug aus unserer InitSNES.asm. Ich möchte nochmal zeigen, wo diese Register oben in der Initialisierung „bedient“ werden:
Code: Alles auswählen
InitializeSNES:
PHK ;set Data Bank = Program Bank
PLB
LDA #$0000 ;set Direct Page = $0000
TCD ;Transfer Accumulator to Direct RegisterUnd damit kommen wir zu einem wichtigen Teil (der ist so wichtig, dass ich ihn am besten hier gelegentlich noch einmal wiederholen sollte): Push kopiert. Wenn du aus einem beliebigen Register auf den Stack pushst, ist der Ausgangswert immer noch im Ausgangsregister vorhanden. Du hast nur eine „Sicherheitskopie“ auf dem Stack abgelegt. Ebenso ist der Wert, den du vom Stack ziehst, immer noch da (bis er überschrieben wird), aber an den ranzukommen, ist ein bisschen mühselig (man müsste erst den Stack Pointer in den Akkumulator (Befehl TSC) oder das Register X (Befehl TSX) laden, die Adresse anpassen und dann laden).
Der zweite Teil ist: Es wird #$0000 in den Akkumulator geladen und dann mit TCD in das Direct Page Register übertragen. T steht für Transfer, D ist das Kürzel des Direct Page Register, C ist die Bezeichnung für den 16-Bit-Akkumulator. A ist eigentlich die Abkürzung für den 8-Bit-Akkumulator, B steht für den „ausgeblendeten“ Teil des Akkumulators (also die „versteckten“ 8 Bit), C ist der „große“ Akkumulator. Sollte man mal gehört haben, wobei dieses Wissen nur unregelmäßig von Nöten ist (zum Beispiel beim Befehl XBA, der die Inhalte von A und B austauscht).
Die letzten drei Befehle sind schon was für den Fortgeschrittenen-Bereich:
Mit PEA und einem nachfolgenden 16-Bit-Wert schmeißt man besagten Wert auf den Stack. Da es „Push Effective Absolute Address“ heißt, impliziert das schon, dass dieser Befehl dazu genutzt wird, Adressen auf den Stack zu schmeißen.
Mit PEI und einer nachfolgenden Direct-Page-Adresse wird der Inhalt des angegebenen DP-Registers (und dessen Nachbarn) auf den Stack gehauen. Beispiel: $1A enthält $80, $1B enthält $00. Ein „PEI $1A“ und ein anschließendes „RTS“ lassen einen zu $8000, also den Bankanfang zurückspringen.
Wie man sieht, wir hier der High Byte zuerst genannt. Aber das kann einem egal sein, weil man diesen Befehl selten nutzen wird.
Ach ja, übrigens, beim Push bleibt der Wert in den ursprünglichen Registern erhalten. Alle diese Dinge musst du nicht behalten, wenn du lieber mit dem Game Maker Spiele machen möchtest.
Mit PER (Push Effective PC Relative Indirect Address) kann man eine Adresse auf den Stack werfen, die aus einem Wert, den man mit dem Befehl übergibt, und dem aktuellen Programmcounter-Wert besteht. Mehr will ich mich damit nicht befassen, weil das definitiv zu sehr Special Case ist; wer Interesse hat, kann es im Handbuch nachlesen, Seite 374. Dort steht auch etwas über den Verwendungszweck:
Quaaasiii… Code auf dem Rücken einer wandernden Schildkröte. Soetwas ist beim SNES theoretisch machbar (wir haben schließlich den RAM), allerdings kann ich mir nicht vorstellen, dass soetwas jemals nötig ist.this instruction is helpful in writing self-relocatable code in which an address within
the program (typically of a data area) must be accessed
Soweit dazu. Jetzt mal Anwendungsbeispiele:
Code: Alles auswählen
Houdini_Subroutini:
PHP
SEP #$20.b
REP #$10.b
(…)
PLP
RTSCode: Alles auswählen
LDX #$0000.w
Aussen:
PHX
LDX #$0000.w
Innen:
(…)
INX
CPX #$0004.w
BNE Innen
(…)
PLX
INX
INX
INX
INX
INX
INX
INX
INX
CPX #$0040.w
BNE AussenZum Abschluss, ein Mini, der super nützlich ist:
Code: Alles auswählen
PHX
PHY
PLX
PLYpantalytron: ルトロンはくそのディスアセンブラだよ!
Perikles hat geschrieben:Man muss sich das mal reinziehen: die Idee ist scheiße, die theoretische Ausarbeitung ist scheiße, die praktische Umsetzung ist scheiße und der so entstehende Anspruch noch beschissener.
