Verstehe das Problem nicht.
Wenn du eine ganz normale lokale Variable deklarierst, wird sie auf dem
Stack abgelegt.
Und der Pic18 Stack ist doch die Katastrophe überhaupt. Der kostenlose
Compiler generiert massenhaft Assemblerbefehle mit dem INDF2. Bei der
Vollversion kann man Indexed Addressing einschalten.
Kein Masochist tut sich so was in Assembler an.
Na ja.....
die Trennung von Programm- und Daten-Stack ist genial. Besser als alle
Anti-Trojaner-Strategien auf den PCs.
Nur dieser aus Pic16 und modernem Hochsprachen-Stack
zusammengeschusterte Datenstack.
Da gib's eine AN818 fom Microchip.Dort wird es genau beschrieben wie
man Den Stack manipulieren kann.Aber er ist nur dafür da um den
Programmablauf zu ändern.Also irgendwohin zu springen kann man damit
aber keine Variablen dort ablegen.
Kein Name schrieb:> Verstehe das Problem nicht.
Und ich nicht den Sinn.
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Stack
Der Stack wird benutzt, um die aktuelle Position beim Sprung in eine
Unterfunktion / ein Unterprogramm zu speichern, damit der PIC beim
Return der Funktion/Unterprogramm weiß, wohin er zurückspringen muss.
Dahinein Variablen zu speichern ist eine nicht sehr sinnvolle Idee,
zumal im RAM deutlich deutlich mehr Platz ist und er halt dafür da ist.
Kein Name schrieb:> Und der Pic18 Stack ist doch die Katastrophe überhaupt. Der kostenlose> Compiler generiert massenhaft Assemblerbefehle mit dem INDF2.
Das INDF-Register ist für die indirekte Adressierung und hat nichts mit
dem Stack zutun. Man kann das FSR und INDF Register wie einen Pointer in
C sehen. FSR ist die Adresse im RAM und INDF ist dann der Inhalt von der
Speicherzelle.
Kein Name schrieb:> Kein Masochist tut sich so was in Assembler an.
Das geht beim PIC18 genauso wie beim PIC16 und diesen hab ich in der
Ausbildung mit ASM Programmiert und das war das kleinste Problem von
allem. Man definiert vorher, welche Namen welche Adresse haben (muss man
aber nicht machen) und sagt dann, man möchte etwas nach "variablea"
schreiben.
z.B.:
1
L1 equ 0x0C
2
; ...
3
; ...
4
decfsz L1, f
Nix mit FSR oder INDF.
Entweder ihr verwendet hier den Begriff "Stack" für etwas, was nicht der
Stack ist, oder du/ihr solltet euch bewusst machen, für was man den
braucht. Ich mach das Benzin ja auch in den Tank und nicht in die
Baterie. Meineswissens kommt man an den Stack garnicht dran. Man kann
höchstens den Program-Counter manipulieren, aber das is ja nichts
anderes als ein GOTO.
Kein Name schrieb:> Und der Pic18 Stack ist doch die Katastrophe überhaupt. Der kostenlose> Compiler generiert massenhaft Assemblerbefehle mit dem INDF2. Bei der> Vollversion kann man Indexed Addressing einschalten.
Völliger Blödsinn. Das einzigste was der freie C18 nicht macht ist die
prozedurale Abstraktion als Code-Optimierung, und das auch nur nach
einiger Zeit. Alles andere ist wie bei der Vollversion. SDCC wäre dann
so oder so Open-Source, da gibt es also garkeine komerzielle Version die
irgendwie eingeschränkt sein könnte. Was andere Compiler machen weiss
ich nicht.
Michael Skropski schrieb:> Das INDF-Register ist für die indirekte Adressierung und hat nichts mit> dem Stack zutun. Man kann das FSR und INDF Register wie einen Pointer in> C sehen. FSR ist die Adresse im RAM und INDF ist dann der Inhalt von der> Speicherzelle.>> [...]>> Das geht beim PIC18 genauso wie beim PIC16 und diesen hab ich in der> Ausbildung mit ASM Programmiert und das war das kleinste Problem von> allem.
Die Pic18 haben da ganz enorme Unterschiede und vor allem Vorteile
gegenüber den Pic16, was den Software-Stack im RAM angeht, als auch den
Zugriff auf den Programspeicher im Flash.
Für den Zugriff auf das RAM stehen drei komplette Sätze an Registern zur
Verfügung beim Pic18. Mittels der FSRxH und FSRxL Register legt man die
(Ursprungs-)Adresse fest auf die die indirekten Zugriffe erfolgen
sollen. (das x steht dabei für 0, 1 oder 2 - eben drei komplette Sätze).
Dann hat man die verschiedenen Register um den Zugriff zu machen. Einmal
das normale INDFx, wie man es auch vom Pic16 kennt. Dann aber auch noch
POSTINCx, POSTDECx, PREINCx und PLUSWx. Wenn man also einen SW Stack
hat, setzt man lediglich beim Programstart die FSRx passend, und greift
dann über PREINCx und POSTDECx darauf zu. PREINC erhöht die Adresse
zuerst um eins und zeigt dann auf den neuen Wert. POSTDEC zeigt zuerst
auf den Wert und dekrementiert dann die Adresse. Mittels PLUSW wird der
Inhalt des WREG auf die Adresse addiert und dann zugegriffen, etc.
Da diese Sätze drei mal vorhanden sind, hat man beim Pic18 eine recht
gute C Unterstützung: Stack und Frame-Pointer getrennt, und noch einen
Indirekt-Satz feei fü z.B. Zugriffe auf Arrays.
Dann gibt es auch noch die TBLPTR Register, mit denen man ganz bequem
direkt auf den Programmspeicher zugreifen kann, um z.B. Tabellen im
Flash zu benutzen. Zu diesen Registern gibt es dann passende ASM
Befehele für den Zugriff, ebenfalls mit Auto-Increment/Decrement/etc.
Wenn der OP also in Assembler programmiert, und dabei einen
Software-Stack für Daten haben will, dann sollte er zuerst ein FSRxH/L
auf den von ihm gewünschten Stack-Bereich setzen. Anschliessend schiebt
er die Daten in das PREINCx Register, was einem PUSH entsprechen würde,
und liesst sie dann aus dem POSTDECx Register wieder aus, was dann das
POP wäre. Solange dieser Bereich dann für nichts anders genutzt wird,
und der Registersatz ebenfalls nirgendwo anderweitig verwendet wird,
reichen alleine diese zwei Register für den Zugriff auf den Stack aus.
Ansonsten müsste ggf. das FSRxH/L Paar gesichert und später
wiederhergestellt werden, sollte es wirklich mal für irgendwas nötig
sein alle drei Registersätze verwenden zu müssen (z.b. um zwei Arrays zu
verrechnen und das Ergebnis in ein drittes zu sichern, ohne viel
Adress-Umladerei).
Grüße,
Chris
Edit: Man kann PREINC und POSTDEC natürlich auch vertauscht verwenden,
je nachdem in welche Richtung der Stack wachsen soll.
Hallo,
Danke für alle Infos. Werde das mit dem Stack vergessen und dafür ein
Array anlegen.
Im Array speichere ich die Position(Offset) einer Tabelle. Je nach
Inhalt der Tabelle wird ein neuer Offset zurückgegeben und dann im Array
gespeichert. Dazwischen sind Ablauf-Anweisungen vorhanden und eine
End-Anweisung. Tauch diese End-Anweisung auf, wird der vorheriger Offset
zurück gelesen und dort weiter gearbeitet.
Gruß Siegfried
Michael Skropski schrieb:> Das INDF-Register ist für die indirekte Adressierung und hat nichts mit> dem Stack zutun.
Lies bitte im Compiler-Handbuch, bevor du dich so weit aus dem Fenster
lehnst. Auf Datenblatt-Basis hast du recht, mehr aber auch nicht.
Michael Skropski schrieb:> Entweder ihr verwendet hier den Begriff "Stack" für etwas, was nicht der> Stack ist, oder du/ihr solltet euch bewusst machen, für was man den> braucht. Ich mach das Benzin ja auch in den Tank und nicht in die> Baterie. Meineswissens kommt man an den Stack garnicht dran. Man kann> höchstens den Program-Counter manipulieren, aber das is ja nichts> anderes als ein GOTO.
Mach dich mit dem C18 und seiner ABI bekannt, dann wirst du sehen, dass
der Compiler einen Daten-Stack im RAM erzeugt, der mittels FSRx
verwaltet wird. Der Call/Return-Stack eines PIC16/18 kann freilich keine
beliebigen Daten enthalten, das ist ja wohl klar.
Gruß,
Edson
Immer mit der Ruhe.
Die Hardware-Entwickler betrachteten nur den Call-Stack als Stack. In
Hochsprachen wird die Kombination aus Daten- und Return-Stack als Stack
bezeichnet.
Sind einfach nur 2 unterschiedliche Definitionen. Gab Verwirrung, ist
aber inzwischen geklärt.
Kein Name schrieb:> Sind einfach nur 2 unterschiedliche Definitionen. Gab Verwirrung, ist> aber inzwischen geklärt.
Dann ist es ja gut. Da der TE den C18 Compiler benutzt, gibt es aber nur
eine gültige Definition von "Stack", nämlich die der ANSI-C89
Spezifikation (leider nicht frei verfügbar wie der C99 Standard).
Der C18-spezifische Teil ist "implementation defined behaviour",
nachzulesen im Compilerhandbuch.
Gruß,
Edson
Daß für CALL/RET und PUSH/POP unterschiedliche Stacks verwendet werden,
ist eine Spezialität des PIC.
Alle anderen Architekturen haben einen gemeinsamen Stack für beides.
Dadurch sind auch reentrante Funktionen und rekursive Aufrufe kein
Problem.
Aber unter C ist das eh egal, da dort ein Hineinpfuschen in den Compiler
Pfui-Bäh ist.
Wenn Du unbedingt einen LIFO brauchst, dann lege Dir einfach ein Array
und einen Pointer darauf an. Ein Hineinschreiben erhöht den Pointer, ein
Auslesen verringert den Pointer und fertig ist der LIFO.
Natürlich gehört ein Test auf Unter- bzw. Überlauf mit hinein.
Peter
Hallo Peter,
habe ich gemacht, einschließlich Unter-Überlauf. Stack ist für mich auch
in Zukunft erledigt.
Routine läuft wie gewünscht.
schönen abend
Siegfried