Forum: Compiler & IDEs Rücksprungadresse auf dem Stack schwachsinnig?


von Josch (Gast)


Lesenswert?

Hallo Leute!
Ich arbeite hier mit einbem Atmel ATMega16 und AVR-GCC. Folgendes 
Problem:

Wenn eine ISR aufgerufen wird, müsste ja die Rücksprungadresse auf den 
Stack gelegt werden. Allerdings landet da nur Schwachsinn! Ich werd 
total wahnsinnig ^^

Hier mal die Details:

Sofort am Anfang der ISR steht der StackPointer auf 0x03D9. An dieser 
Stelle steht dann im SRAM eine 0x247D. Und dieser Wert ist natürlich 
jenseits von Gut und Böse (der Speicher geht ja maximal bis 0x1FFF). Ein 
sinnvoller Wert wäre eher 0x0451, denn da liegt die Funktion die 
unterbrochen wurde...

Kennt sich Jemand damit aus? Hab ich da irgendwo einen Denkfehler? Such 
ich die Rücksprungadresse an der falschen Stelle? Oder lese ich sie nur 
falsch?

Danke für eure Hilfe!

von Josch (Gast)


Lesenswert?

Sorry, ich seh gerade, dass ich das falsche Forum erwischt hab. Kann das 
Jemand verschieben? Danke! :-)

von Severino R. (severino)


Lesenswert?

und in welches Forum willst Du verschoben werden?

Werden eventuell noch Register (Status etc.) auf den Stack gepusht?

von Johannes M. (johnny-m)


Lesenswert?

Wenn der Stack Pointer am Anfang der ISR (also wenn die Adresse bereits 
gesichert wurde) auf der von Dir besagten Adresse steht, dann liegt der 
gerettete Programmzähler-Wert zwei Bytes weiter oben. Schließlich wird 
erst die Adresse gesichert und dann der Stack-Pointer dekrementiert. 
Andernfalls wüsste der Stack-Pointer ja nie, ob er jetzt um eins (push) 
oder um zwei (Adresse retten) dekrementiert werden müsste. Da wo der 
Stack Pointer aktuell hinzeigt, ist die Stelle, an der der nächste zu 
sichernde Wert abgelegt würde, wenn er kommt.

Also:
Interrupt/Funktionsaufruf tritt auf -> PC wird an Adresse von Stack 
Pointer geschrieben, Stack Pointer wird um zwei dekrementiert.

ret(i) tritt auf -> Stack Pointer wird um 2 inkrementiert, Adresse wird 
in PC geschrieben.

Ergo: Die Reihenfolge ist wichtig. Schau mal an der Adresse 0x03db (SP + 
2), da könnte was sinnvolles stehen...

An der Adresse, auf die der SP aktuell zeigt, steht fast immer Murks.

von Matthias L. (Gast)


Lesenswert?

Oder lies mal unmitelbar NACH einem RET(i) die Stelle aus, wo der SP 
hinzeigt...

von Josch (Gast)


Lesenswert?

Danke erstmal für eure Antworten! Schön, dass es noch andere Leute gibt, 
die sich so tief in die Hölle hinabwagen ;-)

Ich habe mir natürlich auch schon den gesamten Speicher um den 
StackPointer herum angesehen. Da ist nirgendwo etwas, was der 
gewünschten Rücksprungadresse ähnlich sieht. Das verrückte ist aber, 
dass er beim RETI trotzdem an die richtige Stelle zurückspringt!!! Wah!

Hier noch mehr Details:
StackPointer in der ISR:  0x3D9
StackPointer nach dem Rücksprung:  0x3DB
ProgramCounter nach dem Rücksprung: 0470

Aber diese 0470 ist nirgendwo im Speicher (in der nähe des 
StackPointers) zu sehen:
http://img215.imageshack.us/img215/3097/memoryui2.jpg


Irgendwas sehe ich da wohl falsch, weil der Rücksprung ja anscheinend 
funktioniert....

von Gast (Gast)


Lesenswert?

Hallo Josch,
sprechen wir hier über Assembler-Programm oder Hochsprachen-
compilierte Anwendung?
Letztere nutzt den Hardware-Stackpointer in völlig anderer
Manier als ein simples Assembler-Programm. Compiler verwalten
einen eigenen Stackbereich, schon weil der Hardware-Stack-
pointer bei Manipulationen über SPL- und SPH-Register nicht
solide Interrupt-fest ist.

von Matthias L. (Gast)


Lesenswert?

>ProgramCounter nach dem Rücksprung: 0470

Wie hast du denn diese Werte ausgelesen?

Kannst du mal etwas von deinem Quellcode posten? Den du zum Test 
verwendest?

von Johannes M. (johnny-m)


Lesenswert?

Gast wrote:
> Hallo Josch,
> sprechen wir hier über Assembler-Programm oder Hochsprachen-
> compilierte Anwendung?
> Letztere nutzt den Hardware-Stackpointer in völlig anderer
> Manier als ein simples Assembler-Programm. Compiler verwalten
> einen eigenen Stackbereich, schon weil der Hardware-Stack-
> pointer bei Manipulationen über SPL- und SPH-Register nicht
> solide Interrupt-fest ist.
Mal abgesehen von ein paar Sachen im Offtopic-Forum ist das der größte 
Blödsinn, den ich hier heute gelesen habe...

Da die gesamte Stack-Verwaltung im AVR durch die Hardware geschieht, 
bleibt auch einem noch so tollen Compiler nichts anderes übrig, als die 
Programmzählergeschichten der Hardware zu überlassen. Und dass der 
Hardware-Stackpointer "nicht Interrupt-fest" sein soll, ist völlig 
daneben...

von Rolf Magnus (Gast)


Lesenswert?

Ich sehe jetzt das Problem irgendwie nicht. Wenn korrekt 
zurückgesprungen wird, warum interessiert dich das dann überhaupt?

PS: Hast du auch daran gedacht, daß der Programmspeicher 16bittig 
adressiert wird, die Toolchain aber in der Regel Aderssen auf 
8-bit-Basis anzeigt?

von Josch (Gast)


Lesenswert?

@ Matthias L.: "Wie hast du denn diese Werte ausgelesen?"
Im Processor View von AVR Studio kann ich den PC ablesen. Ich hab also 
direkt hinter den Rücksprung einen Breakpoint gesetzt, und voila!

"Kannst du mal etwas von deinem Quellcode posten? Den du zum Test
verwendest?"

Na sicher ;-)

Funktion, die unterbrochen wird:
while(1)
{
  lcd_writeChar('.');
  delayMs(100);
}//end while

ISR (Timer compare match):

void SIG_OUTPUT_COMPARE1A( void )
{
  asm volatile("reti \n\t");
}

@ Rolf Magnus:
"Ich sehe jetzt das Problem irgendwie nicht. Wenn korrekt
zurückgesprungen wird, warum interessiert dich das dann überhaupt?"

Das hat verschiedene Gründe. Erstens würde ich gerne VERSTEHEN, was da 
passiert. Ich muss das ganze nämlich später anderen Leuten beibringen, 
und da sind solch grobe Verständnisprobleme sicher nicht gut!
Zweitens klappt es nicht immer. Wenn ich das Programm ein bisschen 
komplexer mache, fängt das System an, wild rumzuspringen, und alles 
kaputt zu machen. Deswegen würde ich gerne genau wissen, was es mit 
diesen komischen Adressen auf sich hat, und wo sich die "echte" 
Rücksprungadresse versteckt....

von Michael J. (jogibaer)


Lesenswert?

Hallo,

mich wundert dein reti befehl an dieser Stelle:


void SIG_OUTPUT_COMPARE1A( void )
{
  asm volatile("reti \n\t");
}

Wird das nicht vom Compiler selber erledigt ?
Wäre mir völlig neu, habe selber schon Interrupts benutzt.

Sonst haste 2 mal reti im Programm und der Prozessor
würde nur noch Amok laufen.

( Compiler gcc ?)

Jogibär

von Josch (Gast)


Lesenswert?

Vieleicht würde es auch ohne gehen, aber der fürhrt garantiert nur ein 
Reti aus. Das kann man ja mit Single-Steps gut Debuggen :-)
Müsste also OK sein!

von Michael J. (jogibaer)


Lesenswert?

Hallo,

nach mal nachgedacht.

Ja, er führt nur das erste reti aus -> aber das falsche.

Bei Interrupteinsprüngen wird nicht nur die Rücksprungadresse auf
den Stack geschrieben, sondern mindestens noch das 
Prozessorzustandswort.
(Flags wie carry u.s.w.)
(Der GCC sichert manchmal noch mehrere Register mit)

Bei deinem reti holt er bestimmt nicht die Adresse zurück,
oder kommt nach mehrmaligem Aufruf durcheinander.

Kannst Du mal den Assemblercode posten ?
Da müßte man es sehen.


Jogibär

von Josch (Gast)


Lesenswert?

Aber müsste dann nicht wenigstens IRGENDWO die richtige Adresse im 
Speicher zu sehen sein?

von Michael J. (jogibaer)


Lesenswert?

Hallo,

darum bitte ich ja auch um den Assemblercode.


Jogibär

von Johannes M. (johnny-m)


Lesenswert?

> void SIG_OUTPUT_COMPARE1A( void )
> {
>   asm volatile("reti \n\t");
> }
Wenn das ne ISR sein soll, dann entspricht die aber nicht der 
AVR-GCC-Syntax!

Außerdem (also wenn die Syntax richtig wäre) würde das sowieso 
schiefgehen, wie schon von anderen vermutet. Das führt ein reti aus, 
bevor das SREG und die ganzen anderen Register, die der Compiler am 
Beginn der ISR sichert, wieder zurückgeschrieben wurden. In dem Moment, 
in dem das reti hier ausgeführt wird, steht alles Mögliche auf dem 
Stack, nur ganz bestimmt nicht die richtige Rücksprungadresse! Das reti 
steckt in der schließenden Klammer "}" mit drin.

Da aber die Syntax völlig daneben ist, wird diese ISR vermutlich eh nie 
ausgeführt...

von Gast (Gast)


Lesenswert?

Hallo Johannes,

> Mal abgesehen von ein paar Sachen im Offtopic-Forum ist das der größte
> Blödsinn, den ich hier heute gelesen habe...

> Da die gesamte Stack-Verwaltung im AVR durch die Hardware geschieht,
> bleibt auch einem noch so tollen Compiler nichts anderes übrig, als die
> Programmzählergeschichten der Hardware zu überlassen. Und dass der
> Hardware-Stackpointer "nicht Interrupt-fest" sein soll, ist völlig
> daneben...

Nun ja, mit 30 Jahren CPU-Programmiererfahrung - davon seit 1997 auch
auf AVR - weiß ich natürlich nicht, wovon ich schreibe. ;-)

von Johannes M. (johnny-m)


Lesenswert?

@Gast:
Schau Dir einfach mal ein compiliertes AVR-C-Programm an...

Ist übrigens immer wieder toll, was Leute, die sich originellerweise 
"Gast (Gast)" nennen, hier erzählen...

von Josch (Gast)


Lesenswert?

Disassaembler (ab der Stelle wo Interrupts eingeschaltet werden):

265:        sei();
+0000046B:   9478        SEI                      Global Interrupt 
Enable
270:          delayMs(os_taskOutputDelay);
+0000046C:   91C00062    LDS     R28,0x0062       Load direct from data 
space
+0000046E:   91D00063    LDS     R29,0x0063       Load direct from data 
space
269:          lcd_writeChar('.');
+00000470:   E28E        LDI     R24,0x2E         Load immediate
+00000471:   940E0201    CALL    0x00000201       Call subroutine
+00000473:   01CE        MOVW    R24,R28          Copy register pair
+00000474:   940E0108    CALL    0x00000108       Call subroutine
+00000476:   CFF9        RJMP    PC-0x0006        Relative jump
@00000477: __vector_6
55:       {
+00000477:   9518        RETI                     Interrupt return

Der Interrrupt ist naked, daher gibt's da auch nicht mehr zu sehen. Hat 
im übrigen schon sehr gut und zuverlässig in einem anderen Projekt 
funktioniert (copy & paste).

Wäre dem Topic vielleicht dienlich, wenn kein geflame ausbräche... THX 
;-)

von Andreas Paulin (Gast)


Lesenswert?

"Im Processor View von AVR Studio"
... hm... weiß der Geier, was das Ding anzeigt.

Wenn ichs unbedingt wissen will würde ich mir lieber die SPH und 
SPL-Registerinhalte zwischenspeichern und via RS232 ausgeben lassen.

Interruptfunktionen werden so definiert:

ISR (TIMER1_COMPA_vect)
{
// hier Code einfügen
return;
}

und damit funktionierts...

von Gast (Gast)


Lesenswert?

Hallo Josh,

> void SIG_OUTPUT_COMPARE1A( void )
> {
>   asm volatile("reti \n\t");
> }

der Compiler erzeugt zu jeder Funktion eine eigene Stack-
Umgebung. Ein "reti" innerhalb einer Funktion führt zu
fehlerhaftem Programm-Verhalten - im besten Falle läuft der
Kellerspeicher irgendwann über.

von Andreas Paulin (Gast)


Lesenswert?

Ich meinte: Den Inhalt des Stacks, auf den den SP zeigt ,-)

von Josch (Gast)


Lesenswert?

Aber da die Funktion ja als naked deklariert ist, sollte doch genau das 
nicht passieren?

von Josch (Gast)


Lesenswert?

Was genau macht denn diese Schreibweise: "ISR (TIMER1_COMPA_vect)" 
anders als meine?

//! ISR for timer compare match (scheduler)
void SIG_OUTPUT_COMPARE1A( void ) _attribute_ ( ( signal, naked ) );


??? Hö?? ;-)

von Johannes M. (johnny-m)


Lesenswert?

Sorry, wenn Du hier unvollständigen Code schickst, in dem wichtige Dinge 
fehlen, dann brauchst Du Dich echt nicht zu wundern. In Deinem ersten 
Codeschnipsel stand nichts von "__attribute__..."!

von Josch (Gast)


Lesenswert?

Das ist ja auch nur im Header, daran hatte ich nicht gedacht. Sorry!

von Gast (Gast)


Lesenswert?

Hallo Johannes,
>                                                       Und dass der
> Hardware-Stackpointer "nicht Interrupt-fest" sein soll, ist völlig
> daneben...

Selbstverständlich ist der 16-bit-Stackpointer SPH, SPL bei
Manipulationen der Register über 8-Bit-Befehle nicht interrupt-fest.
Genau deshalb werden für Timer, A/D und andere 16-Bit-Register
high- und low-byte gelatcht.
Dies ist für Stackoperationen mit SPH und SPL nicht der Fall.

Die Polemik ist fehl am Platz - ob ein Beitrag hier falsch oder
richtig ist, hat mit dem Namen nichts zu tun.

von Andreas Paulin (Gast)


Lesenswert?

@Josch: Du hast die ISR mit _attribute_ ( ( signal, naked ) )

deklariert. Das sind zwei unterschiedliche, und auch gegensätzliche 
Dinge. Gerade, was das Stackaufräumen betrifft: Naked macht da 
garnichts, während

eine Signal-Funktion... etliche Register pusht und popt.


ISR ist in interrupt.h als

#define ISR(vector)          \
void vector (void) _attribute_ ((signal));    \

definiert. Und nicht naked!

von Michael J. (jogibaer)


Lesenswert?

Hallo,

kommt mal langsam wieder zurück auf den Boden.


ansonsten schau da mal rein

Beitrag "attribute"

zu signal und nacked gleichzeitig

Bin leider nicht der Crack im__attribute__ Zeugs.
Der KOMPLETTE Assemblercode VOM gcc wäre mir lieber.


Jogibär

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ich denke, du hast einfach nur vergessen, dass die Rücksprungadresse
als 16-bit-Wortadresse auf dem Stack landet, also gegenüber der
Byteadresse durch 2 geteilt.  Ansonsten habe ich selbst schon
hinreichend ``post mortem''-Analysen an AVR-Programmen gemacht um dir
sagen zu können, dass die da wirklich auf dem Stack steht. ;-) Man
muss natürlich ggf. mit dem Disassembler für die jeweilige Funktion
nachgucken, welche Register alles auf dem Stack landen und ob
ggf. noch Platz für lokale Variablen eingeräumt wird.  Die kann man
aber alle fein säuberlich abzählen, dann findet man auch die
Rücksprungadresse.

Im Gegensatz zu anderen Architekturen ist der Stack des AVR ein
post-decrement, er wird als sinngemäß als
1
*sp-- = value_to_push;

beschrieben und als
1
value_to_pop = *++sp;

gelesen.  Daher wird der Stack auch auf die oberste RAM-Zelle
initialisiert.

von Josch (Gast)


Lesenswert?

Genau, alle wieder beruhigen :-D

Ich habe euren Vorschlag die ISR zu ändern jetzt mal umgesetzt ("ISR 
(TIMER1_COMPA_vect)").
Ausserdem habe ich das böse Reti weggenommen.

Das Problem besteht allerdings weiterhin: Es wird jetzt jede Menge Zeug 
auf den Stack geworfen, wenn der Interrupt auslöst. Vorher waren es nur 
2 Byte, jetzt sind es 18. Aber immernoch ist in diesen 18 Byte die 
Rücksprungadresse nicht zu erkennen. Trotzdem springt er dann am Ende 
der ISR brav wieder zurück... komisch!

Hier nochmal die Adresse an die er aus der ISR springt: 0x00047F.
Der StackPointer bewegt sich im Bereich 0x03DB (vor dem Sprung in die 
ISR) bis 0x03C9 (Sofort am Anfang der ISR).
Und hier der Speicher: 
http://img225.imageshack.us/img225/4249/memory2xv6.jpg
Besagter Bereich (in dem die ADresse zu finden sein sollte) ist 
markiert.

von Peter D. (peda)


Lesenswert?

Josch wrote:

> Der Interrrupt ist naked, daher gibt's da auch nicht mehr zu sehen. Hat
> im übrigen schon sehr gut und zuverlässig in einem anderen Projekt
> funktioniert (copy & paste).

Daß etwas scheinbar einmal funktioniert hat, ist ne null Aussage.

Wenn Du naked benutzt, dann bist Du auch für die Registersicherung 
verantwortlich und die fehlt hier !!!

Mindestens SREG, R24,25,28,29 werden zerstört.
Dein Main wird also durch den Wolf gedreht, kein Wunder, daß dann nichts 
mehr funktioniert.


Außerdem macht naked nur Sinn, wenn der Interrupt kurz ist, z.B. nur nen 
Portpin setzen.

Hier aber wird stundenlang gewartet und schnarchlahme LCD-Ausgabe 
gemacht, die gesparten PUSH/POP bringen daher überhaupt nichts.


Peter

von Josch (Gast)


Lesenswert?

@Peter:
Darum geht es mir im Moment garnicht. An die Registersicherung habe ich 
schon gedacht, aber da sie im Moment nicht wichtig ist, hab ich sie 
rausgenaommen. Es interessieren mich wirklich nur die Rücksprünge! 
(siehe meinen letzten Post) Danke trotzdem für die Infos!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ich vermute mal, deine 0x451 (letzte beide Bytes des markierten
Bereichs) sind die Rücksprungadresse.  Liegt halt ein wenig vor der
von dir genannten.  AVR Studio hält nur an den Grenzen der `high level
instructions', also der C-Zeilen an.

Was ich oben noch vergessen hatte: die PC-Adresse auf dem Stack ist,
im Gegensatz zu vielen anderen Dingen beim AVR, big-endian. :-o

von Johannes M. (johnny-m)


Lesenswert?

Gast wrote:
> Selbstverständlich ist der 16-bit-Stackpointer SPH, SPL bei
> Manipulationen der Register über 8-Bit-Befehle nicht interrupt-fest.
> Genau deshalb werden für Timer, A/D und andere 16-Bit-Register
> high- und low-byte gelatcht.
> Dies ist für Stackoperationen mit SPH und SPL nicht der Fall.
Der Stack-Pointer wird aber auch i.d.R. durch das Programm nur ein 
einziges Mal manipuliert, nämlich bei der Initialisierung bei 
Programmstart. Deshalb ist es im Normalfall völlig unerheblich, dass es 
sich um ein 16-Bit-Register handelt. Wenn man die Hardware alles machen 
lässt, wofür sie die Möglichkeiten hat, gibt es auch keine Probleme!

von Josch (Gast)


Lesenswert?

Das dachte ich auch schon. Aber ich habe da mal angehalten, Müll in 
diese Speicherstelle reingeschrieben, und dann einen Single-Step 
gemacht. Er landet nach wie vor an der selben Stelle. Von daher muss die 
Adresse wo anders liegen....  nerv

von Josch (Gast)


Lesenswert?

OK, ich glaube ich hab's. Das Problem ist, dass AVR Studio Einfach 
manche Speicherstellen falsch anzeigt beim Debuggen. Das kann echt 
verwirren ^^

Vielen Dank euch allen!

von Josch (Gast)


Lesenswert?

Muha, zu früh gefreut! Leider zeigt AVR Studio den Speicher doch richtig 
an. Aber dafür bin ich der Lösung des Problems jetzt ein gutes Stück 
näher.

Die Adresse lautet 0x00047D, aber im Speicher steht ..00 24 7D 00...
Wo kommt da bitte die 2 her? Wäre das eine 0, wäre alles in Butter :-)

von Gast (Gast)


Lesenswert?

Hallo Johannes,
so, und nachdem die Polemik ein wenig zurück gefahren wurde
und vielleicht zugestimmt wird, dass der 16-bit-Stackpointer
bei AVR keineswegs interrupt-fest ist, sind wir vielleicht
auch zugänglich zu dem Gedankengang, den "Nixblicker" und
"Blödsinn-Erzähler" Gast bei seinem ersten Statement im Sinn
hatte.

Da speziell bei AVR der Stackpointer nicht interrupt-fest
ist, verbieten sich anderweitig gern benutzte Stackoperationen
der Art "ADD/SUB SP+x" um Variable über den Stack an
Funktionen zu übergeben oder einfach nur eine lokale
Funktions-Umgebung zu schaffen.

Abhilfe schafft ein eigener "Software-Stack", über den durchaus
auch Rückkehr-Adressen verwaltet werden können. Erst mit einem
solchen "Software-Stack" lassen sich die C-style X,Y,Z-pointer-
Operationen sinnvoll nutzen. Dazu müssen diese Pointer-Register
aber wiederum im Hardware-Stack gesichert werden.

Was der ganze Roman soll? Nun ja, anfangs stand ja im Raum,
dass es unerklärliche Inhalte im Hardware-Stack-Bereich geben
sollte. Nicht mehr und nicht weniger. Und da ist es eben nicht
zwingend so, dass dort nur return-Adressen stehen, sondern auch
x-beliebige Inhalte, z.B. auch gerettete Register-Inhalte zur
Verwaltung eines Software-Stack.

Um nicht mehr und nicht weniger ging es.
Bemerkungen wie "der größte Blödsinn" bringen in der Sache nicht
weiter. Inzwischen wurden einige Sachverhalte vom Fragesteller
präzisiert, was auch Raum für gezieltere Vermutungen schuf. Und 
letztendlich hat sich die Sache ja noch ganz anders aufgeklärt.

von Josch (Gast)


Lesenswert?

"Und letztendlich hat sich die Sache ja noch ganz anders aufgeklärt."

Nein, noch nicht ganz! Bitte meinen letzten Post beachten! ;-)

von Michael J. (jogibaer)


Lesenswert?

Jörg Wunsch wrote:
> Ich denke, du hast einfach nur vergessen, dass die Rücksprungadresse
> als 16-bit-Wortadresse auf dem Stack landet, also gegenüber der
> Byteadresse durch 2 geteilt.


Hallo,

wo steht denn das ?
Ich habe schon im Datenblatt geschaut, aber das ist mit Infos
über unser Diskussionsthema ziemlich geizig.

PS:

Das kann ich mir ehrlich gesagt gar nicht vorstellen.
Dann muß ja die ALU ständig selber hin und her rechnen.
( oder verschieben bei /2 ).

------

Habe eben was im Datenblatt zum Mega128 gefunden:

zitat': S.18

The ATmega128 Programm Counter is 16 bits wide, thus adressing the 64k
programm memory location.

16 bit = 64 K

das hört sich für mich nicht nach Wortadresse an.


Jogibär

von Gast (Gast)


Lesenswert?

Hallo Josch,
auch auf die Gefahr hin, von Anderen als "Blödsinn"-Erzähler
geoutet zu werden ;-) - wir sehen hier nur einen Ausschnitt
Deiner Codes. Kann es vielleicht sein, dass der im Listing
ausgewiesenen Adresse noch ein Offset von 0x2000 für ein
Code-Segment hinzuaddiert werden muss?
Ganz vorsichtig und unter allen Vorhalten, nur laut gedacht...

von Johannes M. (johnny-m)


Lesenswert?

Gast wrote:
> Bemerkungen wie "der größte Blödsinn" bringen in der Sache nicht
> weiter.
Das ist grundsätzlich richtig, und ich gebe zu, dass es etwas 
unverhältnismäßig war.

Es gibt hier nur dummerweise viele, die unter dem "Schutzschild-Nick" 
Gast (Gast) (und das ist, wie oben schon angedeutet, der unoriginellste 
der ganzen Troll-Nicks) allen möglichen Unsinn posten, der jeglicher 
fachlicher Grundlage entbehrt und nur Verwirrung und Ärgernis schaffen 
soll. Deshalb meine etwas "verschnupfte" Reaktion.

Nachdem sich nun ja doch herausgestellt hat, dass das oben nicht zum 
Zweck der Verwirrung gedacht war, sollten wir das auf sich beruhen 
lassen...

von Johannes M. (johnny-m)


Lesenswert?

Michael Jogwich wrote:
> Habe eben was im Datenblatt zum Mega128 gefunden:
> ...
> das hört sich für mich nicht nach Wortadresse an.
Der Mega128 hat 128KiB Flash, das sind 64Ki Worte...

von Johannes M. (johnny-m)


Lesenswert?

Der PC vom Mega16 ist übrigens nur 13 Bit breit, d.h. die 2 da hat 
überhaupt keinen Einfluss auf den Wert des PC.
PC: XXXP PPPP PPPP PPPP
      ^
  Da würde das Bit für die "2" stehen...

Scheint also tatsächlich alles im grünen Bereich zu sein.

von August, dk5ug (Gast)


Lesenswert?

Hallo Johannes,
dann möchte ich meinen Beitrag zur Versöhnung nicht
schuldig bleiben - "Gast" wie oben ersetzen.
Wer mit "dk5ug" etwas anfangen kann, weiß meine Aus-
führungen auch einzuordnen.

@Josh
Weiterhin viel Erfolg bei der Suche nach einer Erklärung
für die unpassenden Speicherinhalte!

August

von Johannes M. (johnny-m)


Lesenswert?

August, dk5ug wrote:
> Hallo Johannes,
> dann möchte ich meinen Beitrag zur Versöhnung nicht
> schuldig bleiben - "Gast" wie oben ersetzen.
> Wer mit "dk5ug" etwas anfangen kann, weiß meine Aus-
> führungen auch einzuordnen.
Kann ich als nicht-Amateurfunker zwar nichts mit anfangen, aber nix für 
ungut...

@all:
Wie weiter oben gesagt, scheint die Suche aber erfolgreich zu sein. Es 
werden anscheinend tatsächlich nur die 13 signifikanten Bits des PC 
überhaupt geschrieben, in den 3 MSB des Stack-Wortes bleibt anscheinend 
der Müll von der letzten Benutzung stehen...

von Michael J. (jogibaer)


Lesenswert?

Johannes M. wrote:
> Michael Jogwich wrote:
>> Habe eben was im Datenblatt zum Mega128 gefunden:
>> ...
>> das hört sich für mich nicht nach Wortadresse an.
> Der Mega128 hat 128KiB Flash, das sind 64Ki Worte...

Allerdings steht im Datenblatt 64K Programm Memory

64K sind 64k egal ob 8 16 oder 32 bit breit.

Den Zugriff auf den Speicher oberhalb der 64K erfolgt anscheinend 
anders.
Ist hier glaube ich schon mehrmals diskutiert worden.
Ist auch nicht unbedingt mein Steckenpferd.


Jogibär

von Johannes M. (johnny-m)


Lesenswert?

Michael Jogwich wrote:
> Allerdings steht im Datenblatt 64K Programm Memory
Da steht "64 K Program Memory *Locations*"! Eine "Location" ist im 
Zusammenhang mit dem Flash immer ein Wort.

Nur beim Zugriff mit lpm, bei dem Bytes adressiert werden, muss man sich 
etwas einfallen lassen, um die Halbbytes anzusprechen. Dafür gibts dann 
die elpm-Befehle, die zusätzliche Register nutzen, um den Adressraum 
komplett ansprechen zu können...

> 64K sind 64k egal ob 8 16 oder 32 bit breit.
64 K sind zunächst mal nur 64 * 2^10 = 65536. Ohne Einheit dahinter ist 
das nur eine Zahl. Und die Einheit steht in diesem Falle direkt 
dahinter, nämlich "Memory Locations". Genau das hast Du in Deinem 
"Zitat" aber anscheinend überlesen... Wenn da 64 K*B* gestanden hätte, 
dann hättest Du Recht gehabt.

von Michael J. (jogibaer)


Lesenswert?

Johannes M. wrote:
> Michael Jogwich wrote:
>> Allerdings steht im Datenblatt 64K Programm Memory
> Da steht "64 K Program Memory *Locations*"! Eine "Location" ist im
> Zusammenhang mit dem Flash immer ein Wort. Nur beim Zugriff mit lpm, bei
> dem Bytes adressiert werden, muss man sich etwas einfallen lassen, um
> die Halbbytes anzusprechen. Dafür gibts dann die elpm-Befehle, die
> zusätzliche Register nutzen, um den Adressraum komplett ansprechen zu
> können...
>
>> 64K sind 64k egal ob 8 16 oder 32 bit breit.
> 64 K sind zunächst mal nur 64 * 2^10 = 65536. Ohne Einheit dahinter ist
> das nur eine Zahl. Und die Einheit steht in diesem Falle direkt
> dahinter, nämlich "Memory Locations"...

Hallo,

hoppla, da wirst Du wohl recht haben.
Der Speicher ist organisiert in 16 Bit, das könnte stimmen.

( im Datenblatt gibt es ein paar Stellen, wo man aufpassen muß,
ob die nun Wort oder Byteadressen meinen)

Bloß warum wir dann immer so ein Aufriß beim Überschreiten der 64K
Programmgröße gemacht ?

Jogibär

von Johannes M. (johnny-m)


Lesenswert?

Michael Jogwich wrote:
> Bloß warum wir dann immer so ein Aufriß beim Überschreiten der 64K
> Programmgröße gemacht ?
Das ist eigentlich nur für den oben erwähnten Zugriff auf im Flash 
abgelegte Konstanten (z.B. Textstrings) (über den Assembler-Befehl elpm) 
problematisch, weil die in der lib enthaltenen Funktionen 
(pgm_read_byte_far() und anverwandte) in der aktuellen Implementierung 
nur 64 KiB adressieren können. Vom Programmcode her ist das an sich kein 
Problem.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johannes M. wrote:

>> Bloß warum wir dann immer so ein Aufriß beim Überschreiten der 64K
>> Programmgröße gemacht ?

Wird doch gar nicht, erst beim ATmega256x wird es haarig.  Das Ausnutzen
der 128 KiB ROM für Programmcode auf dem ATmega128 ist gar kein
Problem (und war nie eins).

> Das ist eigentlich nur für den oben erwähnten Zugriff auf im Flash
> abgelegte Konstanten (z.B. Textstrings) (über den Assembler-Befehl elpm)
> problematisch, weil die in der lib enthaltenen Funktionen
> (pgm_read_byte_far() und anverwandte) in der aktuellen Implementierung
> nur 64 KiB adressieren können.

Gerade pgm_read_byte_far() kann mehr adressieren. ;-)  Insbesondere
können aber alle _P-Funktionen (strcpy_P, memcpy_P und sowas) nur mit
16-bit-Adressen umgehen, und da sie den ROM als Daten adressieren,
können sie also nur 64 KiB daraus zugreifen.  Wer mehr haben will, muss
sich um die größere Adressierung selbst kümmern und pgm_read_*_far()
benutzen.

Ja, ein wenig Verwirrend ist diese Dualität des AVR-ROMs schon.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johannes M. wrote:

> Wie weiter oben gesagt, scheint die Suche aber erfolgreich zu sein. Es
> werden anscheinend tatsächlich nur die 13 signifikanten Bits des PC
> überhaupt geschrieben, in den 3 MSB des Stack-Wortes bleibt anscheinend
> der Müll von der letzten Benutzung stehen...

Das erklärt das Symptom natürlich.  Wäre ich auch nicht drauf gekommen,
da ich im Wesentlichen ATmega1281 benutze, bei denen natürlich immer
alle Bits geschrieben werden.  Aus Hardwaresicht ist das Ganze dagegen
verständlich: die Hardware zählt nicht in Bytes, sondern sie ist in
Bits implementiert.  Wenn man ein bestimmtes Bit nicht braucht, wird
es eben gar nicht erst realisiert.

von Johannes M. (johnny-m)


Lesenswert?

Jörg Wunsch wrote:
> Das erklärt das Symptom natürlich.  ...
Ist aber auch nur eine Vermutung, die zumindest die "2" da erklären 
würde...

von Josch (Gast)


Lesenswert?

Aber die 2 schreibt er da schon bewusst rein. Ich habe vorher mal den 
ganzen Speicher mit Nullen gefüllt, aber sobald der entsprechende 
Breakpoint erreicht ist, klatscht er die 2 zusammen mit der Adresse da 
rein :-(

von Johannes M. (johnny-m)


Lesenswert?

Seltsam isses schon. Aber wie gesagt, eine Bedeutung dürfte dem Bit 
nicht zukommen. Zumindest nicht in Hinblick auf den Programmzähler/die 
Rücksprungadresse...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Josch wrote:

> Aber die 2 schreibt er da schon bewusst rein.

Ja, sehe ich jetzt auch, habe mir auch mal einen ATmega16 rausgekramt.
Ich vermute mal, dass das eine Optimierung des Hardwarecompilers ist.
In der Hardwarebeschreibung gibt es außer 0 und 1 noch diverse
andere mögliche Zustände, u. a. kann man da auch sagen, dass einen
ein bestimmtes Bit gar nicht interessiert.  Bei der Synthese des
Gatternetzwerkes steht es dann dem Compiler frei, dafür einen
beliebigen Bitwert einzutragen, was auch immer das kleinere Gesamtnetz
ergibt.

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.