Bei Adresse 1792 (Markierung #1) wird *pushPtr korrekt per lpm geladen.
In der While-Schleife auf Adresse 17b0 (Markierung #2) wird der nächste
code geladen - diesmal nicht per lpm sondern mit ld. Der Compiler hat
also den Modifier __flash am pushPtr verloren und liest jetzt aus dem
RAM.
Wenn ich die Deklaration für pushPtr ändere in
1
const__flashuint16_t*pushPtr=…
verschwinden die 3 seltsamen eor ab Adressen 1796 und 17b4. Am
Ladefehler in der while-Schleife ändert sich nichts.
Ändere testweise die Initialisierung so, dass dem Compiler nichts über
die Flash-Adresse bekannt ist, auch kein Wertebereich, und kein Cast
darin vorkommt. Beispielsweise per Parameter von ebendiesem Typ. Es geht
dabei nur um den erzeugten Code, das Programm muss nicht funktionieren.
Die 3 EORs sind ein Byte-Swap. Du bist ganz sicher, dass der
präsentierte Quellcode und der Asm-Code zusammen gehören?
typedef ... ptr_t;
void initWatchdog(uint8_t timeout, ptr_t init_p) {
...
ptr_t pushPtr = init_p;
...
Aber bitte so, dass der Compiler den Aufruf der Funktion nicht sieht.
Schau jedoch erst einmal, ob das SWAPB genau das ist oder war, was du
oben reingeschrieben hast. Notfalls im Preprocessor-Output. Ich tippe
drauf, dass die EORs etwas mit SWAPB zu tun hatten.
A. K. schrieb:> Aber schau erst einmal, ob das SWAPB genau das ist, was du oben> reingeschrieben hast. Notfalls im Preprocessor-Output.
Das SWAPB habe ich wegdefiniert:
Die Initialisierung für pushPtr mit 0x1a ändert auch nichts.
A. K. schrieb:> Die 3 EORs sind ein Byte-Swap. Du bist ganz sicher, dass der> präsentierte Quellcode und der Asm-Code zusammen gehören?
Die eor kommen vom SWAPB in der ursprünglichen Definition - etwas
umständlich, wenn man einfach nur die Register beim Laden vertauschen
müsste…
A. K. schrieb:> Ändere testweise die Initialisierung so, dass dem Compiler nichts über> die Flash-Adresse bekannt ist,Uhu U. schrieb:> const __flash uint16_t *pushPtr = 0x1a;
Hier kennt der Compiler die Adresse.
Uhu U. schrieb:> Die eor kommen vom SWAPB in der ursprünglichen Definition - etwas> umständlich, wenn man einfach nur die Register beim Laden vertauschen> müsste…
Die beiden Ladebefehle bilden eine Einheit bei der Umsetzung der 16-Bit
Operation auf die 8-Bit Maschine.
A. K. schrieb:> typedef ... ptr_t;> void initWatchdog(uint8_t timeout, ptr_t init_p) {> ...> ptr_t pushPtr = init_p;> ...>> Aber bitte so, dass der Compiler den Aufruf der Funktion nicht sieht.
Der Aufruf steht in einem anderen Quellfile.
Wenn man es so macht, wie du vorgeschlagen hast, ist der Fehler weg (mit
wegdefiniertem SWAPB):
Uhu U. schrieb:> Der Quellcode:
Wozu soll dieser Code denn gut sein?
Wofür auch immer, mit neueren Compilerversionen wird er nicht mehr
funktionieren.
Falls in der ISR kein Frame gebraucht wird, dann kann die Anzahl der
PUSHes im Prolog ganz einfach und unabhängig von der Compilerversion
erhalten werden, zum Beispiel:
Falls der Wert in einer anderen Funktion als der ISR benötigt wird, dann
ist es etwas komplizierter und hässlicher, aber immer noch portabel
zwischen unterschiedlichen Versionen von avr-gcc machbar:
1
// !!!
2
// !!! Muss mit -fno-toplevel-reorder compiliert werden
3
// !!! und unmittelbar auf die ISR folgen!
4
// !!!
5
6
externconstuint8_tn_pushed;
7
8
__asm(".global n_pushed""\n\t"
9
".section .rodata.n_pushed,\"a\",@progbits""\n"
10
"n_pushed:""\n\t"
11
".byte .L__stack_usage");
Auch die return-Adresse einer Funktion kann man bekommen, und zwar mit
__builtin_return_address(0).
http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html
An die Speicheradresse der return-Adresse auf dem Stack kommt man aber
leider nicht per Built-in heran.
Was v4.8 angeht, die ist ja schon was älter — ob es da ein Problem mit
Address-Spaces gab weiß ich jetzt nicht mehr. Auf die Schnelle find ich
zumindets kein passenden PR. Ne neuere Version wäre jedenfalls kein
Luxus.