Hello, Guest the thread was called2.4k times and contains 19 replays

last post from ZeroZero at the

Schnelles Speicherkopieren

  • Grundlage des Tips entstand hier.


    Aufgrund der Erklärung von Mac Bacon und nach "Studieren" der Systemroutine und des Kopierverfahrens aus anderen Snippets hier einmal die allgemeine Anleitung. Das Verfahren funktioniert für das Kopieren von ROM ins RAM, Bildschirme oder alle anderen Speicherbereiche.


    ABER ACHTUNG: die Systemroutine kopiert von hinten nach vorne und benutzt keinen Puffer. Es ist bei überlappenden Bereichen streng darauf zu achten, dass die Speicherbereiche sich nicht in der Weise überlappen, daß der ZIELbereich kleiner als der Quellbereich ist, dann schreiben die ersten Kopieraktionen mitten in den Quellbereich. Wenn der Zielbereich größer als der Quellbereich ist, geht es.


    Und so geht es: ihr benötigt die Anzahl der zu kopierenden Bytes PLUS 256! Der Einsprung in die Systemroutine erniedrigt zunächst den Blockzähler (Indexregister X) um 1.
    Also, um die 1000 Bytes des Textschirms zu sichern, im Beispiel nach 49152, berechnet ihr 1000 + 256 = 1256! Das Highbyte wird in das X-Register, das Lowbyte in das Y-Register geschrieben:


    10 POKE 781, 4 : POKE 782, 232 : REM 781 UND 782 SIND X UND Y REGISTER


    Dann braucht ihr die ENDadressen vom Quell- und vom Zielbereich + 1. Der Textschirm geht bekanntlich von 1024 bis 2023. 2024 (2023 + 1) sind LOWbyte = 232 und HIbyte = 7:


    20 POKE 90, 232 : POKE 91, 7


    Sichern wollen wir den Textschirm nach 49152. Plus 1000 Bytes ist 50151. Plus 1 = 50152 mit LOWbyte = 232 und HIbyte = 195:


    30 POKE 88, 232 : POKE 89, 195


    Jetzt nur noch in die Systemroutine BLTUC gegen Ende einspringen. Ein in vielen Büchern veröffentlichter Tip verwendet die Zeropageadresse 95/96, die aber vom Basicinterpreter beim Einlesen von Zahlenwerten überschrieben wird. Daher diese Alternative:


    40 SYS 41971


    Selbst große Datenmengen werden so in Basic in Sekundenbruchteilen umkopiert, viel Spaß!

  • Hallo MODS,


    könnt Ihr diesen Faden bitte wegen kompletten Bullshits wegwerfen?


    Habe die Systemroutine nochmal gecheckt, und leider gibt es keine Möglichkeit, die von Basic aus so zu verwenden, dass sie korrekt funktioniert.


    Bei ordnungsgemäßem Aufruf werden die Adressen auf Lowbyte 0 standardisiert, bevor mit Y indiziert wird. Das ist mit einem Einsprung an andere Stelle leider doch nicht zu machen. Die Anwendung, wie hier geschrieben ist BLÖDSINN und funkt nicht.


    SORRY

  • Habe die Systemroutine nochmal gecheckt, und leider gibt es keine Möglichkeit, die von Basic aus so zu verwenden, dass sie korrekt funktioniert.

    Bei den ganzen POKEs fällt eine zusätzliche Einsprungroutine auch nicht mehr ins Gewicht:

    Code
    1. stx 95
    2. sty 96
    3. jmp 41919

    Die sieben Bytes für diesen Code schreibt man irgendwo in den Speicher, und dann springt man diese Routine statt des Originals an. Vorher wird die Startadresse eben nicht in 95/96 geschrieben, sondern in 781/782.


    Oder man schreibt sich eh eine ganz eigene Kopierschleife. ;)

  • Oder man schreibt sich eh eine ganz eigene Kopierschleife. ;)

    Ja, würde ich dann eher machen. Da würde ich dann auch auf Überschneidung prüfen und entscheiden, ob ich von vorne oder von hinten kopiere :)


    Eigentlich war da die Hoffnung, für die reinen Basiker eine Möglichkeit anbieten zu können, mittels vorhandener OS-Routinen eine schnelle Speicherkopie bereitzustellen.


    Leider habe ich auch keine andere BASIC- oder KERNAL-Routine gefunden, die eine Speicherkopie macht :(

  • Du mußt nur die Kopierrichtung anpassen: Adressen vom Start her hochzählen, wenn Zielbereich-Start < Quellbereich-Start; Adressen vom Ende her herunterzählen, wenn Zielbereich-Start > Quellbereich-Start. Dann spielt es keine Rolle, ob die Bereiche überlappen oder nicht.


    Eine gute Auswahl allgemein einsetzbarer, kompakter und trotzdem brauchbar schnellen Kopier-Routinen findest Du auf 6502.org: http://6502.org/source/general/memory_move.html

  • diese Routine funktioniert:



    Code
    1. poke 95,<startadresse
    2. poke 96,>startadresse
    3. poke 90,<Endadresse+1
    4. poke 91,>Endadresse+1
    5. poke 88,<Endadresse_neu+1
    6. poke 89,>Endadresse_neu+1
    7. sys 41919

    Ist mir bisher nie aufgefallen, dass die Routine von Basic aus nicht richtig funktioniert.
    Vllt. hätte ich die mal von Basic aus nutzen sollen :facepalm::schande:

  • Hallo MODS,


    könnt Ihr diesen Faden bitte wegen kompletten Bullshits wegwerfen?

    Ich sehe eigentlich keinen Grund dazu.
    Im Gegensatz zu "ähnlichen Threads" von anderen Gesellen, siehst du ein, wenn etwas nicht in Ordnung mit dem Code ist und daraus ist hier eine Diskussion entstanden, die vielleicht zu was Besserem führt.

  • diese Routine funktioniert:



    Code
    1. poke 95,<startadresse
    2. poke 96,>startadresse
    3. poke 90,<Endadresse+1
    4. poke 91,>Endadresse+1
    5. poke 88,<Endadresse_neu+1
    6. poke 89,>Endadresse_neu+1
    7. sys 41919

    Ist mir bisher nie aufgefallen, dass die Routine von Basic aus nicht richtig funktioniert.
    Vllt. hätte ich die mal von Basic aus nutzen sollen :facepalm::schande:

    Mac Bacon hat das in dem anderen von mir im ersten Post referenzierten Faden erklärt: offensichtlich benutzt der Basic-Interpreter die Adressen 95/96 gelegentlich und damit wird die Startadresse vor Aufruf überschrieben und führt zu falschen Ergebnissen, hier direkt zum Crash.


    Ich habe jetzt keine Lust zu prüfen, ob dieses Verhalten z. B. durch Abschalten des Interrupts oder einen anderen Poke unterdrückt werden könnte für die Ausführung des Kopiervorgangs.

  • Was ich nur geil finde ist, dass dieser "Trick" zig mal in aller möglicher Literatur abgedruckt wurde und noch nie jemandem der
    Fehler aufgefallen ist. :gruebel

    Wie gesagt, ich habe den "Trick" direkt aus einem M&T aus der Reihe "Commodore Sachbuch".... Ist schon arg bedenklich. Traurig ist auch, dass trotz Fehlens eines Speicherverschiebe oder -kopier Opcode das OS des C64 keine entsprechende Routine zur Verfügung stellt (für die armen Nur-Basiker zum Aufruf).

  • Traurig ist auch, dass trotz Fehlens eines Speicherverschiebe oder -kopier Opcode das OS des C64 keine entsprechende Routine zur Verfügung stellt (für die armen Nur-Basiker zum Aufruf).

    Da kann man sich durchaus mal auf den Standpunkt stellen, daß das BASIC alle nötigen 'großen' Verschiebeoperationen intern mitbringt und sich so um die Speicherverwaltung kümmert (incl. Einfügen/Löschen von Programmzeilen und Verschieben der Arrays bei der Deklaration einfacher Variablen) und ansonsten ein BASIC-Programmierer mit dem 'großzügigen' Herumkopieren von Speicher doch nur Schindluder anstellen kann.

  • Ich habe mal gerade die 64'er-Sonderhefte 33 (Tips, Tricks & Tools) und 35 (Assembler), die ich gerade beiseite habe, durchgeblättert. Da wird die BLTUC genannte Verschieberoutine genannt und genutzt, allerdings nicht von Basic aus, sondern direkt in abgedruckten Assemblerprogrammen. Es ist wohl nicht davon ausgegangen, daß man sie jemals von Basic aus aufrufen sollte. Vielleicht würde ein kleines Programm in Assembler um den Aufruf herum das Problem lösen.


    Im Sonderheft 35, Seiten 64 bis 66 wird das z. B. gemacht. Mit der dort abgedruckten Routine wird der Bildschirm samt Farbram nach $E800 kopiert (am Ende wird noch der USR-Vektor verbogen, was ich aber mal weggelassen habe). Von Basic aus läßt sie sich über SYS 24576 aufrufen.


  • Ja, ein kleines MC löst das Problem natürlich, und wenn es nur ein Wrapper um BLTUC wäre, aber das war nicht der Zweck der Übung, dann hätte ich es nicht in BASIC eingestellt.

    Da kann man sich durchaus mal auf den Standpunkt stellen, daß das BASIC alle nötigen 'großen' Verschiebeoperationen intern mitbringt und sich so um die Speicherverwaltung kümmert (incl. Einfügen/Löschen von Programmzeilen und Verschieben der Arrays bei der Deklaration einfacher Variablen) und ansonsten ein BASIC-Programmierer mit dem 'großzügigen' Herumkopieren von Speicher doch nur Schindluder anstellen kann.

    Man kann natürlich die Programmierfreiheit auch als Schindluder bezeichnen, aber dann gehören alle anderen Programmiersprachen sofort auf den Müll. Ernsthaft: wenn ich "Schindluder" treiben will, dann ist das meine Sache als Programmierer, daher bleibe ich bei meinem Standpunkt und spreche Dir den Deinen natürlich nicht ab. Jeder, der mal mit C (oder C++ angefangen hat), ich z. B. 1988, der hat seine Erfahrungen mit Pointern gemacht und weiß eigentlich, was er tut. Nicht umsonst habe ich schließlich meinen OT korrigiert und vor BLTUC von Basic aus gewarnt.


    Und ja, es ist ja schön, dass das OS des C64 (BASIC und KERNAL) ohne weitere Speicherroutinen auskommt, das ändert aber nichts daran, dass damit eine schnelle Methode des Speichermoves ohne zugefügten Maschinencode nicht möglich ist und damit reine Basicer z. B. nicht sehr schnell mehrere Textbildschirme umkopieren können.


    So und nur so war dieser Faden gemeint, ohne irgendjemanden angreifen zu wollen oder bifforeske Standpunkte einnehmen zu wollen.


    Ich selbst kann mir sehr wohl mit Assemblercode weiterhelfen, aber in diesem Fall genügt es mir, dass der Basic-Boss in einer "Komfort"-Variante meiner Basic Routine die 24 kB von $A000 bis $FFFF in 2,4 (vorwärts), bzw. 2,7 (rückwärts) Sekunden ausführt. Das muss jetzt nicht per MC auf 0,5 Sekunden runter.


    Vielen Dank an alle, die hier Stellung bezogen, Hilfe geleistet oder alternative Standpunkte aufgezeigt haben!

  • Den hier hab ich noch:

    Man kann natürlich die Programmierfreiheit auch als Schindluder bezeichnen, [...]

    Ich stimme grundsätzlich mit dir überein, daß Programmierer schon wissen (sollten) was sie tun. Die zwei (K&R) sagen das nicht anders.


    Aber wenn ich das BASIC V2, so wie es implementiert ist, mal ganz knallhart als VM auffasse, die mich vor dem Unbill der Hardware des C64 abschirmen soll, ganz gleich welche Funktionalität letztenendes noch beim User ankommt: es hält *keine* Abstraktion eines Speichermodells oder Angaben, wo sich derzeit der Bildschirmspeicher befindet, vor! Es steht also aus Sicht des Programms grundsätzlich mal keinerlei Information zur Verfügung, wo sich welche Speicherbereiche befinden, die man irgendwo anders hinkopieren könnte! Damit hat eine solche Kopierfunktion einfach keinen Platz im BASIC.


    Natürlich *wollen* Programmierer über diese beschränkte Funktionalität hinaus kommen. Die Hardware kann einfach wesentlich mehr, als durch das BASIC beim Programmierer ankommt (das BASIC wäre mit einem reinen Textmodus zufrieden und Sound kennt es auch nicht). Alle derartigen Bemühungen greifen dann eben auf POKE, PEEK, SYS, USR und WAIT zu oder arbeiten direkt in Maschinensprache. Diese Lösungen funktionieren aber nur, weil es eine Offline-Dokumentation der Rechner-Hardware gibt - und bei dieser garantiert ist, daß sie sich nicht mehr ändert.

  • So als Ergänzung:


    Ich hab mal (vor Jahren™) in der 64'er (Tipps und Tricks) auf eine Systemroutine hingewiesen, die zumindest bis zu 255 Bytes transportiert: $b688. Sie ist Teil des Stringhandlings, deshalb prüft sie auf $00 (Leerstring), was dann keine 256 Kopierbytes mehr zulässt. Wenn man aber mal eben den Bildschirm (und seine Farben) irgendwo sichern möchte, reicht die Routine allemal. Hier ein Beispiel, das den Screen (ohne Farben) nach $3000 sichert:

    AN ist die Anzahl der in einem Durchgang zu kopierenden Bytes, BL ist die Anzahl der insgesamt zu kopierenden Blöcke (Pages). Q ist die Quelladresse ($0400) und Z das Ziel ($3000). in 1020/1030 werden die Adressen in High und Lo gesplittet und in 1000 die Systemroutine gefüttert und aufgerufen. Zeile 160 erhöht zur nächsten Page (minus 1 Byte) und Zeile 170 zählt die Pages (wobei dann am Ende BL (=4) Bytes fehlen, was aber hier keine Rolle spielt).


    Vielleicht kann's ja wer gebrauchen.


    Arndt

  • Vielleicht noch die exakte Routine von der 64'er (da ging's darum, das ROM ins RAM zu kopieren):

    Code
    1. 10 a=160:e=192:fori=0to1:poke53,0:poke54,a
    2. 20 poke780,255:poke781,peek(53):poke782,peek(54):sys46728:ifpeek(54)<>ethen20
    3. 30 a=224:e=0:next

    Braucht 2,7 Sekunden.


    Arndt


    Edit: Das Splitting mit AND NOT geht nur bis $8000 (32768). Bei größere Adressen wieder das übliche Schema verwenden... ;-)

  • Vielleicht noch die exakte Routine von der 64'er (da ging's darum, das ROM ins RAM zu kopieren):

    Code
    1. 10 a=160:e=192:fori=0to1:poke53,0:poke54,a
    2. 20 poke780,255:poke781,peek(53):poke782,peek(54):sys46728:ifpeek(54)<>ethen20
    3. 30 a=224:e=0:next

    Braucht 2,7 Sekunden.


    Arndt

    2,7 Sekunden schafft das BB-Kompilat auch aus der reinen Basic-Routine. Wird wohl nochmal schneller, wenn ich für den BB Konstanten deklariere. Und das ist dann die Rückwärtsschleife mit Step -1. Die Vorwärtsschleife braucht 2,4 Sekunden, jeweils von $A000 bis $FFFF.
    Das ist mir schnell genug und hat den Vorteil, dass ich beliebige Bereiche kopieren kann und nicht nur komplette Blöcke. Aber dennoch DANKE für den Hinweis.


    P.S.: die "falsche" Routine mit Verwendung von 95/96 ist auch im 64er Sonderheft 2/1986 auf Seite 156 propagiert.... Peinlich, peinlich....