erstellt 10.06.2010
Stack
HWSTACK ( Hardware Stack)
Der Hardware-Stack ist der Bereich im Speicher, der dafür reserviert ist um Rücksprungadressen und, bei einem Interrupt, eine Sicherung der Register abzulegen.
Springst man mit GOSUB irgendwo hin, dann wird zuvor die Adresse gespeichert, zu der bei einem RETURN wieder zurück gekehrt werden soll. Wenn man innerhalb dieser Unterroutine in die man gesprungen ist, noch einmal GOSUB verwendest, dann wird diese zweite Rücksprungadresse ebenfalls auf den Hardware-Stack (=Stapel) abgelegt.

Bei einem RETURN wird dann von der zweiten Unterroutine in die erste Unterroutine zurück gesprungen. Dann wird die Adresse vom Stack gelöscht. Wird die erste Unterroutine beendet (RETURN), dann springt das Programm zur ersten Rücksprungadresse zurück. Auch diese Adresse wird wieder vom Hardware-Stack gelöscht.

Wie viel Speicher für diese Springerei benötigt wird, hängt also nicht von der Anzahl an GOSUBs oder CALLs ab, sondern davon, wie viele GOSUB oder CALLs ineinander verschachtelt sind. Für ein GOSUB in eine Unterroutine und noch ein GOSUB innerhalb dieser ersten Unterroutine und dann noch ein GOSUB innerhalb der zweiten Unterroutine brauchst man 3 x 2 Byte. Wenn man also  Programme nicht extrem verschachtelst, dann braucht man selten mehr als 10 Byte Hardware-Stack für diese Springerei.

Außer dieser Rücksprungadressen, legt Bascom auch die Werte der Register in diesen Stack, sobald ein Interrupt auftritt und der zugehörige Interrupt-Handler (ISR) angesprungen wird.

Bevor also die Unterprozedur aufgerufen wird, die immer dann automatisch ausgeführt wird, wenn ein Interrupt auftritt, werden die Register in den HWStack gesichert. Dafür werden 32 Byte benötigt. Wenn man also Interrupts aktiviert,  braucht man mindestens 32 Byte HWStack. Da man in einem Interrupt-Handler so wenig wie möglich macht und die Hauptarbeit normalerweise in der MainLoop verrichten lässt, ist es unüblich, innerhalb eines Interrupt-Handlers Unterprozeduren anzuspringen. Also wird selten mehr als 32 Byte HWStack benötigt.

Wenn man es aber doch machst, was ja kein Problem ist, dann musst man zu den benötigten 32 Byte noch die Byte für die Springerei dazuzählen.

Ich würde mal sagen, dass man beim HWSTACK großzügig ist, wenn man  am Anfang auf 40 Byte festlegst. Und falls man weiß, dass man nicht so viel braucht, weil man z.B. keinen Interrupt aktiviert hast, kann man später den HWSTACK entsprechend verkleinern.

$hwstack = 40

SWSTACK ( Software Stack)

So, und jetzt zum Software-Stack. Gleich wie beim Hardware-Stack gilt, dass nicht die Anzahl an Unterprozeduren (SUB) dafür ausschlaggebend ist wie groß der Software-Stack sein muss. Ausschlaggebend ist, wie verschachtelt die Aufrufe untereinander sind.

Wenn man zehn Unterprozeduren hat, aber immer nur eine dieser Unterprozeduren gleichzeitig aktiv wird, brauchst man nur so viel Software-Stack-Speicher wie ihn diese eine Unterprozedur benötigt. Wenn man innerhalb einer Unterprozedur eine andere Unterprozedur aufruft, dann brauchst man im Software-Stack für beide Unterprozeduren Platz. Gleiches gilt auch für Funktionen.

Wie viel Platz ist das überhaupt?

Mann  braucht für jede Variable, die an die Unterprozedur als Parameter übergeben wird, 2 Byte im SWStack. Hast man also eine Unterprozedur mit 2 Parametern, dann braucht man  dafür 4 Byte SWStack. Rufst man innerhalb dieser Unterprozedur eine andere Unterprozedur auf, die z.B. 3 Parameter erwartet, dann braucht man  zu den bereits verbrauchten 4 Byte noch (3 x 2) 6 Byte dazu. Das wären dann 10 Byte.

Jede innerhalb einer Unterprozedur mit dem Befehl LOCAL erstellte Variable braucht ebenfalls je 2 Byte im SWStack.

Nehmen wir also an, dass man im Normalfall bis zu 4 Parameter an eine Unterprozedur weitergibst und innerhalb der Prozeduren maximal 3 Variablen mit LOCAL definierst. Weiters nehmen wir mal an, dass man  innerhalb einer solchen Unterprozedur maximal noch eine weitere Unterprozedur mit wiederum 4 Parametern aufruft, die auch wieder bis zu 3 lokale Variablen hat, dann braut man  für die Parameter der ersten Prozedur (4 x 2) 8 Byte. Und für die lokalen Variablen der ersten Prozedur (3 x 2) 6 Byte. Das sind für die erste Prozedur 14 Byte SWStack. Und die gleiche Menge kommt noch für den verschachtelten Aufruf der zweiten Unterprozedur dazu. Das wären dann 28 Byte die für den SWStack reserviert werden müsste.
Wenn man noch ein paar Reserverbytes dazu tut, dann ist man  in solch einem Fall mit 32 Byte SWStack gar nicht mal so schlecht dran.

Wenn man also schon am Anfang deines Programmes den SWSTACK auf 32 stellst, dann sind solche (eher schon komplexe) Vorgänge recht gut abgedeckt. Wenn man  später erkennt, dass man nicht so viel SWSTACK-Speicher benötigt,  kann man ihn ja immer noch verkleinern.

$swstack = 32

Der ATmega8 hat insgesamt 1024 Byte SRAM zur Verfügung. Von diesem SRAM werden die Bytes für den HWSTACK, den SWSTACK und den FRAME abgezogen.

$hwstack = 40
$swstack = 32
$framesize = 60

Dann bleiben für die Variablen des Hauptprogrammes noch 892 Byte übrig. Man kann also noch gut nach oben korrigieren, falls mehr HWSTACK, SWSTACK oder FRAME benötigt wird, oder wenn man auf "Nummer Sicher" gehen möchte.

$hwstack = 100
$swstack = 100
$framesize = 100

Auch mit diesen Werten sollte alles so lange gut laufen, so lange das Programm nicht mehr als 700 Byte für globale Variablen braucht.
Aktualisiert 23.03.2014
Copyright by Ms  2009