Ich mochte einer in ASM geschriebenen Funktion eine Rückkehradresse
unterschieben:
1
ldi r30, lo8(retaddr)
2
ldi r31, hi8(retaddr)
3
push r30
4
push r31
5
rjmp funktion
6
7
...
8
9
retaddr:
10
...
11
12
funktion:
13
<tuwas>
14
ret
Eigentlich sollte funktion mit dem ret nach retaddr springen -
zumindest ist das meine Intension.
Wenn ich den Code im Simulator durchspiele, dann endet der ret auf einem
ungültigen Befehl weit ab vom eigentlichen Ziel und der Simulator
startet mein Programm wieder von vorne.
Ursache ist, daß die beiden ldi-Befehle einen Wert ins Z-Register
geladen haben, der mit der Rückkehradresse ziemlich wenig zu tun hat.
Auf dem Stack stehen der Z-Inhalt nach den pushs in der Reihenfolge
hi/lo - das scheint zu stimmen.
In meinem Programm hat schon keines der in Z geladenen Bytes was mit der
Adresse von retaddr zu tun.
Was ist das falsch?
Aus dem Bauchgefühl heraus:
Programmworte sind 2 Bytes lang. Du solltest folgendes mal versuchen:
ldi r30, lo8(retaddr*2)
ldi r31, hi8(retaddr*2)
push
push
rjmp
Beim Laden von Tabellen aus dem Programmspeicher muss man auch die
Adresse mit 2 multiplizieren.
Hoffe ich habe ins Schwarze getroffen ...
Gruß,
Thomas
Ich nehm die Aussage aus meinem vorigen Post zurück. Habe es gerade mal
ausprobiert und gebe spess53 recht. Der Code aus dem ersten Post
funktioniert im AVR-Studio (Simulator 2) einwandfrei.
Vielleicht verändert <tuwas> ja den Stackpointer oder den Inhalt des
Stacks?
Gruß,
Thomas
Klaus2m5 schrieb:> Warum so kompliziert?>> rcall funktion> rjmp retadr
Weil das keinen Unterschied macht. Der Trick ist, daß ich funktion
eine beliebige Reckkehradresse unterschieben will; die soll also an
unterschiedliche Stellen zurückkehren - die wird im eigentlichen Code im
Z-Register mitgebracht.
spess53 schrieb:> Bei mir funktioniert das. Stackpointer richtig initialisiert?
Ja, denn das Ganze spielt sich in einem C-Programm ab. Ich kann mir im
Simulator auch den Stack ansehen. Dort wird einfach Scheißdreck, der ein
ganzes Stück hinter dem Code-Ende liegt, drauf geladen.
Hier mal die wesentlichen Code-Teile:
ldz .S1 ; Hier wird eine unsinnige Adresse geladen
50
rjmp pushregs
51
52
Reschedule:
53
; r24, r25: delay
54
; r22, r23: reload
55
; r20, r21: hdlr
56
;ldz .S2
57
ldi r30, lo8(.S2)
58
ldi r31, hi8(.S2)
59
rjmp pushregs
60
.S2:
61
breq .S1
62
63
.S3:
64
ldi r24, 0
65
ldi r25, 0
66
rcall GetTableEntry
67
68
.S1:
69
brne .S4
70
71
std z+, r28
72
std z+, r29
73
std z+, r12
74
std z+, r13
75
std z+, r14
76
std z+, r15
77
.S4:
78
pop r29
79
pop r28
80
pop r15
81
pop r14
82
pop r13
83
pop r12
84
out __SREG__, r0
85
pop r0
86
ret
1
// Testcode im C-Programm, das die ASM-Routine aufruft:
2
Schedule(10,10,funktionsadresse);
Der Trick bei der Sache ist, daß es für Schedule insgesamt 4
Funktionseinsprünge gibt, die sich im Wesentlichen nur durch die Anzahl
der übergebenen Parameter unterscheiden und zwei verschiedene Einsprünge
in Reschedule benötigen.
Die zwei weiteren Einsprungpunkte habe ich mir hier gespart.
Gegenüber dem entsprechenden C-Code bringt das über 100 Byte Platz
Könnte es sein, daß Du über ldz .S1 eine Byteadresse bekommst, auf den
Stack aber eine Wordadresse pushen musst ?
Hatte fast genau dasselbe in Bascom gemacht (Return aus ISR umgebogen),
da musste die Labeladresse einmal rechtsgeschoben werden.
Da scheint was am Simulator schief zu gehen. Wenn ich mir den .map-File
ansehe, sollte die Adresse von .S1 richtig im Z-Register stehen.
Nur im Programmspeicher des Simulators stehen in der Gegend nur noch
ffffs.
Der Code ist für Mega168 compiliert und der Simulator ist auf Mega168
eingestellt.
Dafür geht nur der Simulator1...
MWS schrieb:> Könnte es sein, daß Du über ldz .S1 eine Byteadresse bekommst, auf den> Stack aber eine Wordadresse pushen musst ?
Labels aus dem Programmspeicher haben doch automatisch Wortadressen.
Bytes kann man dort nicht adressieren.
Wie das mit Bascom ist, weiß ich allerdings nicht.
Hi
>Da scheint was am Simulator schief zu gehen.
Unwahrscheinlich. Die Simulatoren haben zwar ein paar Probleme mit
Hardwarecomponenten. Aber der Programmablauf wird korrekt simuliert.
MfG Spess
spess53 schrieb:> Aber der Programmablauf wird korrekt simuliert.
Ja, das ist der Fall - der Simulator führt den Opcode 0xffff aus und
dann knallts.
Die Frage ist, warum der Mist nicht richtig geladen wird.
Uhu Uhuhu schrieb:> MWS schrieb:> Labels aus dem Programmspeicher haben doch automatisch Wortadressen.> Bytes kann man dort nicht adressieren.>> Wie das mit Bascom ist, weiß ich allerdings nicht.
Da gibt's 'ne Funktion Loadlabel() dafür und die liefert eine
Byteadresse.
In C kann das natürlich ganz anders sein, wollt' nur darauf hinweisen.
Du kannst ja das Ergebnis des Makros mit der tatsächlichen Adresse des
Labels vergleichen.
Kannst Du compilierfähigen Code einstellen ?
Ich entwickle eigentlich unter Linux mit Eclipse und gcc. Zum simulieren
benutze ich eine XP-VM, die unter Linux läuft und Zugriff auf mein
Entwicklungsverzeichnis unter Linux hat. Dort simuliere ich Komponenten
mit AVR-Studio 4.18 und avr-gcc 4.3.3.
Frage: Kann man dem AVR-Studio irgendwie das auf Linux mit avr-gcc 4.6.0
produzierte Compilat zwecks Simulation unterschieben?
MWS schrieb:> Du kannst ja das Ergebnis des Makros mit der tatsächlichen Adresse des> Labels vergleichen.
Ja, hab ich gemacht. Die Adresse stimmt, nur steht im Programmspeicher
des Simulators an der Stelle nichts vernunftiges mehr - siehe oben.
spess53 schrieb:> Nachtrag: Statt dieses Stackgefummels kannst du auch 'ijmp' verwenden:
Leider nicht. Ich habe 4 Entrypoints, die alle den Prolog-Code pushregs
brauchen und anschließend an zwei verschiedene Stellen in Reschedule
fortsetzen sollen.
So wie ich es im Moment habe, werden halt noch ein paar Byte zusätzlich
gespart.
Der Einfachkeit halber habe ich zwei weitere Entrypoints weggelassen.
Uhu Uhuhu schrieb:> Frage: Kann man dem AVR-Studio irgendwie das auf Linux mit avr-gcc 4.6.0> produzierte Compilat zwecks Simulation unterschieben?
Wenn's dort ein default Verzeichnis mit .elf, .hex. lss, .o, map gibt,
dann das .elf in AVR-Studio öffnen.
Simon K. schrieb:> Wenn du offen für neue Ansätze bist, würde ich sagen: Lass das Gefummel> und machs "richtig".
"Richtig"? Ach nee.
1. ist die Codierung nicht das Problem und
2. dreht es sich ganz offensichtlich um eine Platzoptimierung - da sind
eben andere Dinge "richtig", als in der reinen Lehre...
Zudem habe ich den Code auch in C - getestet und lauffähig.
MWS schrieb:> Wenn's dort ein default Verzeichnis mit .elf, .hex. lss, .o, map gibt,> dann das .elf in AVR-Studio öffnen.
Danke, das werd ich probieren.
Uhu Uhuhu schrieb:> Ja, denn das Ganze spielt sich in einem C-Programm ab.
Das hättest Du gleich sagen sollen.
Es gibt dabei einige Probleme:
1. Welcher C-Compiler?
2. Der AVR-GCC zählt die Adressen byteweise.
3. Der AVR-GCC berechnet RJMP/RCALL falsch bei absoluten Adressen, als
Würgaround werden daher IJMP/ICALL verwendet.
4. Eine Adresse ist beim Compilieren relativ zum Objectfile. Die
richtige Adresse ermittelt erst der Linker.
Peter
Uhu Uhuhu schrieb:> Simon K. schrieb:>> Wenn du offen für neue Ansätze bist, würde ich sagen: Lass das Gefummel>> und machs "richtig".>> "Richtig"? Ach nee.>> 1. ist die Codierung nicht das Problem und> 2. dreht es sich ganz offensichtlich um eine Platzoptimierung - da sind> eben andere Dinge "richtig", als in der reinen Lehre...
Kauf dir einen "größeren" AVR.
Peter Dannegger schrieb:> 1. Welcher C-Compiler?Beitrag "Re: AVR-ASM: Simulierter call"> 3. Der AVR-GCC berechnet RJMP/RCALL falsch bei absoluten Adressen, als> Würgaround werden daher IJMP/ICALL verwendet.
Aber Rückkehradressen sind doch immer absolut, egal ob sie von einem
RCALL, oder einem ICALL stammen.
Wenn ich die Adresse eines Code-Labels ins Z-Register lade, dann ist
das, was hinterher dort drin steht die Adresse, unter der der gelabelte
Code steht und PC-kompatibel und auf den Stack als Rücksprungadresse
speicherbar.
Richtig?
Wenn ich versuche, den Wert des Labels 1 Bit nach recht zu verschieben,
oder zu halbieren, beschwert sich der ASM:
Error: invalid sections for operation on `.S2' and `L0'
Puh, die zu Fuß auf den Stack gepushte Adresse muß tatsächlich halbiert
werden, um an die richtige Stelle im Code zu kommen.
Das ist wirklich total kaputt...
Gibt es iregend eine Direktive, die aus einem Label was macht, was man
halbieren kann, oder ist der Linker zu doof für solche Kunststücke?
Uhu Uhuhu schrieb:> Puh, die zu Fuß auf den Stack gepushte Adresse muß tatsächlich halbiert> werden, um an die richtige Stelle im Code zu kommen.>> Das ist wirklich total kaputt...>
Hab's lauffähig und auch gesehen, daß tatsächlich die Byteadresse
geliefert wird.
> Gibt es iregend eine Direktive, die aus einem Label was macht, was man> halbieren kann, oder ist der Linker zu doof für solche Kunststücke?
Im Macro R30/R31 shiften ;-)
>Ja, hab ich gemacht. Die Adresse stimmt, nur steht im Programmspeicher>des Simulators an der Stelle nichts vernunftiges mehr - siehe oben.>Ja, hab ich gemacht. Die Adresse stimmt, nur steht im Programmspeicher>des Simulators an der Stelle nichts vernunftiges mehr - siehe oben.
Also hat die Adresse doch nicht gestimmt.
MfG Spess
Hi
Zweites Zitat durch:
>Puh, die zu Fuß auf den Stack gepushte Adresse muß tatsächlich halbiert>werden, um an die richtige Stelle im Code zu kommen.
ersetzen.
MfG Spess
spess53 schrieb:> Also hat die Adresse doch nicht gestimmt.
Sie hat mit dem übereingestimmt, was im .lss-File und im Map-File steht.
Nur ist die Hardware etwas anderer Meinung, als der gcc...
Ja klar, nur würde ich mir halt gerne solche Laufzeit-Klimmzüge ersparen
und das dem ASM überlassen.
Der gcc ist eben für schöne von-Neumann-Maschinen konzipiert und nicht
für solche Harvard-Schrumpfarchitekturen...
Uhu Uhuhu schrieb:> Sie hat mit dem übereingestimmt, was im .lss-File und im Map-File steht.
Schau Dir im .lss ganz links die Adressen-LBytes an, dann siehst Du daß
dort in Byteadressen gezählt wird:
Simon K. schrieb:> Kauf dir einen "größeren" AVR.
Tja mein lieber Simon. Es gibt brutale und clevere Lösungen.
Die cleveren brauchen nur meistens etwas Hartnäckigkeit...
Hi
>>spess53 schrieb:>> Bei mir funktioniert das.>Wie hast du das denn geschafft?
Ich bin ja nicht der einzige:
Beitrag "Re: AVR-ASM: Simulierter call"
Beim stinknormalen AVR-Assembler funktioniert das. Dort ist ein Label
eine Wordadresse. Das der C-Assembler das anders sieht, finde ich
irgendwie krank.
MfG Spess
spess53 schrieb:> Beim stinknormalen AVR-Assembler funktioniert das. Dort ist ein Label> eine Wordadresse.
Welcher ist das? Ist der mit gcc objektkompatibel?
> Das der C-Assembler das anders sieht, finde ich irgendwie krank.
Nicht nur du...
Uhu Uhuhu schrieb:> Labels aus dem Programmspeicher haben doch automatisch Wortadressen.> Bytes kann man dort nicht adressieren.
Wie kommst du auf sowas? Daß man keinen Instruction-Fetch von einer
ungeraden Adresse machen kann heisst doch nicht, daß man nicht eine
ungerade Adresse bilden könnte. Das wird zB regelmässig bei Daten im
Flash gemacht, die Byte-aligned sind. Ein Data-Read von einer ungeraden
Adresse ist also sehr wohl möglich!
Uhu Uhuhu schrieb:> Stefan Ernst schrieb:
Uhu Uhuhu schrieb:> Super. Wo steht denn das?
Z.B. im Assembler-Output des Compilers. ;-)
Man nehme einen Funktions-Zeiger, und sehe nach, wie der Compiler die
"Word/Byte-Adress-Sache" handhabt.
Es steht auch in der Dokumentation das Assemblers, aber die Erklärung
dort ist irgendwie nicht so richtig deutlich (finde ich jedenfalls).
Hi
>Welcher ist das?
Der bzw. die vom AVR-Studio.
Ist der mit gcc objektkompatibel?
Kann ich nicht sagen. Ich programmiere in Assembler. Wenn ich so etwas
sehe, weiss ich auch warum.
MfG Spess
Johann L. schrieb:> Wie kommst du auf sowas?
Der AVR adressiert den Programmspeicher tatsächlich wortweise - oder wie
willst du sonst mit 16-Bit-Adressen 128 kb adressieren?
Der lpm-Befehl kann entsprechend auch nur 64 kb Programmspeicher
adressieren - vermutlich liest der intern ein Wort aus und pickt dann
entsprechend dem niederwertigsten Adreßbit das entsprechende Byte raus.
Für AVRs mit bis zu 32 k Worten Programmspeicher mag das akzeptabel
sein. Darüber wirds einfach nur ätzend.
Und wie du dem Posting von spess entnehmen kannst, sind nicht alle
AVR-Assembler nur auf Biegen und Brechen auf den AVR angepaßt worden.
spess53 schrieb:> Wenn ich so etwas sehe, weiss ich auch warum.
Wie wir gesehen haben, gibts einen Hack, mit dem man die Klippe
umschiffen kann.
Aber schön ist sowas wirklich nicht. (Vielleicht sollte man diese
Kategorie im Zusammenhang mit den ATmegas und deren noch kleineren
Brüder einfach wegschließen.)
808x und Z80 sind wirklch kleine Schönheiten...
Uhu Uhuhu schrieb:> Der AVR adressiert den Programmspeicher tatsächlich wortweise - oder wie> willst du sonst mit 16-Bit-Adressen 128 kb adressieren?
Das geht mit RAMPZ.
Hi
>Der lpm-Befehl kann entsprechend auch nur 64 kb Programmspeicher>adressieren
Jein. Es gibt noch ELPM. Zusammen mit RAMPZ geht es auch größer.
MfG Spess
Uhu Uhuhu schrieb:> Johann L. schrieb:>> Wie kommst du auf sowas?>> Der AVR adressiert den Programmspeicher tatsächlich wortweise - oder wie> willst du sonst mit 16-Bit-Adressen 128 kb adressieren?
Beim Instruction-Fetch: ja, beim Data-Read: nein. Das ist auch der Grund
für:
> Der lpm-Befehl kann entsprechend auch nur 64 kb Programmspeicher> adressieren.> Und wie du dem Posting von spess entnehmen kannst, sind nicht alle> AVR-Assembler nur auf Biegen und Brechen auf den AVR angepaßt worden.
Was meinst du mir "Biegen und Brechen? Woher soll ein Assembler denn
wissen, wie du ein Symbol verwenden willst? Ob ein LMP folgt oder ob's
ein IJMP wird?
Du kannst es entweder zur Laufzeit umrechnen oder das genannte Feature
der binutils verwenden, die es dir erlauben, einen optimierten Code zu
erstellen durch Einfügen eines speziellen RELOCs und die Umwandlung zur
Laufzeit zu sparen.
> Wie wir gesehen haben, gibts einen Hack, mit dem man die Klippe> umschiffen kann.
As ist die AVR-Hardware, die einen Registerinhalt einmal als
Wort-Adresse interpretiert (IJPM, ICALL, RET, ...) und einmal als
Byte-Adresse (LPM). Dieser "Hack" ist also im AVR-Core. :-)
Uhu Uhuhu schrieb:> Aber wenn man immer nur in C programmiert, ist das auch schnuppe...
Wie Du erkennen konntest, schadet auch ein Blick abseits vom eigenen Weg
nicht ;D
HI
>Was meinst du mir "Biegen und Brechen? Woher soll ein Assembler denn>wissen, wie du ein Symbol verwenden willst? Ob ein LMP folgt oder ob's>ein IJMP wird?
Die Assembler des AVR-Studios gehen generell bei einem Label von einer
Wordadresse aus. Bei dem Sonderfall 'lpm', bei dem auf eine Byteadresse
zugegriffen wird, muss man die Adresse explizit verdoppeln. Irgendwie
logisch.
MfG Spess
Johann L. schrieb:> Was meinst du mir "Biegen und Brechen? Woher soll ein Assembler denn> wissen, wie du ein Symbol verwenden willst? Ob ein LMP folgt oder ob's> ein IJMP wird?
Er kanns natürlich nicht immer wissen. Nur sollten die Annahmen nicht so
gemacht werden, daß sie ausgerechnet für den mit Abstand seltensten Fall
passen.
Uhu Uhuhu schrieb:> Johann L. schrieb:>> Was meinst du mir "Biegen und Brechen? Woher soll ein Assembler denn>> wissen, wie du ein Symbol verwenden willst? Ob ein LMP folgt oder ob's>> ein IJMP wird?>> Er kanns natürlich nicht immer wissen. Nur sollten die Annahmen nicht so> gemacht werden, daß sie ausgerechnet für den mit Abstand seltensten Fall> passen.
Na schreibs auf die TODO-Liste für deinen nächsten binutils-Port ;-)
BTW: Ein LPM ist in Allerweltscode wesentlich häufiger als ein ICALL.
spess53 schrieb:>>>Was meinst du mir "Biegen und Brechen? Woher soll ein Assembler denn>>wissen, wie du ein Symbol verwenden willst? Ob ein LMP folgt oder ob's>>ein IJMP wird?>> Die Assembler des AVR-Studios gehen generell bei einem Label von einer> Wordadresse aus. Bei dem Sonderfall 'lpm', bei dem auf eine Byteadresse> zugegriffen wird, muss man die Adresse explizit verdoppeln. Irgendwie> logisch.
Versteh ich net.
Wenn foo an Byte-Adresse 1 steht und diese wird als Wort-Adresse
geladen, steht dann 1/2 im Register und dann muss man das mit 2
multiplizieren um auf die Byte-Adresse von 1 zu kommen?
spess53 schrieb:> Die Assembler des AVR-Studios gehen generell bei einem Label von einer> Wordadresse aus. Bei dem Sonderfall 'lpm', bei dem auf eine Byteadresse> zugegriffen wird, muss man die Adresse explizit verdoppeln. Irgendwie> logisch.
Nein, darauf bezogen nicht. Denn lpm nennt sich load program memory und
liest Daten Byte-weise, für sich gesehen ist dafür eine Byte-weise
Adressierung natürlicher.
Ein Label grundsätzlich in ASM als Codelabel anzunehmen, dürfte darauf
zurückzuführen sein, daß in ASM sehr viel häufiger Programmlabels
benötigt werden, etwas das in C oder anderen Hochsprachen nicht mehr der
Fall ist.
Johann L. schrieb:> BTW: Ein LPM ist in Allerweltscode wesentlich häufiger als ein ICALL.
Nur klebt für den asm-Programmierer an LPM ein rotes Fähnchen: "Achtung
hier funktionierts anders, als bei Codeadressen".
Aber einerlei. Der gas ist nicht in erster Linie für handgestrickte
Programme gemacht. Entsprechend ist er auch ein ziemlich tumbes
Exemplar, gemessen an dem, was im Assemblerzeitalter so üblich war.
Hi
>Versteh ich net.>Wenn foo an Byte-Adresse 1 steht und diese wird als Wort-Adresse>geladen, steht dann 1/2 im Register und dann muss man das mit 2>multiplizieren um auf die Byte-Adresse zu kommen?
Ein
foo: .db 0xYZ
kann nur an einer Word-Adresse stehen.
foo: .db 0xYZ
fooo: .db 0xYZ
Sind jeweils eine Wordadresse. Das '.db 0xYZ' wird mit 0x00 zu einem
Word aufgefüllt.
MfG Spess
MWS schrieb:> Ein Label grundsätzlich in ASM als Codelabel anzunehmen, dürfte darauf> zurückzuführen sein, daß in ASM sehr viel häufiger Programmlabels> benötigt werden, etwas das in C oder anderen Hochsprachen nicht mehr der> Fall ist.
Das kann ich nicht bestätigen. Ich habe schon etliche Flugstunden mit
diversen Assemblern auf dem Buckel und meine Programme hatten immer
deutlich weniger Labels, als von einem Compiler erzeugeter äquivalenter
ASM-Output.
Trotzdem würde ich intuitiv davon ausgehen, daß Programm-Memory-Adressen
beim AVR Wortadressen sind, weil in der Maschine den Code eben wortweise
organisiert ist.
"Gute" Programmiersprachen zeichnen sich dadurch aus, daß sie der
Intuition folgen - ein schönes Beispiel dafür ist Ruby bzw Ruby on
Rails.
Aber in Anbetracht der Tatsache, daß Assembler weniger eine
Programmiersprache, als ein organisiertes Gestammel ist, ist dieser
Maßstab vielleicht nicht angemessen...
spess53 schrieb:> Hi>>>Versteh ich net.>>>Wenn foo an Byte-Adresse 1 steht und diese wird als Wort-Adresse>>geladen, steht dann 1/2 im Register und dann muss man das mit 2>>multiplizieren um auf die Byte-Adresse zu kommen?>> Ein>> foo: .db 0xYZ>> kann nur an einer Word-Adresse stehen.>> foo: .db 0xYZ> fooo: .db 0xYZ>> Sind jeweils eine Wordadresse. Das '.db 0xYZ' wird mit 0x00 zu einem> Word aufgefüllt.
Oje.. verstehe. .db ist immer Word-aligned und man schüttet das Kind mit
dem Base aus. So verschwendet man doch wertvollen Flash-Speicher, den
man gerade duch asm-Programmierung sparen will!
Bei den avr-Tools geht maximal 1 Byte verloren und zwar durch das
Alignment von .text; die Daten in .progmem liegen dicht.
p.s.: Ok, Atmel als Hersteller ist natürlich daran interessiert, größere
µCs zu verkaufen. Von daher wär's noch besser, alle Labels auf 32 Bits
zu alignen, he he
Uhu Uhuhu schrieb:> Das kann ich nicht bestätigen. Ich habe schon etliche Flugstunden mit> diversen Assemblern auf dem Buckel und meine Programme hatten immer> deutlich weniger Labels, als von einem Compiler erzeugeter äquivalenter> ASM-Output.
Das hab' ich damit nicht gesagt, es ging darum wieviele Label der
Programmierer zu schreiben hat und wie tolerant der dann gegenüber einer
Byte-Adressierung wäre, wenn er laufend Word-Adressen braucht, bzw.
damit rechnet. In C fällt das weg, da gibt's nicht viele Labels, die
internen interessieren nicht, da für den User nicht sichtbar.
Hi
>Oje.. verstehe. .db ist immer Word-aligned und man schüttet das Kind mit>dem Base aus. So verschwendet man doch wertvollen Flash-Speicher, den>man gerade duch asm-Programmierung sparen will!
Kann es sein, das du etwas missverstehst?
foo: .db 0x00 belegt 1 Word
foo: .db 0x00,0x00 belegt 1 Word
foo: .db 0x00,0x00,0x00 belegt 2 Word
foo: .db 0x00,0x00,0x00,0x00 belegt 2 Word
MfG Spess
Intuition ist eben subjektiv und zum Glück nicht in irgendner ISO-Norm
festgelegt ;-)
MWS schrieb:> Uhu Uhuhu schrieb:>> Das kann ich nicht bestätigen. Ich habe schon etliche Flugstunden mit>> diversen Assemblern auf dem Buckel und meine Programme hatten immer>> deutlich weniger Labels, als von einem Compiler erzeugeter äquivalenter>> ASM-Output.>> Das hab' ich damit nicht gesagt, es ging darum wieviele Label der> Programmierer zu schreiben hat und wie tolerant der dann gegenüber einer> Byte-Adressierung wäre, wenn er laufend Word-Adressen braucht, bzw.> damit rechnet. In C fällt das weg, da gibt's nicht viele Labels, die> internen interessieren nicht, da für den User nicht sichtbar.
Es gibt zwar viele Labels, aber nur wenige davon werden in Register
geladen:
Der häufigste Fall ist Laden der Adresse eines Objekts im static
storage; zweithäufigster sind Funktionspointer und der Rest ist schon
ferner liefen.
spess53 schrieb:> Hi>>>Oje.. verstehe. .db ist immer Word-aligned und man schüttet das Kind mit>>dem Base aus. So verschwendet man doch wertvollen Flash-Speicher, den>>man gerade duch asm-Programmierung sparen will!>> Kann es sein, das du etwas missverstehst?
Ich denke nein. Wenn man 10 Objekte à 3 Byte anlegen will muss man 5
Bytes verschwenden. Zumindest dann wenn jeded Objekt nen eigenen Label
haben soll und man nicht alles zusammenklatscht, was nicht wirklich
wartbar wäre.
Johann L. schrieb:> Es gibt zwar viele Labels, aber nur wenige davon werden in Register> geladen:> Der häufigste Fall ist Laden der Adresse eines Objekts im static> storage; zweithäufigster sind Funktionspointer und der Rest ist schon> ferner liefen.
Dennoch, würde ich ausschließlich ASM schreiben, wäre ich sicher
Word-orientiert, mit Wissen um die Ausnahmen eben. Mit einer
Hochsprache, die mich vom Maschinenraum ein wenig fernhält, hätte ich
keinen Grund mehr in Word zu denken. Damit sind dann die Compilerbauer
frei darin was als Standard zu gelten hat.
spess53 schrieb:> Dort ist ein Label> eine Wordadresse. Das der C-Assembler das anders sieht, finde ich> irgendwie krank.
Nö, krank ist der Atmel-Assembler, denn er ist weit und breit der
einzige, der so einen Quark macht. Alle anderen, egal ob sie
eine 8-, 16-, 32- oder 64-bit-Architektur benutzen, nehmen die
Adressen byteweise. Nur der Atmel-Assembler (und das Datenblatt)
machen da eine Ausnahme. Natürlich keine Ausnahme ohne Ausnahme:
der Flash ist keinesfalls zwingend in 16-bit-Worten adressiert,
sondern wenn man ihn per LPM lesen will, ist er sehr wohl byteweise
adressiert. Will man ihn mit SPM beschreiben, dann geht das aber
wieder wortweise. ==:-)
AVRASM bildet das ab, was im Hardware-Datenblatt steht. Und das sollte
jeder vernünftige Assembler tun - auch der Inline Assembler eines
Hochsprachen-Compilers.
Johann L. schrieb:> Ich denke nein. Wenn man 10 Objekte à 3 Byte anlegen will muss man 5> Bytes verschwenden. Zumindest dann wenn jeded Objekt nen eigenen Label> haben soll und man nicht alles zusammenklatscht, was nicht wirklich> wartbar wäre.
Jörg Wunsch schrieb:> Nö, krank ist der Atmel-Assembler, denn er ist weit und breit der> einzige, der so einen Quark macht.
Bitte keine Glaubenskriege ;-)
Die At*-Controller sind dermaßen von (preismindernden) Kompromissen
geprägt, daß sie aus menschlicher Sicht echte Contergan-Maschinen sind.
Da das menschliche Denken etwas anderen Regeln folgt, finde ich den
Ansatz der Atmel-ASM schon in Ordnung, denn er biegt das Bild des
Maschinchens etwas mehr in Richtung der Denkweise eines
ASM-Programmierers.
Solchen Scheiß muß man bei richtig schönen von-Neumann-Maschinen mit
genügend breiten Bussen und reichlich Speicher natürlich nicht machen.
Aber auch dort gibt es zuweilen gewisse Einschränkungen, wie z.B. die,
daß Maschinenbefehle immer auf geraden Adressen liegen müssen - so z.B.
beim MSP430, der ja eigentlich eine stark abgespeckte PDP-11 ist, die
diesen kleinen Schönheitsfehler auch hatte.
Ist halt alles eine Frage des Geldes...
Uhu Uhuhu schrieb:> Aber auch dort gibt es zuweilen gewisse Einschränkungen, wie z.B. die,> daß Maschinenbefehle immer auf geraden Adressen liegen müssen - so z.B.> beim MSP430
Nicht nur dort, das ist bei jeder x-beliebigen RISC-CPU gang und
gäbe, trotzdem haben die Assembler immer byteweise gearbeitet.
Man muss eben einfach wissen, dass der Code für eine UltraSPARC
auf durch 4 teilbaren Adressen liegen muss, oder für einen ARM im
Thumb-Mode auf durch 2 teilbaren.
Den GNU-Assembler hat halt einfach niemand auf die Atmel-Denkweise
verbogen, warum auch? Am Ende hätte man nur für diese Verrenkung
wohl gleich noch den Compiler zusätzlich ändern müssen, denn
schließlich ist der gas in erster Linie das Arbeitstier dafür, den
vom GCC generierten Code in Objektcode zu transferieren.
HI
>Den GNU-Assembler hat halt einfach niemand auf die Atmel-Denkweise>verbogen, warum auch?
Dann wäre der ganze Thread unnötig gewesen. Ändert auch nichts an meiner
Meinung, das die Assembler des AVR-Studios besser an die Arbeitsweise
der AVRs angepasst sind als dieser C-Asssembler.
MfG Spess
Jörg Wunsch schrieb:> Den GNU-Assembler hat halt einfach niemand auf die Atmel-Denkweise> verbogen, warum auch? Am Ende hätte man nur für diese Verrenkung> wohl gleich noch den Compiler zusätzlich ändern müssen, denn> schließlich ist der gas in erster Linie das Arbeitstier dafür, den> vom GCC generierten Code in Objektcode zu transferieren.
Da hast du ja durchaus recht. Es ist eben wie mit geerbten Klamotten,
Hose zu kurz, aber am Bauch so breit, daß man zweimal reinpaßt, das Hemd
stockfleckig und der Mottenpulvergeruch ist nach dem dritten mal waschen
immer noch zu riechen.
Der gas ist einfach ein Assembler, der in erster Linie für den gcc
gemacht wurde.
Aber vielleicht solltet ihr einfach in der Beschreibung der AVR-binutils
auf den Unterschied zum AVR-ASM hinweisen...
spess53 schrieb:> Dann wäre der ganze Thread unnötig gewesen.
Ich fand ihn sehr lehrreich...
Uhu Uhuhu schrieb:> Aber vielleicht solltet ihr einfach in der Beschreibung der AVR-binutils> auf den Unterschied zum AVR-ASM hinweisen...
??? Eher umgekehrt: Die Binutils gibt's für mehr Architektiren, als es
für AVR Derivate gibt ;-)
Und die Binutils sind wesentlich weiter verbreitet, älter und auch
bekannter.
Was im binutils-Manual nicht so toll ist, sind die Beschreibungen wie zB
pm_lo8 wo es heisst "... This modifier useful for addressing data or
code from Flash/Program memory."
Daß der Atmel-Anstz nicht so prockelnd ist sieht man schon an der
Splatzverschwendung, die dies zwangsläufig bedeutet.
Zudem sind Adressen in C/C++ und Objektgrößen immer Byte-Adressen,
egal welches Alignment eine Architektur für Daten oder Code fordert.
Johann L. schrieb:> Zudem sind Adressen in C/C++ und Objektgrößen immer Byte-Adressen,
Hier gehts um ASM-Programmierung - nicht um C/C++.
> Und die Binutils sind wesentlich weiter verbreitet, älter und auch> bekannter.
Klar. Nur ist das nicht eine Universal-Version für alle Architekturen,
sondern eine auf AVRs angepaßte, der könnte man ja immerhin ein paar
Sonderbemerkungen mitgeben.
Aber vielleicht könnte man das auch in einem Artikel hier unterbringen.
Ist zwar für Leute nutzlos, die hier nicht verkehren, oder kein Deutsch
verstehen, aber besser als nichts.
Ich werde einen Hinweis in
http://www.mikrocontroller.net/articles/AVR_Assembler_-_Unterprogramme
einbauen.
Uhu Uhuhu schrieb:> Aber vielleicht solltet ihr einfach in der Beschreibung der AVR-binutils> auf den Unterschied zum AVR-ASM hinweisen...
Die AVR-binutils haben keine wirklich eigene Beschreibung. Es gibt
die Dokumentation der GNU binutils, und dort dann einen Abschnitt,
der die Ergänzungen für das Target "avr" beschreibt (da stehen
beispielsweise Dinge wie der pm-Operator drin). Alternativ könnte
man es sicher auch in der avr-libc-Doku irgendwo mit unterbringen.
Biete doch einfach mal einem der Projekte (GNU binutils oder avr-libc)
einen Patch an, der die Dokumentation so ergänzt, dass es an einer
Stelle dann auftaucht, wo auch du es wohl gelesen hättest. Das ist
nämlich immer das Hauptproblem bei der Doku, welches für einen
Entwickler (der ja voll in den Details drinsteckt) immer schwer
zu beurteilen ist: Wo würde der Nutzer nach dieser Information
suchen?
Johann L. schrieb:> Zudem sind Adressen in C/C++ und Objektgrößen immer Byte-Adressen,> egal welches Alignment eine Architektur für Daten oder Code fordert.
Genau genommen sind es Adressen in Vielfachen von sizeof(char) (das
per definitionem ja gleich 1 ist). Auf den meisten Architekturen
ist ein "char" auch 8 Bits, aber es gibt wohl prominente Ausnahmen.
Jörg Wunsch schrieb:> Die AVR-binutils haben keine wirklich eigene Beschreibung.
Sie sind aber in einem eigenen Paket enthalten und dem kann man eine
AVR-README oder irgendwas in der Art mitgeben.
Es soll Pakete geben, bei denen so verfahren wird ;-)
Hi
Der entsprechende Code für die AVR-Assembler ist
ldi r30, low(label)
ldi r31, high(label)
und
ldi r30, low(data_label<<1)
ldi r31, high(data_label<<1)
MfG Spess
Takes a program-memory (ROM) address, and converts it into a RAM address.
3
This implies a division by 2 as the AVR handles ROM addresses as 16-bit
4
words (e.g. in an IJMP or ICALL instruction), and can also handle
5
relocatable symbols on the right-hand side.
Im Gegensatz zur binutils-Doku steht hier zwar klipp und klar, dass das
eine Division durch 2 macht, aber der erste Satz ist doch irgendwie
daneben, um nicht zu sagen falsch. Oder ich verstehe ihn nicht richtig,
dann ist er zumindest missverständlich. ;-)
Hi
>Ich dachte, es sind Wortadressen?
Ja. Um aus einer Wordadresse eine Byteadresse zu machen muss man sie x2
nehmen oder wie hier ein Linksshift machen.
MfG Spess
Stefan Ernst schrieb:>> Alternativ könnte>> man es sicher auch in der avr-libc-Doku irgendwo mit unterbringen.>> Ist dort schon enthalten:
Daher wollte ich ja auch von den Nutzern (also Uhu in diesem Falle)
einen Vorschlag haben, wohin man es denn schreiben sollte, damit er
das bei der entsprechenden Suche sofort gefunden hätte.
> Im Gegensatz zur binutils-Doku steht hier zwar klipp und klar, dass das> eine Division durch 2 macht, aber der erste Satz ist doch irgendwie> daneben, um nicht zu sagen falsch. Oder ich verstehe ihn nicht richtig,> dann ist er zumindest missverständlich. ;-)
Dann schlag' (bitte per Bugreport) etwas besseres vor. Der Satz
könnte gut und gern von mir stammen, und etwas besseres ist mir
einfach nicht eingefallen.
Hi
>Sieh dir mal>http://www.mikrocontroller.net/articles/AVR_Assemb...>an, ob das so OK ist.
Doch noch ein Fehler: Es gibt den Befehl 'lpm', ohne Registerangabe mit
r0 als Ziel. Bei einer Registerangabe lautet der Befehl 'lpm Rxy,Z',
wobei es außer Z auch noch -Z (Predecrement) und Z+ (Postincrement)
möglich sind. Sollte (?) beim GCC-Assembler auch so sein.
MfG Spess
Jörg Wunsch schrieb:> Daher wollte ich ja auch von den Nutzern (also Uhu in diesem Falle)> einen Vorschlag haben, wohin man es denn schreiben sollte, damit er> das bei der entsprechenden Suche sofort gefunden hätte.
Hier ist er: Beitrag "Re: AVR-ASM: Simulierter call"
Ich hab die Erkenntnisse aus diesem Thread jetzt man fürs erste hier
drangeflickt:
http://www.mikrocontroller.net/articles/AVR_Assembler_-_Unterprogramme
Sicherlich gibts noch weitere Unterschiede, daraus könnte man dann einen
eigenen Artikel machen: "AVR-Assembler: Unterschiede" oder so ähnlich.
Nur eine Idee, wie man diese Unterschiede herausbekommen kann, habe ich
noch nicht - die meisten werden nur einen der Kandidaten benutzen.
spess53 schrieb:
> Doch noch ein Fehler:
Danke, ist gefixt.
> Sollte (?) beim GCC-Assembler auch so sein
Ja, das ist gleich. Deswegen hab ichs weggelassen - das wäre ein anderes
Thema.
Jörg Wunsch schrieb:> Der Satz> könnte gut und gern von mir stammen
Das mag ich gar nicht glauben, denn in meinen Augen ist die Aussage des
Satzes schlicht falsch. Was hat das Ganze mit dem RAM zu tun? Und wenn
man "RAM address" als Synonym für Byte-orientierte Adresse annimmt, dann
ist die Aussage doch genau verkehrt herum.
Jörg Wunsch schrieb:> Dann schlag' (bitte per Bugreport) etwas besseres vor.
Wenn ich morgen Abend wieder an meinem heimischen Rechner sitze, werde
ich mal einen Vorschlag einreichen (per Bugreport). ;-)
Der Vorschlag wird wohl auf so was hinauslaufen:
Takes a usual address, and converts it into a program-memory (ROM)
address.
In der avr-libc steht was von
lo8(pm(·)) was afaik was anderes ist als pm_lo8(·)
ZB wenn man den Wert nicht einem Register zuweisen will sondern im
Speicher anblegen, zB als Initializer.
Da sind beide Methoden nicht gleichmächtig.
Auch die wäre ein Beispiel interessand, etwa
.db LO(label >> 1), HI(label >> 1)
oder wie auch immer die Syntax bei Atmel/GNU aussieht.
Johann L. schrieb:> In der avr-libc steht was von>> lo8(pm(·)) was afaik was anderes ist als pm_lo8(·)>> ZB wenn man den Wert nicht einem Register zuweisen will sondern im> Speicher anblegen, zB als Initializer.
Sorry, aber das verstehe ich jetzt nicht. Das Low-Byte einer
Word-Adresse bleibt doch gleich, egal ob ich es nun direkt in ein
Register lade, oder im Speicher ablege. Und es ist auch in beiden Fällen
ein relocatable Symbol. Ich hatte bisher pm_lo8(·) nur als etwas
bequemere Variante von lo8(pm(·)) gesehen.
Versuch mach kluch...
Zumindest beim GNU-Assembler kann man diese Modifier nicht beliebig
kaskadieren oder mir Arithmetik mischen.
Und gs(·) findet sich in der Doku überhaupt nicht :-(
Uhu Uhuhu schrieb:> Johann L. schrieb:>> .db LO(label >> 1), HI(label >> 1)>> Der gas läßt ein label >> 1 garnicht zu.
Yep, weil das Ganze durch einen entsprechenden relocation record im
Objektcode abbildbar sein muss, damit der Linker es dann auflösen
kann.
Das ist letztlich der ganze Grund für den pm-Operator.
Johann L. schrieb:> Und gs(·) findet sich in der Doku überhaupt nicht :-(
Ja, das hat Björn Haase wohl vergessen. :-/
Stefan Ernst schrieb:> Takes a usual address, and converts it into a program-memory (ROM)> address.
Nö, das passt nicht. Der label hinter dem pm-Operator muss sich auf
ein Flash-ROM-Segment beziehen, es ist also eine (byteadressierte)
ROM-Adresse. Die wird vom Operator in eine Wortadresse gewandelt,
wobei die eigentliche Operation (meines Wissens) dann erst vom Linker
ausgeführt wird.
Jörg Wunsch schrieb:> Die wird vom Operator in eine Wortadresse gewandelt,> wobei die eigentliche Operation (meines Wissens) dann erst vom Linker> ausgeführt wird.
Zwangsläufig muß das der Linker machen - sonst könnte man auch
verschiebliche Symbole mit Shift und Arithmetik traktieren.
Da stellt sich mir gleich (wieder) die Frage: Ist der AVR-ASM eigentlich
Objektkompatibel zum gcc?
Das shift auf Labels läß vermuten, daß nicht.
Uhu Uhuhu schrieb:> Ist der AVR-ASM eigentlich> Objektkompatibel zum gcc?
Zwangsläufig, denn alles, was der GCC tut, schiebt er anschließend
dem gas unter. ;-)
Jörg Wunsch schrieb:> Der label hinter dem pm-Operator muss sich auf> ein Flash-ROM-Segment beziehen
Ok, hatte jetzt nicht erwartet, dass es eine solche Beschränkung bei der
Ausgangsadresse tatsächlich konkret gibt.
Ich dachte ursprünglich an so was Simples wie "converts a byte oriented
ROM address into a word oriented one". Aber das harmoniert ja überhaupt
nicht mit dem dann folgenden Satz, so dass mehr geändert werden müsste.
;-)
Jörg Wunsch schrieb:> Uhu Uhuhu schrieb:>> Ist der AVR-ASM eigentlich>> Objektkompatibel zum gcc?>> Zwangsläufig, denn alles, was der GCC tut, schiebt er anschließend> dem gas unter. ;-)
Ich denke, er meinte mit AVR-ASM den Atmel-Assembler. ;-)
Aber diese Frage stellt sich doch schon deshalb gar nicht, weil der
Atmel-Assembler gar keinen Objekt-Code produziert oder verarbeiten kann.
Der wird mit einer Source-Datei gefüttert und produziert daraus direkt
das komplette Binary. Nix mit Objekten, die gelinkt werden. Oder irre
ich da?
Stefan Ernst schrieb:> Ich denke, er meinte mit AVR-ASM den Atmel-Assembler. ;-)
Ja, das hatte ich mist-verstanden.
> Nix mit Objekten, die gelinkt werden. Oder irre> ich da?
Nö, ich glaube, du irrst da nicht.
Jörg Wunsch schrieb:> Uhu Uhuhu schrieb:>> Ist der AVR-ASM eigentlich>> Objektkompatibel zum gcc?>> Zwangsläufig, denn alles, was der GCC tut, schiebt er anschließend> dem gas unter. ;-)
Ich meinte den von Amel, nicht den gas...
Stefan Ernst schrieb:> Der wird mit einer Source-Datei gefüttert und produziert daraus direkt> das komplette Binary.
OK, das erklärt, warum man Labels schiften kann - die sind nicht
verschieblich, sonden dem ASM schon bekannt.