-
Die Erfindung betrifft ein Verfahren
und eine Schaltungsanordnung zur Zuordnung von verfügbarem Speicherbereich
innerhalb eines Schreib-Lese-Speichers, der durch eine unterste
und eine oberste Grenze vorbestimmt ist und bei dem der Wert der
obersten Grenze in einen zweiten vorbestimmten Speicherort abgelegt
wird.
-
Zur Software-Entwicklung von Computersystemen,
die in ein externes System, z. B. eine Maschine, ein Gerät oder eine
Anlage eingebettet sind und diese Regeln und/oder steuern, werden
Hochsprachen der Softwareentwicklung wie z. B. C und/oder C++ eingesetzt.
-
Funktionen die während der Ausführung eines
mit solchen Hochsprachen der Softwareentwicklung entwickelten Programms
aufgerufen werden, legen eine zur Abarbeitung erforderliche Variable,
eine sogenannte lokale Variable, in einen bestimmten Abschnitt eines
beschreibbaren und lesbaren Speichers ab. Im folgenden ist dieser
Abschnitt als "Stack" bezeichnet.
-
Lokale variablen werden in diesem
Stack für
die gesamte Ausführungszeit
der Funktion gespeichert und belegen damit einen Teil des Stack.
Wird während
der Ausführung
einer Funktion, eine weitere Funktion, z. B. eine Unterfunktion
einer aktuellen Funktion aufgerufen, so wird auch diese Unterfunktion
lokale Variablen in den Stack ablegen.
-
Zur Verwaltung des Stack und dem
von den lokalen Variablen benötigten
Bereich wird ein sogenanntes Stackframe-Konzept angewendet. Dabei
wird beim Funktionsaufruf zu einer Compilezeit der benötigte Stackanteil
für die
Speicherung der lokalen Variablen der Funktion ermittelt und der
entsprechende Stackanteil für
die lokalen Variablen dieser Funktion am anfang des noch freien
Stacks reserviert.
-
Dabei werden wiederum zwei Varianten
unterschieden.
-
Variante 1: Ein Compiler reserviert
für eine
Funktion, durch zusätzlich
eingefügte
Instruktionen, den über
die Dauer der Ausführung
und entsprechend den aktuellen Randbedingungen jeweils minimal notwendigen
Bereich des Stacks, zu jeder Zeit der Funktionsausführung.
-
Variante 2: Diese reserviert unmittelbar
nach dem Funktionsaufruf, immer den für jeden Fall maximal benötigten Stack.
Unabhängig
davon, ob bei den aktuellen Randbedingungen auch weniger Stack ausreichen würde.
-
Variante 3: Der Compiler reserviert
in der aufrufenden Funktion unmittelbar vor dem Funktionsaufruf, den
bis dahin tatsächlich
minimal notwendigen Stack für
die aufrufende Funktion.
-
Außer den durch die Software
aufgerufenen Funktionen und von diesen wiederum aufgerufenen Funktionen,
benötigen
auch spezielle hardwaregesteuerte Funktionen einen Bereich aus dem
Stack zur Speicherung der lokalen Variablen. Diese sogenannten "Interrupts" unterbrechen den
eigentlichen Programmablauf der Software zur Compilezeit unvorhersehbar.
Bei der Ausführung
eines Interrupts dürfen
dennoch die lokalen Variablen der anderen Funktionen und von diesen
wiederum aufgerufenen Funktionen im Stack nicht überschrieben werden.
-
Es sind zwei Möglichkeiten bekannt, dies zu
realisieren.
-
- 1. Die Varianten 1 und 2 für die Reservierung des Stacks
finden Verwendung, oder
- 2. die Interruptfunktion benutzt zur Ablage der lokalen Variablen
einen anderen Stack.
-
Alle Möglichkeiten beinhalten spezifische
Nachteile:
-
- 3. Bei Variante 2 erfolgt stets maximaler Speicherverbrauch
im Stack.
- 4. Bei Variante 1 bedarf es hohen zusätzlichen Instruktionsaufwandes
zur Stack Verwaltung in Software, oder eine höheren Verbrauch für Codierungsraum
für Hardwareinstruktionen
und für
komplexe Befehle sowie eine höhere
Compilerinteligenz.
- 5. Wird zur Ablage lokaler Variablen ein anderer Stack benutzt,
ergibt sich ein höherer
Hardware-Verwaltungsaufwand zur Einrichtung mehrerer Stacks.
-
In den betrachteten Computersystemen
ist beschreibbarer und lesbarer Speicher zum Beispiel RAM, wegen
des hohen Platzbedarfes und Stromverbrauchs gegenüber anderen
elektronischen Speichern wie EEPROM oder ROM nicht in beliebiger
Größe einsetzbar.
Als Stack eignet sich jedoch kein anderer Speichertypus.
-
Es ist die Aufgabe der Erfindung,
ein Verfahren und eine Schaltungsanordnung bereit zu stellen, wobei mit
einfachen Mitteln der verfügbare
Speicherbereich optimal genutzt wird und die genannten Nachteile
beseitigt werden.
-
Diese Aufgabe wird durch ein Verfahren
und eine Schaltungsanordnung zur Zuordnung von verfügbarem Speicherbereich
innerhalb eines Schreib-Lese-Speichers, der durch eine unterste
Grenze und eine oberste Grenze vorbestimmt ist, und bei dem der
Wert der obersten Grenze in einem zweiten vorbestimmten Speicherort
abgelegt wird, wobei eine Obergrenze eines durch laufende, nicht
vollständig
abgearbeitete Funktionen belegten Teilspeicherbereiches bei jedem
Schreibzugriff neu bestimmt wird und in einem dritten vorbestimmten
Speicherort, einem Stack-Pointer abgelegt wird und wobei jeder Schreibzugriff
an der Obergrenze beginnt, gelöst.
-
Dabei wird in einem beschreibbaren
und lesbaren Speicher durch eine oberste Grenze und eine unterste
Grenze ein zur Speicherung lokaler Variablen verfügbarer Bereich
definiert. Dieser wird im folgenden "Stack" bezeichnet. Die Speicherung der lokalen
Variablen erfolgt beginnend an der untersten Grenze oder beginnend
an der obersten Grenze und wird in Richtung der jeweils anderen
Grenze fortgesetzt.
-
Im folgenden wird nur die Richtung
von der untersten Grenze zur obersten Grenze betrachtet. Diese Betrachtung
reicht zur Beschreibung des Verfahrens aus, da die andere Richtung
durch eine Spiegelung ebenfalls darzustellen ist.
-
Es wird bei jedem Schreibvorgang
die Obergrenze des bereits belegten Stack ermittelt und in einem dafür vorgesehenen
Stack-Pointer abgelegt. Der Wert in diesem Stack-Pointer wirkt wie
ein "Zeiger", der stets den aktuellen "Füllstand" des Stacks anzeigt. Bei einem leeren
Stack entspricht der Wert dieses Zeigers der untersten Grenze des
Stacks.
-
Erfolgt ein Funktionsaufruf, so wird
der Wert des Zeigers in einen vierten Speicherort, einem Stack-Frame-Pointer,
kopiert. Dabei ist es die Aufgabe dieses Stack-Frame-Pointers, stets
den Beginn eines für
die aktuelle Funktion reservierten Bereiches darzustellen.
-
Im Folgenden sei der für eine Funktion
reservierte Bereich als "Stackframe" und der Beginn des
Stackframe als "Stackframe-Pointer" bezeichnet.
-
Bevor der alte Wert des Stackframe-Pointers
bei einem Funktionsaufruf überschrieben
wird, wird er in einen dafür
vorgesehenen fünften
Speicherbereich abgelegt bzw. gesichert. Die beim Funktionsaufruf
durchzuführenden
Kopier und Sicherungsvorgänge
werden durch ein Interrupt nicht unterbrochen.
-
So lange eine aufrufende Funktion
nicht vollständig
abgearbeitet ist, existiert für
diese Funktion auch ein Stackframe und der jeweilige Stackframe-Pointer
ist im dafür
vorgesehenen fünften
Speicherbereich gesichert. Ein Funktionsaufruf kann dabei zu jeder
Zeit erfolgen. Ebenso kann ein Funktionsaufruf unabhängig von dem
laufenden Softwareprogramm durch einen Hardware-Interrupt erfolgen.
Dabei zeigt sich der Vorteil des erfindungsgemäßen Verfahrens, bei dem stets
bei jedem Funktionsaufruf die Obergrenze des aktuell belegten Speicherbereiches
als Beginn eines neuen Stackframes dient. Somit wird der Schreib-Lese-Speicher
lückenlos
aufgefüllt.
-
Nach der vollständigen Abarbeitung einer aufgerufenen
Funktion befinden sich in dem für
sie reservierten Stackframe keine lokalen Variablen mehr, deren
Wert für
eine weitere Berechnung benötigt
wird und der Bereich bzw. Stackframe wird wieder freigegeben. Dazu
werden der alte gesicherte Wert des Stackframe-Pointers der aufrufenden
Funktion bei jedem Rücksprung
aus seinem fünften
Speicherbereich heraus wieder in den Stackframe-Pointer zurückgeschrieben.
Ausserdem erfolgt auch das Überschreiben
des "Füllstandzeigers" im dritten Speicherort,
den Stack-Pointer mit dem vorherigen Wert des Stack-Frame-Pointers
der aufgerufenen Funktion. Diese beiden Schreibvorgänge werden
durch Interrupts nicht unterbrochen.
-
Vorteilhaft an dem Verfahren und
der Schaltungsanordnung ist, daß sich
als Speicherorte für
die einzelnen Werte, die die jeweiligen Grenzen markieren, z. B.
RAM ebenso wie Hardwareregister eignen. Die Speicherorte müssen zur
Erfüllung
ihrer Aufgabe vorbestimmt sein und dürfen nicht für andere
Zwecke sondern nur zur Ablage dieser Werte verwendet werden.
-
Erfindungsgemäß ist zur Realisierung des
Verfahrens eine Schaltungsanordnung vorgesehen, die zur Zuordnung
von verfügbarem
Schreib-Lese-Speicher aus
-
- 1. einer zweiten Speichereinrichtung, die die
Adresse der obersten Grenze des gesamten verfügbaren Adreßbereiches, das Stack-Ende
enthällt,
und
- 2. einer dritten Speichereinrichtung zur Speicherung einer Obergrenze
eines durch laufende, nicht vollständig abgearbeitete Funktionen
belegten Adreßbereiches,
den Stack-Pointer,
und
- 3. einer vierten Speichereinrichtung zur Speicherung des Stack-Frame-Pointers,
und
- 4. einer ersten Vergleichseinrichtung zum Vergleich des Wertes
des Stack-Endes mit dem Wert der Adresse für einen aktuellen Schreibvorgang
im zugeordneten Schreib-Lese-Speicher,
und
- 5. einer zweiten Vergleichseinrichtung zum Vergleich des Wertes
des Stack-Pointersd mit dem Wert der Adresse für einen aktuellen Schreibvorgang
im zugeordneten Schreib-Lese-Speicher,
und
- 6. einer Und-Verknüpfung
zur Verknüpfung
der Ausgänge
aus der ersten Vergleichseinrichtung und der zweiten Vergleichseinrichtung,
besteht.
-
Dabei wird durch die erste Vergleichseinrichtung
und durch die zweite Vergleichseinrichtung ein Beobachtungsfenster
aufgespannt, das durch den Wert in der zweiten Speichereinrichtung,
dem Stack-Ende, nach oben und durch den Wert in der dritten Speichereinrichtung,
dem Stack-Pointer, nach unten begrenzt wird. Dabei ist der Ausgang
der Und-Verknüpfung
mit einem Eingang zu einer Kontrolleinrichtung, die die jeweiligen Verfahrensschritte
des Hardwareverfahrens veranlasst verbunden. Die dritte Speichereinrichtung,
der Stack-Pointer, wird dabei zur Speicherung des Werts der Adresse
für den
aktuellen Schreibvorgang im zugeordneten Schreib-Lese-Speicher angeregt.
-
Eine vorteilhafte Ausführungsform
der Schaltungsanordnung ermöglicht
bei einem Funktionsaufruf die Übertragung
des Wertes aus der dritten Speichereinrichtung, den Stack-Pointer,
in eine vierte Speichereinrichtung, dem Stack-Frame-Pointer über eine
Verbindung zwischen den beiden Speichereinrichtungen.
-
Dabei wird das aktuelle "Füllstandsmaximum" des Stacks als Untergrenze
eines neuen Stackframes definiert.
-
Um bei einem Rückschritt aus der laufenden
Funktion den freigewordenen Stack für neue Speichervorgänge zu öffnen, wird
erfindungsgemäß der Wert
aus der vierten Speichereinrichtung, dem Stack-Frame-Pointer in
eine fünfte
Speichereinrichtung übertragen.
-
Im Folgenden wird die Erfindung anhand
von Figuren und eines Ausführungsbeispiels
näher beschrieben.
-
Es zeigen:
-
1 eine
schematische Darstellung des,
-
2 eine
schematische Darstellung der Schaltungsanordnung.
-
Es bezieht sich das Ausführungsbeispiel
auf die Verwendung eines definierten Speicherbereiches im Schreib-Lese-Speicher
als Stack zur Ablage von lokalen Variablen aktuell ausgeführter Funktionen.
Dabei ist der Stack 11 begrenzt durch eine Obergrenze 3 und
eine Untergrenze 2. Dabei wird die Untergrenze in einem ersten
vorbestimmten Speicherort 4 abgelegt und die oberste Grenze 3 in
einem zweiten vorbestimmten Speicherort 5 abgelegt.
-
Erfolgt ein Schreibzugriff auf den
Stack 11, so erfolgt dieser immer beginnend von unten nach
oben oder beginnend von oben nach unten. In der weiteren Betrachtung
wird nur der Zugriff von unten nach oben erörtert, da der Zugriff von oben
nach unten durch eine Spiegelung der Darstellung ebenfalls abgedeckt
ist und keiner weiteren besonderen Beschreibung bedarf.
-
Bei jedem Schreibzugriff wird die
Adresse der oberen Grenze 6 des aktuellen Schreibzugriffs
in einen dritten vorbestimmten Speicherort 7, dem Stack-Pointer,
abgelegt. Dieser enthält
somit stets ein aktuelles "Füllstandsmaximum" des Stack.
-
Erfolgt ein Funktionsaufruf, wobei
es unerheblich ist, ob dieser Funktionsaufruf durch die Software oder
unerwartet durch die Hardware durch einen Hardware-Interrupt erfolgt,
so wird der zu diesem Zeitpunkt im dritten Speicherort 7,
dem Stack-Pointer, sich befindende Wert in einen vierten Spei cherort 9,
den Stack-Frame-Pointer übertragen
und markiert dort den Beginn des "Stackframes" für
die nun aktuelle Funktion. Der Wert der bis dahin in dem vierten
Speicherort 9, dem Stack-Frame-Pointer, abgelegt war, wird
zum Zeitpunkt des Funktionsaufrufes in einen fünften Speicherbereich 10 übertragen,
und dort gesichert.
-
Während
der Abarbeitung der Funktion erfolgt weiter die Aufzeichnung der
höchsten
Speicheradresse bei jedem Schreibzugriff in dem dritten Speicherort 7,
dem Stack-Pointer. Ist die Funktion gänzlich abgearbeitet, erfolgt
ein Rücksprung
zu der vorherigen Funktion, wobei der im fünften Speicherbereich 10 abgelegte Wert
nun auf den vierten Speicherort 9, dem Stack-Frame-Pointer, übertragen
wird und zuvor der Wert aus dem vierten Speicherort 9,
dem Stack-Frame-Pointer, auf den dritten Speicherort 7,
dem Stack-Pointer übertragen
wird.
-
Die Adresse für einen Schreibvorgang auf
den Speicher 1 wird auf einen Adressbus 21 angelegt.
Daten werden über
die Verbindungsleitungen 31 und 32 zum Stack 11 geführt. Dort
wird ein Schreibvorgang an der über
die Adressleitung 21 und 22 geführten Adresse
eingeleitet. Diese Adresse wird zu zwei Vergleichseinrichtungen 12 und 13 geführt, die
den Wert auf der Adreßleitung 24 mit
den Werten in den Speicherorten 5, und 7, dem
Stack-Ende und dem Stack-Pointer, vergleichen. Falls die Auswertung
der Vergleichseinrichtungen 12 und 13, dessen
Ausgänge über eine
Und-Verknüpfung 14 verbunden
sind ergibt, daß der
Adresswert auf der Adreßleitung 24 zwischen
den Werten in den Speicherorten 5 und 7, dem Stack-ende
und dem Stack-Pointer, liegt, wird der Schreibvorgang des Adresswerts über die
Verbindungsleitung 29 in der Kontrolleinrichtung veranlasst.
-
Erfolgt ein Funktionsaufruf, wird
der Wert aus dem Speicherort 9, dem Stack-Frame-Pointer, über die Verbindungsleitungen 22 und 23 in
einem Controll-Stack 10 abgelegt. Daran anschließend wird
der Wert von Speicherort 7, dem Stack- Pointer, über die Verbindungsleitung 30 an
den Speicherort 9, dem Stack-Frame-Pointer, übergeben.
-
Folgt ein Rücksprung aus einer Funktion,
wird der momentane Wert aus dem Speicherort 9, dem Stack-Frame-Pointer, über die
Leitung 30 zurück
nach Speicherort 7, dem Stack-Poitner, geschrieben und
der zuletzt im Controll-Stack 10 gespeicherte Wert vom
Controll-Stack 10 wieder an den Speicherort 9,
dem Stack-Frame-Pointer, über
die Leitung 23 und 22 zurückgeschrieben. Der Controll-Stack
wird dazu über
die Hardwarekontrolleinrichtung 33 verwaltet.
-