Hallo Besucher, der Thread wurde 7,5k mal aufgerufen und enthält 53 Antworten

letzter Beitrag von Mike am

Viele Sprünge usw - wie handhabt ihr das?

  • Aber ohne Not? Warum?

    Warum nicht, solange der Code dadurch nicht unverständlich wird?

  • Aber ohne Not? Warum?

    Von mir schon in Post #30 beantwortet und in diesem Thread auch genauer ausgeführt:

    Zitat von Mike

    wenn's geht und Sinn macht.


    Dogmatisches Verteufeln einer Programmiermethode bringt dich nicht weiter. Du wirst auch niemand davon abhalten können, diese Technik einzusetzen. Nochmal: auf dem Abstraktionslevel, wo die CPU hier operiert, ist das völlig egal - die führt alles aus, was Du ihr vorsetzt und wird sich nicht über mangelhaften "Stil" beschweren (die "Problematik" einer Harvard-Architektur mal ausgenommen).


    Wenn Du für dich alleine und als Zeitvertrieb programmierst, bist Du der einzige der sich ein Urteil über deinen Code erlauben kann. Wenn hier im Forum aber Programmiermethoden oder -ideen zusammen getragen werden, dann ist alles erlaubt was funktioniert. Zwingt dich ja keiner, das selbst einzusetzen. Und wenn was abstürzt, wird nur der Rechner neu gebootet.


    Anders sieht's eben im Beruf aus. Da sollte man sich schon gut überlegen, mit welcher Programmierung man 10 MW elektrische Leistung auf die Last losläßt. :bgdev

  • Wenn Du für dich alleine und als Zeitvertrieb programmierst, bist Du der einzige der sich ein Urteil über deinen Code erlauben kann. Wenn hier im Forum aber Programmiermethoden oder -ideen zusammen getragen werden, dann ist alles erlaubt was funktioniert. Zwingt dich ja keiner, das selbst einzusetzen. Und wenn was abstürzt, wird nur der Rechner neu gebootet.

    Was ist daran auszusetzen, dass es hier auch mal Feedback gibt, wie sowas im professionellen Umfeld gehandhabt wird.


    Natürlich kann jeder programmieren wie er will (das wird er sowieso tun), aber das ändert nichts daran, das ich das ggf. für unsinnig halte. Weil ich aus Erfahrung weiß, dass es langfristig oft Nachteile bringt - wenn man den Code nach 3 Jahren noch mal verstehen will, wenn man den Code doch mal weitergeben möchte, wenn der Code doch mal auf eine ROM-Cartridge soll.


    Nehmt es doch einfach mal als Hinweis, darüber nachzudenken, ob es sinnvoll ist. ;)


    Und wenn ich schreibe, dass selbstmodifizierender Code "ganz ganz BÖSE" ist - also wer da die Ironie nicht herausliest (auch ohne Smiley), dem kann ich auch nicht helfen.

  • wenn man den Code nach 3 Jahren noch mal verstehen will

    Mach ruhig 6 Monate daraus. Die reichen schon aus um eigenen undokumentierten Code unverständlich zu machen. Den hätte ebensogut jemand anders schreiben können. Ansonsten...

    also wer da die Ironie nicht herausliest

    Keine Sorge, so viel war mir schon klar. Aber da Du es auch noch für notwendig erachtet hattest, diese Aussage hier im Thread argumentativ zu unterfüttern, kamen von mir eben auch noch gute Gegenargumente. ^^
    Also, ein Bierchen (oder ein anderes, nicht-alkoholisches Getränk deiner Wahl) geht immer: :bia

  • Also, ein Bierchen (oder ein anderes, nicht-alkoholisches Getränk deiner Wahl) geht immer:

    Bei einem Bierchen (oder mehr) könnte man dieses Thema noch nächtelang vertiefen. :drunk:

  • Der Code stammt aber eben immernoch nur aus den Eprom- / Rombausteinen des Moduls. Der wird dann sonstwo in ein Ram hingeladen (manchmal auch entpackt) und erst da beginnt im Grunde das Programm. ... 64KB Mega Drive, 128KB SNES dazu jeweils noch etwas Video- und Soundram. ... Nur da läuft das Programm ab. Zwischendurch wird immer 'was vom Modul in dieses Ram nachgeladen u. (anschließend) ggf. entpackt. ...


    Manchmal macht das Bild + Ton auch bei ein paar Spielen vor einem Boss eine ca. 0,5 bis 1,0 sekündige Pause, weil in der Zeit etwas vom Modul (der upcoming Boss + Bossroutinen + ein neuer Tune) nachgeladen wird [Strider, Golden Axe, Ghouls 'n Ghosts fällt mir da z.B. ein]. ;) Oder mindestens etwas schon im Ram vorhandenes entpackt wird.


    In diesen kurzen Pausen werden Grafikdaten in den dedizierten Videospeicher geschauffelt. (Vergleichbar mit dem C 128 und dessen VDC-Chip.) Ausserdem besitzen beide Konsolen spezielle Audio-CPUs mit wiederum eigenem Speicher, der auch gefüttert werden will. Aber der eigentliche Programmcode verbleibt weiterhin auf dem Modul und wird von da aus ausgeführt.


    Verwechselst du das vieleicht mit CD-ROM-basierten Konsolen?

  • Also um es jetzt mal etwas genauer zu erklaeren. Wenn ich selbstmodifizierenden Code einsetze, sieht der bei mir z.B. IMMER so aus:


    .o1 LDA $FFFF
    .o2 STA $FFFF


    Die Labels sind direkt vor dem Statement und heissen .o1 oder .o2, das "o" steht fuer overwrite, und die Labels sind nur 3 Zeichen lang damit sie eben noch vors Statement passen. Wenn ich sowas in meinem Code sehe, dann weiss ich IMMER, dass hier eine Adresse ueberschrieben wird. Davor ist dann irgendwo die Initialisierung, wo eben .o1 +1 und .o1 +2 mit der Adresse ueberschrieben werden.


    Wenn man sich an seine eigenen Regeln haelt, dann sehe ich da wirklich UEBERHAUPT kein Problem. Ich habe auch noch nie den Code irgendwie anders modifizert, als Start- oder End-Adressen zu ueberschreiben bei z.B. Kopier-Vorgaengen innerhalb des Speichers usw.


    Natuerlich kann man das auch mit indirekten Adressen machen, aber da stoert mich bereits, dass man dann immer auch ein Register braucht. Oder ist ein LDA ($FF) zulaessig? Waere mir neu. Also brauche ich immer ein X oder ein Y, welches ich auf null setzen muss, um sowas zu machen. Vielleicht sind meine Register aber schon anderweitig in Benutzung, dann muss ich die zwischenspeichern ueber irgendwelche TXA PHA Orgien, oder ich muss mir zwei lokale Variablen namens .x und .y machen, aber das finde ich alles umstaendlich, unschoen, und unpraktisch. Da ist fuer mich das Ueberschreiben mit der Adresse ein Segen. Und das mache ich wie gesagt schon seit meinem ersten Projekt genau auf die gleiche Art und Weise und habe da noch nie an irgendeiner Stelle Probleme damit gehabt oder nach 6 Monaten den Code nicht mehr verstanden oder sonstiges.


    Natuerlich kann das jeder machen wie er mag, ich machs aber so und finde dass das die beste Loesung ist.

  • Also einfache C64-Module haben definitiv den Code direkt aus dem ROM
    ausgeführt. Natürlich, komplexere Module, die irgendein Bankswitching
    machen, müssen natürlich die Sachen wechselweise ins RAM bringen. Das
    hängt aber eben von den jeweiligen Gegebenheit ab.


    Auch hier nochmal Einspruch, Euer Ehren.
    Das SNES kann an seinem Adressbus A bis zu 16 MB adressieren, weshalb diese Aussage einfach nur falsch ist. Ich bin kein SNES Programmierer, bin mir aber sehr sicher dass weite Teile des Codes nicht umkopiert werden sondern direkt aus dem ROM laufen - alles andere wäre Verschwendung von Ressourcen, und da tun sich Hersteller schwer mit.

    Ich bin auch kein SNES-Programmierer und kenne die Hardware kaum, aber die 65816 CPU könnte das Problem haben, das ROM-Zugriffe zu langsam sind und kritische Codesequenzen tatsächlich im RAM landen. Ich weiß nicht, ob es zu SNES-Zeiten vertretbar war entsprechende schnelle ROMs für Module zu verwenden vertretbar war. Das wird auch bei diversen Turbokarten für den C64 so gehandhabt, das aus dem ROM in ein Shadow-RAM kopiert wird damit die CPU den Code mit maximaler Taktfrequenz ausführen kann. Also ich kann mir da schon vorstellen, dass es da eine Mischkonstellation gegeben haben könnte.
    Jedenfalls halte ich die Aussage, dass *immer* ins RAM kopiert wurde und dort ausgeführt wurde als allgemeine Aussage ebenso für falsch.

  • @Mike und @detlef Danke für eure Erklärungen! Tut mir leid für das OFF Topic.
    Das Beispiel mit deiner Zeichenroutine finde ich sehr interessant. Das hat für mich einen Hauch von Lambda Funktion, aber eben auf Assembler Ebene. Aber würde sich das nicht auch durch einen Jump auf eine jeweilige konfigurierte Unterfunktion (und daher Adresse) realisieren lassen?
    Natürlich mit etwas Laufzeit Einbuße. Also eine Mini Unterfunktion.

    Bei mir ist es mit meiner Grafikerweiterung genauso. Obwohl ich die unterschiedlichen Linienfälle nicht durch Modifizierungen im Code zu einem zusammenschmelze, so ist es schon alleine für den Zeichenmodus (löschen, setzen, invertieren) bei mir so, dass ich über einen zentrale Routine gehe (es gibt ja nicht nur die Linienbefehle, sondern alle anderen verwenden die auch), die je nach Modus "gepatcht" wird. Wie @Mike schon sagte, ist es gerade bei Grafikroutinen so, dass Fallunterscheidungen für den Zeitaufwand absolut geschwindigkeitstötend sind ... das leisten sich halt manche Grafikerweiterungen oder BASIC-Varianten, weil sie ja im ROM laufen. Notwendig ist es nicht immer, denn auch meine Grafikerweiterung habe ich in einer ROM-/Shadow-ROM-Umgebung im Einsatz und da ist der Code nicht ohne weiteres beschreibbar. Die Grafikmanipulationsroutine, die gepatcht wird, ist hier dann im RAM ausgelagert. Allerdings auch mit den Kosten für JSR/RTS, welche noch vermeidbar wären.
    Aber gerade bei Assembler und bei den entsprechenden Ressourcenknappheiten heiligt der Zweck die Mittel, mit einer gewissen Verhältnismäßigkeit. Bei einer Tastenabfrage mag eine Einsparung von ein paar Takten oder Bytes mit Hilfe von selbstmodifiziertem Code vielleicht nicht wirklich angebracht sein, aber wenn jemand das als präferierten Stil hat, dann soll sich auch niemand daran stoßen. ;)

  • Ich finde auch, dass Spaghetti-Code, Wiederverwertbarkeit und Selbstmodifikation verschiedene paar Schuhe sind.


    Grad unsere Form von Assembler erlaubt ja Konstruktionen, die so gar nichts mit strukturiertem Programmieren zu tun haben, und die werden auch zu Hauf verwendet.
    Da werden Register nicht initialisiert, weil sie aus einem vorher abgelaufenem Unterprogramm verwendet werden können.
    Es wird mitten in andere Unterprogramme gesprungen, oder an deren Ende, um Befehle für Rückgabewerte zu verwenden.
    Man kann Programme schreiben, die nur an bestimmten Adressen funktionieren, weil man Zeiger in der ZP mit "zufällig" vorhandenen Registerwerten initialisiert.
    3-Byte-Befehle können 2-Byte-Befehle verstecken.


    Manche Selbstmodifikation kann dagegen sehr übersichtlich und schnell offensichtlich sein.


    Oft genug muss ein Unterprogramm auch gar nicht "sicher" genug für alle Anwendungen programmiert sein.
    Falls ein Unterprogramm Register retten will: MUSS es das auf dem Stack tun, damit es parallel aus dem Hauptprogramm und einem IRQ anwendbar ist?
    Falls es ZP-Adressen benutzt, müssen die exklusiv sein, oder dürfen andere Unterprogramme die ebenfalls verwenden und kaputt machen?