Flash und RAM: Codeausführung

Ich habe vor kurzem angefangen, Assembler zu lernen, und habe Linker-Skripte und andere grundlegende Details der Hardwareprogrammierung kennengelernt. Ich bringe mir auch selbst Computerarchitektur bei und irgendwann befürchtete ich, dass mein Bild vom Speichermodell die ganze Zeit falsch gewesen sein könnte.

Nach dem, was ich derzeit verstehe, befinden sich der gesamte Code und die Daten im nichtflüchtigen Speicher, unmittelbar nachdem wir die Binärdatei auf einen Prozessor "gebrannt" haben - der flüchtige RAM enthält beim Zurücksetzen nichts. Wenn das Programm mit der "Ausführung" beginnt, tut es dies von der Adresse 0x0000, die fast immer (AFAIK) die niedrigste Adresse in Flash ist. Anweisungen werden also auf den Bus zwischengespeichert, der Flash mit dem CPU-Kern verbindet, und dort findet die eigentliche Ausführung statt. Wenn wir jedoch davon sprechen, dass die CPU Daten aus dem Speicher abruft oder speichert, sprechen wir normalerweise über RAM - mir ist bewusst, dass wir auch Daten aus dem Programmspeicher lesen / schreiben können (ich habe dies bei AVRs gesehen). aber ist es nicht so üblich? Liegt es daran, dass RAM schneller als ROM ist, dass wir Daten lieber dort speichern?

Die akzeptierte Antwort auf diese Frage besagt, dass die meisten Codeteile außerhalb des Arbeitsspeichers ausgeführt werden.

Bedeutet dies, dass der Start-Laufzeitcode (der selbst von Flash ausgeführt wird) alle Programm-Opcodes von Flash in RAM kopieren und die Adressen in Flash irgendwie so zuordnen muss, dass sie auf RAM zeigen, damit die CPU Opcodes von dort abruft? Ist es dem Vorgang ähnlich, bei dem wir die .data-Abschnitte beim Start vom ROM in den RAM verschieben?

Ich kann mir vorstellen, dass dies in von Neumann-Architekturen einfacher ist, in denen sich Programm- und Datenspeicher einen Bus teilen, aber in Harvard-Architekturen würde dies nicht bedeuten, dass der gesamte Code und die Daten zuerst die CPU-Register durchlaufen müssen?

Wie Sie wahrscheinlich erraten können, bin ich ein wenig zu verwirrt von dieser ganzen Sache. Da ich immer auf einer höheren Abstraktionsebene programmiert habe, bin ich mit solchen Details leicht beunruhigt. Jede Hilfe ist willkommen.

Bei einfachen Mikrocontrollern muss zur Ausführung nicht vom Programmspeicher (heute häufig Flash) in den RAM kopiert werden.
Das liegt alles daran, dass ein RAM schneller als Flash ist, aber da es nach einem Stromausfall Daten verliert, kommt der nichtflüchtige Speicher Flash. Wenn der Strom eingeschaltet ist, werden Daten vom Flash in den RAM geladen und die CPU beginnt zu arbeiten, all das wiederholt sich.

Antworten (3)

Dies hängt vom Gerät ab.

RAM kann schneller gebaut werden als Flash; dies beginnt etwa im 100-MHz-Bereich wichtig zu werden.

Einfache Mikrocontroller

Kleine langsame Mikrocontroller werden direkt aus dem Flash heraus ausgeführt. Diese Systeme haben normalerweise auch mehr Flash als SRAM.

Midrange-Systeme

Sobald Ihr Gerät schneller wird, sieht die Situation etwas anders aus. Mittelklasse-ARM-Systeme können dies ebenfalls tun, oder sie verfügen möglicherweise über einen Masken-ROM-Bootloader, der etwas Intelligenteres tut: vielleicht das Herunterladen von Code von USB oder externen EEPROMs in den internen SRAM.

Große Systeme

Größere, schnellere Systeme verfügen über externes DRAM und externes Flash. Dies ist typisch für eine Mobiltelefonarchitektur. An diesem Punkt ist viel RAM verfügbar und es ist schneller als der Flash, sodass der Bootloader es kopiert und ausführt. Dies kann das Schaufeln durch die CPU-Register beinhalten oder es kann eine DMA-Übertragung beinhalten, wenn eine DMA-Einheit verfügbar ist.

Harvard-Architekturen sind in der Regel klein, stören Sie sich also nicht an der Kopierphase. Ich habe einen ARM mit "Hybrid-Harvard" gesehen, bei dem es sich um einen einzelnen Adressraum handelt, der verschiedene Speicher, aber zwei verschiedene Abrufeinheiten enthält. Code und Daten können parallel geholt werden, solange sie nicht aus demselben Speicher stammen. Sie könnten also Code aus Flash und Daten aus SRAM oder Code aus SRAM und Daten aus DRAM usw. abrufen.

RAM ist im Allgemeinen schneller als Flash, aber es spielt keine Rolle, bis Sie Taktraten von über 80-100 MHz oder so erreichen - solange die Flash-Zugriffszeit schneller ist als die Zeit, die zum Ausführen einer Anweisung benötigt wird sollte keine Rolle spielen.

Die physische Konstruktion von RAM ermöglicht es uns, sehr schnelle Geräte zu bauen; viel schneller als Flash. An dieser Stelle ist es sinnvoll, Codeblöcke vor der Ausführung in den Arbeitsspeicher zu kopieren. Dies bringt auch zusätzliche Vorteile für den Entwickler, z. B. die Möglichkeit, Code zur Laufzeit zu ändern.

In von Neumann-Architekturen, in denen sich Programm- und Datenspeicher einen Bus teilen, würde dies in Harvard-Architekturen nicht bedeuten, dass der gesamte Code und die Daten zuerst die CPU-Register durchlaufen müssen?

Nicht unbedingt. Hier kommt die virtuelle Adressierung ins Spiel. Anstatt dass Programmcode auf die rohen Hardware-RAM-Adressen verweist, verweist er tatsächlich auf einen virtuellen Adressraum. Blöcke des virtuellen Adressraums werden physischen Speichergeräten zugeordnet, die RAM, ROM, Flash oder sogar Gerätepuffer sein können.

Wenn Sie beispielsweise auf einem Mikro auf die Adresse 0x000f0004 verweisen, lesen Sie möglicherweise die Adresse 0x0004 aus dem Flash. Die virtuelle Adresse ist 0x000f0004, aber die physische Adresse ist nur 0x0004 – der gesamte 0x000fxxxx-Adressraum wird einem physischen 4-KB-Speichergerät zugeordnet. Dies ist natürlich nur ein Beispiel, und die Methode zum Verwalten und Organisieren des virtuellen Adressraums ist je nach Architektur sehr unterschiedlich.

Wenn Sie also sagen, dass "das Programm mit der Ausführung [...] von der Adresse 0x0000 beginnt, die fast immer die niedrigste Adresse im Flash ist", haben Sie nicht garantiert Recht. Tatsächlich beginnen viele Mikrocontroller bei 0x1000.

Ich hätte gesagt, dass die Unterscheidung bei etwa 20-40 MHz relevant wird, nicht bei 100 MHz, da die meisten Flash-Geräte, die ich gesehen habe, um diesen Punkt herum einen Wartezustand erfordern. In vielen Fällen enthält Code-Flash Schaltungen, so dass jeder Abruf mehrere Befehlswörter erfasst, sodass die „Strafe“ für das Ausführen aus dem Flash für viele Arten von Code nur etwa 5-10% beträgt, für einige andere Arten jedoch Code (z. B. mit vielen Sprüngen) kann die Strafe viel strenger sein.
Das ist keine virtuelle Adressierung, das ist speicherabgebildete E/A (der Speicherbereich wird mithilfe eines Peripheriegeräts auf E/A abgebildet, der Name vieler MCUs lautet "Static Memory Controller"). Natürlich greift die I/O auf einen anderen Speicher zurück, daher betrachten wir es manchmal nicht als I/O. Aber es ist definitiv keine virtuelle Speicherzuordnung.

Was Sie sagen, ist nicht ganz richtig oder falsch. Dafür gibt es verschiedene Szenarien.

Das hängt davon ab, ob Sie auf der Rohhardware oder auf der mit OS installierten Hardware programmieren.

Ihr Betriebssystem, das auf dem Allzweckcomputer ausgeführt wird, ruft Code von der Festplatte ab und speichert ihn für einen schnelleren Zugriff im RAM. Wenn Ihr Prozessor ständig versucht, direkt von der Festplatte abzurufen, wäre der Betrieb aufgrund von Geschwindigkeitsunterschieden zwischen beiden viel langsamer. Ihr RAM kommt also ins Spiel, wo ein Teil Ihres sich wiederholenden Codes für einen schnelleren Zugriff gespeichert wird. Und auch das wird noch weiter auf dem Cache-Speicher des Prozessors zur Verfügung gestellt, um ihn noch schneller zu machen.

Wenn Sie jetzt an einem Mikrocontroller arbeiten, hängt es ganz von Ihnen ab, wo Sie Ihre Daten auf dem Chip speichern. Wenn die Daten statisch sind, möchten Sie sie möglicherweise im Codespeicher lokalisieren, wodurch Ihr RAM gespart wird, der vergleichsweise viel kleiner als der Codespeicher ist. In der C-Sprache werden beim Initialisieren des Datentyps mit static oder in einigen Compilern const-Präfixdaten im Codespeicher oder im RAM gespeichert. Und in der Assembly verwenden Sie direkt DB (Define Byte im Fall von Basic 8051), um Daten an der jeweiligen Stelle zu initialisieren. Jetzt können Sie sogar in einigen Controllern wie PIC ARM ROM zur Laufzeit schreiben, aber das Abrufen von Daten wird viel Zeit in Anspruch nehmen.

Außerdem gibt es Bootloader-Hardware in mittleren und anspruchsvollen Controllern, die den Controllern oder Prozessoren mitteilt, von wo aus der Startcode ausgeführt werden soll, oder es selbst ist der Startcode, der tatsächlich in den Speicher segmentiert wird. Es gibt also viele Möglichkeiten aufgrund von Weiterentwicklung , ich würde eher hybride Weiterentwicklung in der Branche sagen, die das gesamte Konzept von herkömmlichem RAM, ROM und Speichern durcheinander bringt. Also im Grunde ist Ihre Verwirrung gültig.