Ich las über Arduino und die AVR-Architektur und blieb an dem Punkt hängen, an dem die Einführung der Harvard-Architektur in den AVR das Abwürgen oder Sprudeln von Pipelines löst ermöglicht das Laden eines Programms ohne Bediener. Aber wie kann das oben genannte Problem gelöst werden?
12
Antworten:
Die Harvard-Architektur, die übrigens lange vor der Erfindung von AVRs verwendet wurde, verfügt in der Tat über separate Adressräume für den Programmspeicher und den Datenspeicher. Dies bringt für die Partei die Fähigkeit mit sich, die Schaltung so zu gestalten, dass ein separater Bus und eine Steuerschaltung verwendet werden können, um den Informationsfluss vom Programmspeicher und den Informationsfluss zum Datenspeicher zu handhaben. Durch die Verwendung der getrennten Busse ist es möglich, dass der Programmabruf und die Programmausführung ohne Unterbrechung einer gelegentlichen Datenübertragung in den Datenspeicher fortgesetzt werden. Beispielsweise kann in der einfachsten Version der Architektur die Programmabrufeinheit damit beschäftigt sein, den nächsten Befehl in der Programmsequenz parallel zu einer Datenübertragungsoperation abzurufen, die Teil des vorherigen Programmbefehls gewesen sein kann.
Auf dieser einfachsten Ebene ist die Harvard-Architektur dahingehend eingeschränkt, dass es im Allgemeinen nicht möglich ist, Programmcode in den Datenspeicher zu schreiben und von dort ausführen zu lassen.
Es gibt viele Variationen und Komplexitäten, die zu dieser einfachsten Form der von mir beschriebenen Architektur hinzugefügt werden können. Eine übliche Ergänzung besteht darin, dem Programminformationsbus eine Befehlszwischenspeicherung hinzuzufügen, die es der Befehlsausführungseinheit ermöglicht, schneller auf den nächsten Programmschritt zuzugreifen, ohne jedes Mal in einen langsameren Speicher gehen zu müssen, um den Programmschritt abzurufen, wenn dies erforderlich ist.
quelle
Einige Anmerkungen zusätzlich zu Michaels Antwort:
1) Die Harvard-Architektur erfordert nicht, dass zwei separate Bereiche für Daten und Code vorhanden sind, sondern dass sie (meistens) über zwei verschiedene Busse abgerufen werden .
2) Das Problem, das durch die Harvard-Architektur gelöst wird, ist ein Buskonflikt: Bei einem System, bei dem der Codespeicher die Anweisungen gerade noch schnell genug bereitstellen kann, um die CPU auf Hochtouren zu halten, verlangsamt die zusätzliche Belastung durch Datenabrufe / -speicher die CPU Nieder. Dieses Problem wird durch eine Hardvard-Architektur gelöst: Ein Speicher, der (etwas) zu langsam für die Geschwindigkeit der CPU ist.
Beachten Sie, dass Caching eine weitere Möglichkeit ist, dieses Problem zu lösen. Häufig werden Harvarding und Caching in interessanten Kombinationen eingesetzt.
Harvard benutzt zwei Busse. Es gibt keinen inhärenten Grund, sich an zwei zu halten. In ganz besonderen Fällen werden mehr als zwei verwendet, hauptsächlich in DSPs (Digital Signal Processors).
Memory Banking (im Sinne der Verteilung von Speicherzugriffen auf verschiedene Sätze von Chips) kann als eine Art Überlastung innerhalb des Speichersystems selbst angesehen werden, die nicht auf der Daten- / Code-Unterscheidung beruht, sondern auf bestimmten Bits der Adresse.
quelle
Mit einer reinen Harvard-Architektur kann ein Computer mit einer bestimmten Komplexität im Allgemeinen schneller ausgeführt werden als mit einer Von Neuman-Architektur, vorausgesetzt, dass keine Ressourcen zwischen dem Code und den Datenspeichern geteilt werden müssen. Wenn Pinbelegungsbeschränkungen oder andere Faktoren die Verwendung eines Busses zwingen, um auf beide Speicherbereiche zuzugreifen, können solche Vorteile weitgehend zunichte gemacht werden.
Eine "reine" Harvard-Architektur beschränkt sich darauf, Code auszuführen, der durch einen anderen Mechanismus als den Prozessor, der den Code ausführt, in den Speicher gestellt wird. Dies schränkt den Nutzen solcher Architekturen für Geräte ein, deren Zweck nicht vom Werk festgelegt wurde (oder für Geräte mit speziellen Programmiergeräten). Zwei Ansätze können verwendet werden, um dieses Problem zu beheben:
Einige Systeme verfügen über separate Code- und Speicherbereiche, bieten jedoch spezielle Hardware, die aufgefordert werden kann, kurz den Codebus zu übernehmen, eine Operation auszuführen und die Steuerung an die CPU zurückzugeben, sobald eine solche Operation abgeschlossen ist. Einige solcher Systeme erfordern ein ziemlich ausgefeiltes Protokoll, um solche Operationen auszuführen, andere haben spezielle Anweisungen, um eine solche Aufgabe auszuführen, und einige überwachen sogar bestimmte "Datenspeicher" -Adressen und lösen die Übernahme / Freigabe aus, wenn versucht wird, auf sie zuzugreifen . Ein Schlüsselaspekt solcher Systeme ist, dass es explizit definierte Speicherbereiche für "Code" und "Daten" gibt; Selbst wenn es der CPU möglich ist, "Code" -Raum zu lesen und zu schreiben, wird sie immer noch als semantisch anders als der Datenraum erkannt. '
Ein alternativer Ansatz, der in einigen High-End-Systemen verwendet wird, besteht darin, eine Steuerung mit zwei Speicherbussen zu haben, einen für Code und einen für Daten, die beide mit einer Speicherarbitrierungseinheit verbunden sind. Diese Einheit wiederum ist über jeweils einen separaten Speicherbus mit verschiedenen Speichersubsystemen verbunden. Ein Codezugriff auf ein Speichersubsystem kann gleichzeitig mit einem Datenzugriff auf ein anderes verarbeitet werden; Nur wenn Code und Daten versuchen, gleichzeitig auf dasselbe Subsystem zuzugreifen, muss einer der beiden warten.
Auf Systemen, die diesen Ansatz verwenden, können nicht leistungskritische Teile eines Programms die Grenzen zwischen Speichersubsystemen einfach ignorieren. Wenn sich der Code und die Daten zufällig im selben Speichersubsystem befinden, laufen die Dinge nicht so schnell wie in separaten Subsystemen, aber für viele Teile eines typischen Programms spielt das keine Rolle. In einem typischen System gibt es einen kleinen Teil des Codes, auf den es wirklich ankommt, und er wird nur auf einen kleinen Teil der vom System gespeicherten Daten angewendet. Wenn ein System mit 16 KB RAM in zwei 8-KB-Partitionen unterteilt ist, kann mithilfe von Linkeranweisungen sichergestellt werden, dass sich der leistungskritische Code am Anfang des gesamten Speicherbereichs befindet und die leistungskritischen Daten sich in der Nähe des befinden Ende. Wenn die Gesamtcodegröße auf z. B. 9 KB ansteigt, Code innerhalb der letzten 1 KB wird langsamer ausgeführt als an anderer Stelle platzierter Code, dieser Code ist jedoch nicht leistungskritisch. Wenn der Code beispielsweise nur 6 KB groß wäre, die Daten jedoch auf 9 KB anwachsen würden, wäre der Zugriff auf die niedrigsten 1 KB langsam. Wenn sich die leistungskritischen Daten jedoch an einer anderen Stelle befinden würden, wäre dies kein Problem.
Es ist zu beachten, dass, während die Leistung optimal wäre, wenn der Code unter 8 K und die Daten unter 8 K wären, der oben erwähnte Entwurf des Speichersystems keine strikte Aufteilung zwischen Code und Datenraum auferlegen würde. Wenn ein Programm nur 1 KB Daten benötigt, kann der Code auf 15 KB anwachsen. Wenn nur 2 KB Code benötigt werden, können die Daten auf 14 KB anwachsen. Viel vielseitiger als ein 8K-Bereich nur für Code und ein 8K-Bereich nur für Daten.
quelle
Ein Aspekt, der nicht diskutiert wurde, ist, dass für kleine Mikrocontroller, die typischerweise nur einen 16-Bit-Adressbus haben, eine Harvard-Architektur den Adressraum effektiv verdoppelt (oder verdreifacht). Sie können 64 KByte Code, 64 KByte RAM und 64 KByte speicherzugeordnete E / A haben (wenn das System speicherzugeordnete E / A anstelle von Portnummern verwendet, trennt letzteres die E / A-Adressierung bereits vom Code & RAM-Speicher).
Andernfalls müssen Sie den Code, den Arbeitsspeicher und die optionale E / A-Adresse innerhalb desselben 64-KB-Adressraums komprimieren.
quelle