AVR-ASM: Simulierter call

OP #2317064
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?
#2317082
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
OP #2317161
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
OP #2317187
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...
Gast #2317245
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.
OP #2317246
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...
Gast #2317271
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
Gast #2317272
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 ?
OP #2317280
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?
OP #2317288
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.
OP #2317322
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.
#2317345
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
Persönliche Seite #2317348
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.
OP #2317355
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'
OP #2317376
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?
Gast #2317387
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 ;-)
Gast #2317389
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
OP #2317406
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...
OP #2317417
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?
Gast #2317418
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
Persönliche Seite #2317451
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
OP #2317482
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...
Persönliche Seite #2317494
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. :-)
Gast #2317500
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
Persönliche Seite #2317512
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.
Persönliche Seite #2317517
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?
Gast #2317519
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.
OP #2317520
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.
Gast #2317523
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
OP #2317524
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...
Persönliche Seite #2317526
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
Gast #2317529
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.
Gast #2317534
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
Persönliche Seite #2317538
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.
Persönliche Seite #2317540
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.
Gast #2317543
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.
Moderator Persönliche Seite #2317788
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.  ==:-)
OP #2317821
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...
Moderator Persönliche Seite #2317859
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.
Gast #2317878
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
OP #2317897
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...
Persönliche Seite #2317951
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.
OP #2317995
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.
Moderator Persönliche Seite #2317997
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?
Moderator Persönliche Seite #2318004
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.
#2318051
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. ;-)
Moderator Persönliche Seite #2318188
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.
OP #2318206
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.
#2318589
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.
Persönliche Seite #2318614
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.
#2318634
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.
Moderator Persönliche Seite #2318697
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.
OP #2318709
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.
#2318781
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. 
;-)
#2318791
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?
OP #2318830
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren