Forum: Mikrocontroller und Digitale Elektronik Hilfe bei "Codeverständnis"


von Max (Gast)


Lesenswert?

Hallo zusammen,

ich mache gerade ein Praktikum bei einer Elektronikfirma. Als Aufgabe 
habe ich die Importierung eines ATMega88 Codes auf einen ATXMega16D 
bekommen. Leider ist der Entwickler dieses Programmcodes nicht mehr in 
der Firma, so dass ich keinen Ansprechpartner für gezielte Fragen habe. 
Im Grunde klappt die Importung bis jetzt recht gut. Nur eine Routine 
macht mir Kopfzerbrechen, da ich Ihre Funktionsweise nicht verstehe:
1
void init_varis(void)
2
{  
3
  uc_8 i;
4
5
  i = input(SPL);
6
  i ^= 0xFF;
7
  
8
  extern ui_16 __bss_start;
9
  extern ui_16 __stack;
10
  uc_8 *ptr = (uc_8*)&__bss_start;
11
12
  while((ptr<(uc_8*)&__stack - i) &&(ptr <= 0x038F)){/*sub because of returning of subroutine*/
13
    *ptr++=0;
14
  }
15
}

Ich verstehe bis jetzt nur, dass die Inhalte der Speicheradressen bis 
0x038F mit 0 beschrieben werden, also eine Art Initialisierungsroutine. 
Doch was bedeutet input(SPL) und warum beginnen die beiden Variablen mit 
__? Zweites ist wahrscheinlich egal, aber vielleicht gibt es ja nen 
Grund warum das mal so gemacht wurde.

Viele Grüße,
Max

von Karl H. (kbuchegg)


Lesenswert?

Max schrieb:

> Doch was bedeutet input(SPL)

das ist der Aufruf einer Funktion. Es könnte auch ein Makro sein.

Auf jeden Fall ist es nichts aus dem C-Standard. D.h. du wirst den Rest 
des Projekts durchforsten müssen, ob es wo eine derartige Funktion gibt, 
bzw. ein Makro, und ansehen was die macht.
Findest du nichts, dann gilt es deine Compilerdoku zu durchforsten, denn 
dann ist das eine in deinem System vordefinierte Funktion.

> und warum beginnen die beiden Variablen mit
> __?

Weil Namen, die mit __ beginnen für die IMplementierung reserviert sind. 
D.h. die beiden __ sagen dir als C-Programmierer, dass diese beiden 
Variablen vom Compiler/Library zur Verfügung gestellt werden und einfach 
'magisch vorhanden' sind. Sie haben eine spezifische Bedeutung, welche 
steht im Handbuch deines Compilers.

von Peter D. (peda)


Lesenswert?

Max schrieb:
> aber vielleicht gibt es ja nen
> Grund warum das mal so gemacht wurde.

Der Grund erschließt sich vielleicht dadurch, wann diese Routine 
aufgerufen wird.

Normaler Weise läßt man den Stack nämlich in Ruhe, der gehört alleine 
dem Compiler.
Und genullt wird der gesamte SRAM auch automatisch.

von Amateur (Gast)


Lesenswert?

Bei unbekannten Namen wäre ein kleiner Hinweis auf die 
Entwicklungsumgebung nicht schlecht. Muss aber nicht sein, da alle, die 
die Gleiche benützen, wissen was Sache ist.

von ConvertsQuestionsToAnswers (Gast)


Lesenswert?

1
input(SPL);

Eine recht plausible Vermutung ist, das hier das Low-Byte des 
Stackpointers geholt wird. Darauf deuten "SPL" hin und die Verwendung 
des Funktionsnamens "input", was konsistent mit der Tatsache ist, das 
der Stackpointer unter einer IO-Adresse zuzugreifen ist.

"__bss_start" und "__stack" beginnen mit einem doppelten Unterstrich um 
Konflikte zwischen Systemvariablen (das sind sie nämlich) und Variablen 
des Benutzerprogrammes zu verhindern.

Deine Vermutung, das hier ein Speicherbereich auf 0 gesetzt wird ist 
korrekt.
Die Bedingung in der while-Schleife sorgt dafür das der Inhalt des 
bbs-Segmentes (siehe Compilerdokumentation) bis herauf zum Anfang der 
momentanen 256-Byte Seite des Stacks initialisiert wird.

Achte darauf, das die Konstante 0x038F Prozessorabhängig ist. Du wirst 
sie wahrscheinlich ändern müssen.

Den Grund kann ich mir im Moment nicht so ohne weiteres denken. Eine 
Vermutung wäre, das man das mal für Debug-Zwecke benutzt hat. Man müsste 
mal den gesamten Code sehen (aber frage vorher Deinen Arbeitgeber ob es 
OK wäre den zu veröffentlichen).

von Max (Gast)


Lesenswert?

Vielen Dank für die Antworten. Nun hab ich es verstanden.

Das "input" ist in der ina.90 des GCC folgendermaßen definiert:
1
#define input(port) (port)

Die "__bss_start" und "__stack" werden vom Linker definiert. Hier eine 
ähnliche Beschreibung aus dem AVR-Freaks Forum.

With AVR gcc, two symbols are defined by the linker that can make this 
easy. These are _end and __stack which define the first free byte of 
SRAM after program variables, and the starting address of the stack, 
respectively.

The stack starts at __stack, which is conventionally the highest byte of 
SRAM, and grows towards zero; _end will be somewhere between zero and 
__stack. If the stack ever falls below _end, it has almost certainly 
corrupted program data

von Softwareverwickler (Gast)


Lesenswert?

Hallo Max,

Das ist ein Stück Code, wie es eigentlich beim startup vor dem 
eigenlichen Programm aufgeführt wird.
Nach dem reset sind auf einem uC noch nicht die Bedingungen gegeben, von 
denen man in einer Hochsprache ausgeht. In C sind es nicht so viele und 
oft wird alles Nötige in einem Stück assemblercode erledigt, aus dem 
dann main aufgerufen wird. Wird der uC nur mit internem RAM u. ROM 
betrieben, ist bei den Standard-Libs meist schon der nötige Code oder 
ein Object file vorhanden, welches automatisch mit gelinkt wird.

Im bss Segment landen globale und statische Variablen, welche nicht 
direkt explizit initialisiert werden. In C sind diese automatisch Null.

Die Schleife nullt das gesammte bss segment aber wohl auch den "oberen" 
bis zu diesem Punkt zur Laufzeit nicht genutzten Teil des Stack, der 
meist auf das bss segment folgt (maximal jedoch bis addr 0x38f). Wobei 
das nur mit nen paar Annahmen aufgeht.

Hier wird in i das lowbyte des Stackpointers gespeichert und dann 
invertiert:
1
i = input(SPL);
2
i ^= 0xFF;

und hier von der letzten stackaddresse abgezogen.
1
(uc_8*)&__stack - i

Für mich ergibt das Sinn, wenn das stack segment bei 0x300 beginnt, die 
Stackgröße 256 Byte beträgt und __stack  auf 0x3FF liegt.
Für die Berechnung der aktuellen stackgröße ist dann nur das lowbyte des 
stackpointers notwendig. Die Invertierung ist äquivalent zu 255 - SPL.
&__stack - (255 - SPL) ergibt dann 0x300 + SPL, also die kleinste 
genutzte adresse vom stack.

Der Code ist wirklich nicht so dolle.
Es gibt keinen Kommentar, der beschreibt, warum dies so gemacht wurde.
Was der Code macht, ist nicht wirklich offensichtlich. Es geht nur mit 
gewissen Rahmenbedingungen auf, die auch nicht in nem Kommentar 
auftauchen.
Die feste Maximalgrenze von 0x38f macht mich etwas stutzig. Da wäre dann 
doch einiges vom stack zum zeitpunkt des aufrufs belegt. Es laufen wohl 
schon einige funktionen die lokale variablen angelegt haben, aus diesen 
dann diese init funktion aufgerufen wird. Oder in main werden viele 
variablen angelegt die die gesammte laufzeit von bedeutung sind.

Schöne Grüße

Stephan

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.