Forum: Mikrocontroller und Digitale Elektronik AVR-ASM: Simulierter call


von Uhu U. (uhu)


Lesenswert?

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?

von Floh (Gast)


Lesenswert?

Wirst denke ich erstmal 2 Byte popen müssen ,damit die neue ret-Adresse 
an der richtigen Stelle steht.

von spess53 (Gast)


Lesenswert?

Hi

Bei mir funktioniert das. Stackpointer richtig initialisiert?

MfG Spess

von Thomas T. (knibbel)


Lesenswert?

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

von spess53 (Gast)


Lesenswert?

Hi

>Hoffe ich habe ins Schwarze getroffen ...

Nein. 'retaddr' ist eine Wordadresse. Und die muss auf den Stack.

MfG Spess

von Thomas T. (knibbel)


Lesenswert?

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

von Klaus2m5 (Gast)


Lesenswert?

Warum so kompliziert?

      rcall  funktion
      rjmp   retadr
...

retaddr:
      ...

funktion:
      <tuwas>
      ret

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

@Klaus2m5: Pah, das beraubt die Quelle jedglicher Magie und man sieht 
sofort, was gemeint ist. Eines wahren Assembler-Programmierers unwürdig!

von Uhu U. (uhu)


Lesenswert?

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:
1
.macro  ldz, addr
2
  ldi  r30, lo8(\addr)
3
  ldi  r31, hi8(\addr)
4
.endm
5
6
7
GetTableEntry:
8
  movw  r18,r24
9
  ldz   ScheduleTable + ((ScheduleEntries - 1) * SE_size)
10
  ldi   r24,lo8(ScheduleEntries - 1)
11
12
.L1:
13
  ld    r20,Z
14
  ldd   r21,Z+1
15
  cp    r20,r18
16
  cpc   r21,r19
17
  breq  .L2
18
19
  sbiw  r30, SE_size
20
  subi  r24, 1
21
  brpl  .L1
22
23
.L2:
24
  ret
25
26
pushregs:
27
  push  r0
28
  in    r0, __SREG__
29
  cli
30
  push  r12
31
  push  r13
32
  push  r14
33
  push  r15
34
  push  r28
35
  push  r29
36
37
  movw  r12, r24          ; delay
38
  movw  r14, r22          ; reload
39
  movw  r24, r20          ; hdlr
40
41
  push  r30
42
  push  r31
43
  rjmp   GetTableEntry
44
45
Schedule:
46
  ; r24, r25:    delay
47
  ; r22, r23:    reload
48
  ; r20, r21:    hdlr
49
  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

von Klaus2m5 (Gast)


Lesenswert?

Also funktioniert es nicht, wenn Du das Makro benutzt.

von Uhu U. (uhu)


Lesenswert?

Am Macro liegts nicht - hab ich schon probiert.

Allerdings ist noch ein weiterer Macro im Spiel, der aber nur Direktiven 
enthält:
1
.macro  FUNCTION  name
2
  .section  .text.\name,"ax",@progbits
3
  .type     \name, @function
4
  .global    \name
5
\name:
6
.endm

Die Funktionsköpfe sehen dann so aus:
1
FUNCTION GetTableEntry
2
...
3
FUNCTION Schedule
4
...
5
FUNCTION Reschedule

Die sollten aber keinen Einfluß auf den erzeugten Code haben.

Das wars dann aber auch...

von MWS (Gast)


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

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...

von Uhu U. (uhu)


Lesenswert?

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.

von spess53 (Gast)


Lesenswert?

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

von Uhu U. (uhu)


Lesenswert?

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.

von spess53 (Gast)


Lesenswert?

Hi

Nachtrag: Statt dieses Stackgefummels kannst du auch 'ijmp' verwenden:
1
      ldi    r30, lo8(retaddr)
2
      ldi    r31, hi8(retaddr)
3
      rjmp   funktion
4
5
...
6
7
retaddr:
8
      ...
9
10
funktion:
11
      <tuwas>
12
      ijump

das ist sogar noch kürzer und auch sauberer programmiert.

MfG Spess

von MWS (Gast)


Lesenswert?

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 ?

von Uhu U. (uhu)


Lesenswert?

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?

von Uhu U. (uhu)


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

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.

von Simon K. (simon) Benutzerseite


Lesenswert?

Wenn du offen für neue Ansätze bist, würde ich sagen: Lass das Gefummel 
und machs "richtig".

von MWS (Gast)


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von Simon K. (simon) Benutzerseite


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

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'

von Uhu U. (uhu)


Lesenswert?

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?

von MWS (Gast)


Lesenswert?

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 ;-)

von spess53 (Gast)


Lesenswert?

>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

von spess53 (Gast)


Lesenswert?

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

von Uhu U. (uhu)


Lesenswert?

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...

von MWS (Gast)


Lesenswert?

1
.macro  ldz, addr
2
  ldi  r30, lo8(\addr)
3
  ldi  r31, hi8(\addr)
4
  lsr  r31
5
  ror  r30
6
.endm

von Uhu U. (uhu)


Lesenswert?

MWS schrieb:
>
1
> .macro  ldz, addr
2
>   ldi  r30, lo8(\addr)
3
>   ldi  r31, hi8(\addr)
4
>   lsr  r31
5
>   ror  r30
6
> .endm
7
>

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...

von Stefan E. (sternst)


Lesenswert?

1
  ldi  r30, pm_lo8(\addr)
2
  ldi  r31, pm_hi8(\addr)

von Uhu U. (uhu)


Lesenswert?

So, jetzt funzts.

Die Shift-Operation brauch in dem Fall auch nur ein einziges mal codiert 
werden: bevor das Z-Register gepusht wird, also etwa so:
1
pushregs:
2
  push  r0
3
  in    r0, __SREG__
4
  cli
5
  push  r12
6
  push  r13
7
  push  r14
8
  push  r15
9
  push  r28
10
  push  r29
11
12
  movw  r12, r24          ; delay
13
  movw  r14, r22          ; reload
14
  movw  r24, r20          ; hdlr
15
16
  lsr  r31               ; ***********************
17
  ror  r30               ; ***********************
18
  push  r30
19
  push  r31
20
  rjmp   GetTableEntry


spess53 schrieb:
> Bei mir funktioniert das.

Wie hast du das denn geschafft?

von MWS (Gast)


Lesenswert?

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:
1
  ldz  .S1
2
  b2:  e2 ed         ldi  r30, 0xD2  ; 210
3
  b4:  f0 e0         ldi  r31, 0x00  ; 0
4
  b6:  f6 95         lsr  r31

von Uhu U. (uhu)


Lesenswert?

Stefan Ernst schrieb:
>
1
>   ldi  r30, pm_lo8(\addr)
2
>   ldi  r31, pm_hi8(\addr)
3
>

Super. Wo steht denn das?

von MWS (Gast)


Lesenswert?

Stefan Ernst schrieb:
> ldi  r30, pm_lo8(\addr)
> ldi  r31, pm_hi8(\addr)

Sehr gut !

von Uhu U. (uhu)


Lesenswert?

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...

von spess53 (Gast)


Lesenswert?

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

von Uhu U. (uhu)


Lesenswert?

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...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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:
1
>>   ldi  r30, pm_lo8(\addr)
2
>>   ldi  r31, pm_hi8(\addr)
>
> Super. Wo steht denn das?

Dort wo man es suchen würde: Im binutils-Manual:

http://sourceware.org/binutils/docs-2.21/as/AVR_002dModifiers.html#AVR_002dModifiers

von Stefan E. (sternst)


Lesenswert?

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).

von spess53 (Gast)


Lesenswert?

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

von Uhu U. (uhu)


Lesenswert?

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...

von MWS (Gast)


Lesenswert?

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.

von spess53 (Gast)


Lesenswert?

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

von Uhu U. (uhu)


Lesenswert?

Für alles gibts einen Hack. Nur übersichtlicher wirds dadurch nicht.

Aber wenn man immer nur in C programmiert, ist das auch schnuppe...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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. :-)

von MWS (Gast)


Lesenswert?

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

von spess53 (Gast)


Lesenswert?

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

von Uhu U. (uhu)


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

MWS schrieb:
> Wie Du erkennen konntest, schadet auch ein Blick abseits vom eigenen Weg
> nicht ;D

Das war ja mein Optimierungsansatz auch.

von Charly B. (charly)


Lesenswert?

cli
      ldi    r30, low(retaddr)
      ldi    r31, high(retaddr)
      push   r30
      push   r31
cli
cli

      rjmp   funktion
      rjmp   funktion



retaddr:
      nop
      cli

funktion:
      nop
      cli
      cli
      ret


funktioniert im Bascom Simulator bestens

ps. die cli & nop sin nur "fuellmaterial" ;)


vlG
Charly

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

@Charly B.
Das ist aber mit Sicherheit nicht der gas aus den gcc-binutilities.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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?

von MWS (Gast)


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

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.

von spess53 (Gast)


Lesenswert?

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

von Uhu U. (uhu)


Lesenswert?

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...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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

von MWS (Gast)


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

Ich denke, der springende Punkt ist wirklich die Intuition. Wenn die und 
das Verhalten einer Maschine nicht zusammenpassen, dann machts keinen 
Spaß.

von spess53 (Gast)


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von MWS (Gast)


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

Insgesamt hat die Optimierung 220 Byte Programmspeicher gebracht.

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


Lesenswert?

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.  ==:-)

von Klaus2m5 (Gast)


Lesenswert?

AVRASM bildet das ab, was im Hardware-Datenblatt steht. Und das sollte 
jeder vernünftige Assembler tun - auch der Inline Assembler eines 
Hochsprachen-Compilers.

von Ralf G. (ralg)


Lesenswert?

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.
1
X: .db 1, 2, 3  ; + Füllbyte
Also bei jedem Objekt ein Byte zusätzlich.

von Uhu U. (uhu)


Lesenswert?

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...

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


Lesenswert?

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.

von spess53 (Gast)


Lesenswert?

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

von Uhu U. (uhu)


Lesenswert?

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...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

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.

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


Lesenswert?

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?

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


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

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 ;-)

von Uhu U. (uhu)


Lesenswert?

@Spess:
Was muß man denn beim AVR-ASM machen, um eine mit LPM benutzbare Adresse 
zu bekommen?

Geht etwa sowas:
1
       ldi     r30, 2*lo8(label)

Du kannst die korrekte Schreibweise auch gleich hier einflicken: 
http://www.mikrocontroller.net/articles/AVR_Assembler_-_Unterprogramme

von spess53 (Gast)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

Jörg Wunsch schrieb:
> Alternativ könnte
> man es sicher auch in der avr-libc-Doku irgendwo mit unterbringen.

Ist dort schon enthalten:
http://www.nongnu.org/avr-libc/user-manual/assembler.html
1
pm
2
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. ;-)

von spess53 (Gast)


Lesenswert?

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

von Uhu U. (uhu)


Lesenswert?

Danke, ich hatte den Irrtum bald bemerkt.

Sieh dir mal 
http://www.mikrocontroller.net/articles/AVR_Assembler_-_Unterprogramme 
an, ob das so OK ist.

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


Lesenswert?

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.

von spess53 (Gast)


Lesenswert?

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

von Uhu U. (uhu)


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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 :-(

von Uhu U. (uhu)


Lesenswert?

Johann L. schrieb:
> .db LO(label >> 1), HI(label >> 1)

Der gas läßt ein label >> 1 garnicht zu.

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


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

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.

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


Lesenswert?

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. ;-)

von Stefan E. (sternst)


Lesenswert?

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. 
;-)

von Stefan E. (sternst)


Lesenswert?

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?

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


Lesenswert?

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.

von Uhu U. (uhu)


Lesenswert?

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.

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.