Wie ist der in ARM7 geschriebene Code mit ARM9 kompatibel?

Ich studiere ARM-Familien,

Geben Sie hier die Bildbeschreibung ein

Im obigen Bild steht geschrieben, dass der Code von unterstütztem ARM7 auf ARM9 und andere migriert werden kann.

ARM7 verwendet die Von-Neumann-Architektur (einzelner Bus für Daten und Anweisungen) und eine dreistufige Pipeline (dh Abrufen, Decodieren und Ausführen). ARM9 und andere verwenden die Harvard-Architektur (separater Bus für Daten und Anweisungen) und 5-Stufen (Abrufen, Decodieren, Ausführen, Speichern und Schreiben (für ARM9)). Außerdem unterstützt ARM7 keine Speicherverwaltungseinheit, andere jedoch schon.

Wie kann der Code kompatibel sein, wenn die Prozessoren unterschiedliche Architekturen und Pipelines verwenden? Wird es keinen Einfluss von Architekturen auf die Codes geben?

Ich gehe davon aus, dass ARM9, ARM10, ARM11 dieselbe Architektur haben, Code kompatibel sein kann, ARM7 sich jedoch von anderen Prozessoren unterscheidet. Daher müssen vor der Migration aufgrund unterschiedlicher Architekturen einige Änderungen am Code vorgenommen werden. Ich frage mich, ob es richtig ist oder nicht.

Ich wünschte, alle würden aufhören, sich über Harvard gegen von Neumann aufzuregen. Auf dem Gebiet ist ein echtes Harvard etwas nutzlos, es ist eine akademische Übung. Modifiziertes Harvard, was die meisten Prozessoren nur sind, bedeutet, dass einige Steuersignale auf dem gemeinsam genutzten Bus anzeigen, dass diese Übertragung ein Abruf ist, und das sind Daten. Natürlich hat der Speicher/E/A-Bus absolut nichts mit dem Prozessorkern und dem Befehlssatz zu tun, noch die Art der Pipeline. Schauen Sie sich x86 an, wenn nichts anderes, aber Mips, Arm, so ziemlich jeder Kern, der mehr als ein Produkt gesehen hat.
Schauen Sie sich einfach MIPS an, jeder andere Ingenieur auf der ganzen Welt musste eine Art Mips-Simulator oder Verilog-Implementierung durchführen, manchmal seriell und manchmal auch parallel, wobei alle nach einer binären Spezifikation für den Maschinencode, die Pipeline-Tiefe, die Signalnamen usw. suchen alles bis zum Programmierer/Ingenieur. Nehmen Sie 100 Ingenieure, geben Sie ihnen den Armv4t-Befehlssatz und sagen Sie ihnen, sie sollen impementen, dass Sie irgendwo zwischen 1 und 100 verschiedene Lösungen erhalten, die alle vollkommen gültig sind. das eine hat mit dem anderen nichts zu tun.
Die armv4t-Anweisungen wurden bis zu den armv8-Implementierungen unterstützt, die in aarc32 (armv7-kompatibler Modus) ausgeführt werden. Wenn/wenn Sie nur die Armdokumentation lesen, werden Sie sehen, dass im Laufe der Zeit neue Anweisungen hinzugefügt werden. Sie raten von der Verwendung von swp in Multi-Core-Implementierungen ab, wenn der Kern den Speicher teilt, aber glauben Sie nicht, dass sie die Anweisung tatsächlich entfernt haben, die meisten Leute lesen nicht wirklich über ldrex/strex oder wie man es benutzt und missverstehen die swp-Sache.
Einige Fehler und IP-Schutz ("unvorhersehbare Ergebnisse") im ARM7TDMI wurden behoben, wie Sie sehen werden, wenn Sie die Handbücher im Laufe der Zeit lesen. Der Arm9 hat aufgrund der damaligen Technologie möglicherweise einige neue hinzugefügt, aber seitdem ist die Validierung besser geworden.
@old_timer Sind PIC- und AVR-Prozessoren nutzlos?
@WayneConrad sicherlich nicht, sie sind immer noch super beliebt. Avrfreaks gingen der Arduino-Community voraus, die wirklich keinen Rivalen hat. leider sind beide unter Mikrochip. ateml war sehr gut mit Dokumenten und ihre Community und Microchip waren ziemlich schlecht darin. Sie sind vollständige Produkte, nicht irgendein fremdes Prozessor-IP, das sie so eingezogen und herumgeklebt haben. Vielleicht haben sie immer noch Sachen aufgeklebt, wer weiß, woher ihre IP ursprünglich stammt, aber sie sind immer noch eine Kraft auf dem Markt.

Antworten (4)

Ein Prozessor wird als Code-kompatibel mit einem anderen bezeichnet, wenn sein Befehlssatz kompatibel ist. Das ist alles, was dazu gehört.

Jetzt können Befehlssätze unabhängig von ihrer Pipeline-Architektur kompatibel gemacht werden. Es ist richtig, dass das Pipelining Auswirkungen auf die Anweisungen haben kann, wenn Sie nur auf die Ausführungsgeschwindigkeit und den Kern-Siliziumbereich abzielen, aber es gibt immer Problemumgehungen, wenn Sie eine gewisse Kompatibilität mit einem vorhandenen Prozessor sicherstellen müssen. Es mag den Kern verkomplizieren, aber es gibt immer einen Weg. Sehen Sie sich an, wie sich die Architektur vom 8086 zu den neuesten Pentiums entwickelt hat. Aber auch alter Code kann noch ausgeführt werden.

In Bezug auf die Von Neumann / Harvard-Unterschiede kann auch festgestellt werden, dass es nur minimale Auswirkungen hat, wenn die Code- und Datenbusse tatsächlich zu denselben physischen Speicherblöcken mit denselben Adressen führen (was bei allen ARM-Implementierungen der Fall ist, die ich gesehen habe, außer vielleicht für Speicherzonen von Peripheriegeräten). Es kann Auswirkungen auf Sonderfälle geben, wie z. B. die Notwendigkeit, bestimmte Anweisungen aufzurufen, wenn der Code selbstmodifizierend ist, aber in normalen Fällen werden Sie dies nicht bemerken.

In Bezug auf die Speicherverwaltung ist das eine andere Geschichte. Dies wirkt sich auf die OS-Ebene aus. Die MMU ist wie ein zusätzliches Peripheriegerät, dessen Konfiguration sich auf das Speicherlayout auswirkt, aber den Befehlssatz nicht ändert. Ein Algorithmus wird auf dieselbe Weise codiert, unabhängig davon, ob es eine MMU gibt oder nicht.

Dieser Grenzfall, den Sie erwähnen, tritt auch auf, wenn Sie einfach Code zur Laufzeit generieren, was bei der Verwendung von JIT-Compilern üblich ist, sodass dies je nach Anwendungsfall ein sehr häufiges Szenario sein kann.
@voo das stimmt. Aber die Entwicklung eines JIT-Compilers ist nicht gerade ein sehr häufiges Szenario. Etwas in JIT auszuführen ist zwar viel häufiger, aber der Entwickler des interpretierten Codes muss sich dessen nicht bewusst sein, sondern nur der Entwickler des JIT-Compilers.
@Voo: Jeder Prozessor mit "Harvard" -Architektur, den ich mir angesehen habe, konnte wirklich Code im RAM ausführen, aber es gab mehr ROM als RAM, sodass Sie nicht zu viel davon tun können.
@Joshua Die Unterscheidung zwischen Harvard- und Van-Neumann-Architekturen ist weitgehend akademisch und heutzutage für praktische Architekturen nicht wirklich relevant. Echte CPUs sind eine Mischung aus beidem. Zum Beispiel wäre jede CPU, die über separate L1-Cachespeicher für Anweisungen und Daten verfügt (also fast alle), eine Harvard-Architektur. Aus diesem Grund benötigen Sie hier auch spezielle Anweisungen: Instruktions-Caches ungültig machen.

Die Idee, dass "Code migriert werden kann", bedeutet, dass die Anweisungen das gleiche Endergebnis erzeugen. Die Architektur oder Anzahl der Pipeline-Stufen haben darauf keinen Einfluss. zB der Code für die Anweisung:

add r0,r1,r2 

Wird auf beiden Maschinen gleich sein und das gleiche Ergebnis liefern: r0 ist am Ende die Summe von r1 und r2. Die Latenz kann länger sein. zB auf einem ARM7 dauert es 3 Zyklen und auf einem ARM 9 dauert es 5 Zyklen. Dies gilt jedoch für alle Anweisungen, sodass das Nettoergebnis dasselbe ist.

Die Echtzeit hängt von der Taktrate ab. Daher kann der ARM9 schneller sein, obwohl er 5 Takte benötigt, da zB der ARM7 mit 100 MHz und der ARM9 mit 3 GHz laufen kann.

Die MMU auf dem ARM9 ist nach einem Reset „transparent“, sodass Sie nicht bemerken, dass sie vorhanden ist. Zumindest solange Sie es nicht programmieren, wird der ARM7-Code nicht funktionieren, da es keinen Code geben sollte, um die MMU zu berühren.

Eine Harvard-Architektur bedeutet nicht, dass Code anders ausgeführt wird. Tatsächlich müssen Sie die Anweisung noch decodieren, bevor Sie wissen, welche Daten abgerufen/geschrieben werden sollen. Es ermöglicht nur, dass die nächste Anweisung ankommt und gleichzeitig mit dem Lesen/Schreiben der Daten decodiert wird.

Nachdem ich das alles gesagt habe, erinnere ich mich, dass es ein Problem mit der Verzweigungsanweisung gab, aber das könnte gewesen sein, als ich Assembler auf einen A53-Kern übertragen habe.

Ja, in den meisten Fällen sollte Code, der nur auf die Funktionen der älteren Architektur abzielt, problemlos funktionieren. Die Ausnahmen wären Code, der Timing-Annahmen trifft (handoptimiert, Verzögerungsschleifen usw.) oder Dinge wie sich selbst modifizierender Code, der auf Konsistenz angewiesen sein kann, die durch das Hinzufügen unterschiedlicher Code- und Daten-Caches gebrochen wird, so dass explizite Cache-Flush-Anweisungen erforderlich sind richtig funktionieren. Glücklicherweise sind dies keine neuen Probleme - portabler Code wie ein Betriebssystem-Kernel hat wahrscheinlich bereits Vorkehrungen dafür auf einigen Architekturen, und erfahrene Programmierer sind damit vertraut.
Betreff: Verzweigungsvorhersage + spekulative Ausführung: Diese Frage tauchte kürzlich bei Stack Overflow auf: Ein neuerer ARM spekulierte an a vorbei pop {r4, pc}, als die Verzweigungsvorhersage deaktiviert war, und spekulatives Laden von einer Adresse, die das System aufhängte , da die Daten nach der Funktion als decodiert wurden a Ladeanweisung. (Und die MMU wurde nicht so konfiguriert, dass spekulative Ladevorgänge aus diesem Adressbereich nicht zugelassen werden.)

ARM9 und andere verwenden die Harvard-Architektur (separater Bus für Daten und Anweisungen)

Das ist ungenau. Eine CPU mit Harvard-Architektur hat getrennte Speicher für Code und Daten; dies ist bei keiner Implementierung der ARM-Architektur der Fall. In einigen Implementierungen gibt es getrennte Busse für Befehle und Daten, aber sie sind immer mit demselben Speicher verbunden.

Wird es keinen Einfluss von Architekturen auf Codes geben?

Die Pipeline ist ein Implementierungsdetail. Es wirkt sich nicht auf das CPU-Modell des Programmierers aus – unter fast allen Umständen wird derselbe Code auf beiden Implementierungen auf dieselbe Weise ausgeführt. (Die Ausnahmen sind alle ungewöhnlich, wie selbstmodifizierender Code.)

Da es sich um zwei separate Busse handelt, wäre es jedoch ebenso ungenau zu sagen, dass es sich um Von Neumann handelt. Ich glaube, dass der Fall, in dem zwei Busse (möglicherweise mit jeweils einem separaten Cache) zum selben physischen Speicher gehen, als "modifiziertes Harvard" bezeichnet wird. Für mich immer noch Harvard...
Die Behauptung, dass beide Busse immer mit demselben Speicher verbunden sind, verfehlt das Entscheidende. Die einzige Möglichkeit, von zwei Bussen zu profitieren, besteht darin, mit ihnen auf verschiedene Speicher zuzugreifen - entweder auf verschiedene Caches in einem großen System oder auf Flash für Code und RAM für Daten in einem MCU-Typ. Wenn Sie beide Arten von Zugriffen auf denselben Speicher vornehmen müssen, erleiden Sie einen Effizienzeinbruch, da sie sich abwechseln müssen. Richtig ist, dass diese Prozessoren einen einheitlichen Adressraum haben - Sie können dieselben Anweisungen verwenden , um auf beide Arten von Speicher (und normalerweise auch E / A) zuzugreifen.
Daher ist es am genauesten zu sagen, dass sie ein Von-Neumann-Programmiermodell mit optionalen Optimierungen im Harvard-Stil haben, die der informierte Systemdesigner nutzen sollte.
@ChrisStratton: Also baut niemand jemals einen ARM, bei dem Code + Daten separate Adressräume haben, dh eine Funktion und eine globale könnten dieselbe numerische Adresse haben? Ich wäre nicht überrascht, wenn es Systeme gibt, bei denen es einen Fehler geben würde, wenn Sie LDRein Anweisungswort eingeben oder zu einigen Bytes springen, die Sie gerade gespeichert haben, aber nicht, dass Sie je nach Zugriffsart unterschiedliche Bytes erhalten würden. Diese Frage kam neulich für MIPS auf (meistens als Anfängerverwirrung ), und ich war mir nicht 100% sicher, dass es unmöglich war, ein MIPS mit separaten Adressräumen zu erstellen.
@PeterCordes Nicht, dass ich wüsste. Es wäre inkompatibel mit Thumb-Code -- Standardverfahren besteht darin, Konstanten am Ende einer Funktion zu speichern und PC-relative Speicherreferenzen zu verwenden, um sie zu laden. Mit getrennten Adressräumen würde das nicht funktionieren.
@duskwuff: ah richtig, also mit ziemlicher Sicherheit nicht für ARM. Ich denke, es ist für MIPS nicht völlig undenkbar, aber ich glaube nicht, dass irgendjemand sie tatsächlich so baut, weil die MMU und alle Caches normalerweise einen einheitlichen Adressraum annehmen würden. Natürlich sind einige Mikrocontroller wie AVR echte Harvard und haben möglicherweise tatsächlich separate Adressräume.
@PeterCordes AVR ist fast eine echte Harvard-Architektur. Die LPM/SPM-Anweisungen machen es zu einer (minimal) modifizierten Harvard-Architektur.
@PeterCordes - nein. Auf ARM oder MIPS befinden sich alle anderen einheitlichen Adressraummaschinen. Die einzige Möglichkeit, unterschiedliche Ergebnisse für den legalen Zugriff auf dieselbe Hardwareadresse zu erhalten, ist die Cache-Inkonsistenz - was ein echtes Problem sein kann, wenn Software nicht korrekt geschrieben wird.
Wirklich jede CPU, die getrennte Befehls- und Daten-Caches hat und dies für den Programmierer nicht per Definition vollständig unsichtbar macht, kann keine Van-Neumann-CPU sein. ARM ist es sicherlich nicht, da es spezifische Anweisungen erfordert, um den i-Cache ungültig zu machen. Ich bezweifle, dass eine moderne CPU, die Caches verwendet, als Van-Neumann-Architektur angesehen werden könnte - selbst x86, das sich am stärksten bemüht, den i-Cache vor Ihnen zu verbergen, muss unter bestimmten Umständen behandelt werden.

Alles, worauf sich "Architektur" bezieht, ist, wie die CPU mit dem Speicher verdrahtet ist - die meisten Befehle und ihre Codierungen und die Register sind zwischen den beiden Chips gleich - die einzige Möglichkeit, mit dem Unterschied zwischen einer Harvard in Schwierigkeiten zu geraten und andere Architekturen, oder die Anzahl der Pipe-Stufen könnte sein, wenn Sie Code in den Speicher schreiben und ihn dann ausführen ... Sie müssen nur vorsichtig sein, Caches ungültig zu machen

Einige Dinge wie Ausnahmen und dergleichen können anders sein

Code als Daten zu schreiben und ihn dann auszuführen, ist auf einer Harvard-Architektur unmöglich. Es ist auf einem modifizierten -Harvard (dh einer normalen CPU mit geteilten L1D / L1I-Caches) möglich . Auf ARM dauert es ein isyncoder etwas, weil die geteilten Caches nicht kohärent sind. (Im Gegensatz zu x86, wo der Befehls-Cache separat ist, aber leider mit den Daten-Caches kohärent sein muss, was Transistoren und Strom kostet, um den Icache und die Pipeline nach Speicheradressen zu durchsuchen, um zu erkennen, wann die Pipeline geleert werden muss.)