Forum: Compiler & IDEs direkter Zugriff auf Low/High Byte von 16bit-Werten


von Karl F. (kafido)


Lesenswert?

Hallo Leute,

sagt mal, gibt's eigentlich eine einfache Variante/Schreibweise um dem 
GCC zu erklären, *direkt/effizient* auf das High/Low-Byte eines 
16-Bit-Wertes zuzugreifen?

uint16_t word;
uint8_t lo;
uint8_t hi;

hi = word >> 8;
lo = word & 0xff;

das ist klar - wird aber (soweit ich bisher gesehen habe) vom Compiler 
leider nicht auf die wirklichen Hi-/Lo-Byte-Zugriffe optimiert ...

Die Kombination aus

typedef union whl {
  uint16_t word;
  struct {
    uint8_t lo;
    uint8_t hi;
  };
};

ist so umständlich zu schreiben (bla.word, bla.lo, bla.hi) und man muß 
die Werte bei der Zuweisung auch noch typecasten ...

Gibt's noch was einfacheres?
Vielleicht ein geschicktes Macro?
Ich steh irgendwie grad auf'm Schlauch ...

- Karl

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl F. schrieb:

> das ist klar - wird aber (soweit ich bisher gesehen habe) vom Compiler
> leider nicht auf die wirklichen Hi-/Lo-Byte-Zugriffe optimiert ...

Der GCC Bug-Report ist
http://gcc.gnu.org/PR41076

Könntest du (oder jemand, der sich dazu berufen fühlt), weitere 
Beispiele zusammenstellen und dort hochladen? Und bitte ohne Includes. 
Danke :-).

von Karl F. (kafido)


Lesenswert?

argh

das ist ja wiedermal typisch ich. Voll in die Falle getreten.
Und dann auch noch ein Bug, der schon vor zwei Jahren
reported wurde und immernoch nicht gefixed ist ...
Ich glaub, ich brauch den nicht nochmal submitten, oder?
Das will scheinbar nicht verstanden werden ...

seufz

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl F. schrieb:

> Ich glaub, ich brauch den nicht nochmal submitten, oder?

Nein. Es gibt doch schon einen Eintrag. Du kannst auch einen neuen 
öffnen, der dann als DUPLICATE gekennzeichnet wird. In dem Falle beachte 
aber auch, daß gcc 4.3 nicht mehr unterstützt wird. Da es sich bei dem 
"Bug" lediglich um ein Optimierungsproblem handelt, sollte ein möglichst 
neuer Compiler verwendet werden (z.b. 4.6.1) um sicherzustellen, daß der 
Fehler nicht bereits behoben wurde und man nur warme Luft produziert.

Einen avr-gcc 4.6.1 für Win32 gibt's in 
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=841595#841595

> Das will scheinbar nicht verstanden werden ...

Was wird nicht verstanden?

von Karl F. (kafido)


Lesenswert?

jau - ich hab nicht richtig gelesen - inzwischen ist der Bug ja gefixed.
Hat ja nur fast zwei Jahre gedauert ...

Hmm ... selbst das relativ neue AVR studio 5 verwendet nur gcc 4.5.1
und die Ardiono-IDE bringt gcc 4.3.2 mit ...

Kriegt man den neuen da ohne Probleme reingeflickt oder geht dann
wieder irgendwas anderes nicht? Hast Du den schon im Einsatz?
Ich kann grad keine unnötige Arbeit und Fehlersuche gebrauchen ...

Danke
- Karl

von (prx) A. K. (prx)


Lesenswert?

Karl F. schrieb:

> Hat ja nur fast zwei Jahre gedauert ...

Fehlende Optimierung eines Spezialfalls hat nicht grad oberste 
Priorität.

von Karl F. (kafido)


Lesenswert?

A. K. schrieb:
> Karl F. schrieb:
>
>> Hat ja nur fast zwei Jahre gedauert ...
>
> Fehlende Optimierung eines Spezialfalls hat nicht grad oberste
> Priorität.

naja, 8-bittiger Zugriff auf Daten ist in einem 8-Bit uC IMHO nicht 
gerade ein Spezialfall. Naja, es gibt ja immernoch Assembler ...

- Karl

von J.-u. G. (juwe)


Lesenswert?

Karl F. schrieb:
> naja, 8-bittiger Zugriff auf Daten ist in einem 8-Bit uC IMHO nicht
> gerade ein Spezialfall.

Das mag sein, aber 8Bit µc gehören nun mal nicht zu den primären 
Zielplattformen des GCC, und dementsprechend sind derartige 
Optimierungen doch ein Spezialfall.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl F. schrieb:
> Kriegt man den neuen da ohne Probleme reingeflickt oder geht dann
> wieder irgendwas anderes nicht? Hast Du den schon im Einsatz?

Bitte von Anfang an lesen!
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=108357&start=all&postdays=0&postorder=asc

Karl F. schrieb:
> Das will scheinbar nicht verstanden werden ...

Karl F. schrieb:
> Hat ja nur fast zwei Jahre gedauert ...

Mich wundert immer die Ansprüchlichkeit, die einer freien Software wie 
GCC entgegengebracht wird, siehe. 
Beitrag "GCC: Arg unzulängliche Optimierungen?"

Jeder kann sich avr-gcc Distributionen herunterladen oder nach Gusto 
selbst erzeugen, ohne auch nur einen Groschen dafür hinzulegen. Und das 
für einen Compiler (GCC), der mit vielen kommerziellen Compilern 
mitziehen kann oder sogar weit in den Schatten stellt, etwa was 
Verfügbarkeit sowie Plattform- und Architekturabdeckung oder 
Erweiterbarkeit (Plugins) angeht. Und obendrauf gibt's auch noch die 
Quellen! Ditto für binutils, avr-libc, avrdude, ...

Und was die PRs angeht, so gibt es für viele noch nicht einmal 
vernünftige Bugreports und/oder man muss solche Kommentare lesen:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49764#c3

> inzwischen ist der Bug ja gefixed
Nein, ist er nicht. Er steht auf UNCONFIRMED.

Es gibt viele Möglichkeiten mit so einem Bug umzugehen:

0. Man ignoriert das Problem und geht zur Tagesordnung über.
1. Man behebt ihn selbst. Immerhin hat man die Quelle.
2. Man wartet, bis irgendjemand ihn behebt.
3. Man versucht zumindest andere Entwickler bei der Entwicklung zu
   unterstützen; etwa durch aussagekräftige Bugreports, Benchmarks,
   Vorabversionen (Release-Candidates) um mehr Fehler vor einer
   Release zu erkennen, etc.
4. Man bezahlt einen Entwickler, ihn zu beheben bzw. kauft sich
   einen professionellen avr-gcc Support (keine Ahnung ob's sowas
   gibt).
5. Man kauft einen kommerziellen Compiler mit Support.

0. und 2. sind bei weitem am beliebtesten, also der Herde nach!
4. und 5. dürften für viele nach Aufräumen der Portokasse ausscheiden.

1. ist nicht wirklich populär und der aktuelle Trend geht dahin, daß die 
AVR-Unterstützung in GCC immer mehr versandet und irgendwann nicht mehr 
nutzbar ist und daher ganz aus GCC entfernt wird, weil sich niemand 
darum kümmert. Dann gibt's auch keine Fehler mehr und vor allem keine, 
bei denen man 2 Jahre rumsitzen muss, bis sich jemand erbarmt für den 
trivialen Bugfix.

Gerade im Feld von Compileranwendern dürfte es einige Entwickler geben, 
die mächtig was auf dem Kasten haben an Erfahrung, Abstraktionsvermögen, 
Hardwarekenntnissen und anderen Skills, die sich vortrefflich für die 
Mitarbeit in einem Open-Source Projekt wie GCC eignen. An Baustellen und 
Herausforderungen mangelt is dort und in anderen Teilen wie binutils 
oder avr-libc nun wirklich nicht. Und sei es nur, Testprogramme für die 
avr-gcc Testsuite beizutragen. Dazu muss man keine Zeiler der 
Compilerquelle gesehen haben oder anfassen.

> Ich kann grad keine unnötige Arbeit und Fehlersuche gebrauchen ...
Wer kann schon unnötige Arbeit oder Fehlersuche gebrauchen? Sag ich auch 
beim nächsten avr-gcc Bugreport...

von Karl F. (kafido)


Lesenswert?

Johann L. schrieb:
> Mich wundert immer die Ansprüchlichkeit, die einer freien Software wie
> GCC entgegengebracht wird

Sorry, Du hast ja vollkomen Recht! Das vergisst man nur viel zu oft.
Normalerweise bin ich derjenige, der das sagt!
... manche Dinge werden mit der Zeit wohl zu selbstverständlich ...

Zu Deiner 6-Punkte-Liste:
0. Das Problem ignorieren kann ich nicht, da es grade zu sehr stört.
1. Selber fixen kann ich es aber auch nicht - dazu kenn ich mich viel 
zuwenig mit compilern aus. Und wenn dann brauch ich dafür Zeit zum 
probieren, die ich im Moment grad echt nicht habe ...

Aber mit dem Wissen dass das so ist, kann ich mir zumindest einen 
geeigneten Workaround basteln - zur Not ein Assembler-Macro.

Punkt 3 hat sich in diesem Fall erübrigt und 4+5 kommen - wie Du bereits 
richtig vermutet hast - gerade nicht in Frage.

Bleibt (MIR) in diesem Fall eigentlich nur Punkt 2.
Compilerbau ist nunmal nicht gerade meine Stärke - da gibt es andere.
Und dort wo ich kann, tu ich auch gern was für andere!

Off-Topic:
Da ATmel selbst den AVR-GCC im AVR-Studio einsetzt hätte ich eigentlich 
erwartet, dass die den irgendwie subventionieren!? Der Erfolg der 
Prozessorfamilie liegt ja schließlich nicht zuletzt an der freien 
Verfügbarkeit der Entwicklungstools.

- Karl

von Karl F. (kafido)


Lesenswert?

trotzdem nochmal zurück zur urprünglichen Frage:
(ganz unabhängig von compiler bug oder nicht)

gibt es nun noch eine andere, möglichst elegante Variante um direkt
auf das HIGH oder LOW Byte eines 16bit-Wertes zuzugreifen oder nicht?

irgendwas nach dem Muster

hi = _HI(word)
lo = _LO(word)

Ich kann gut damit leben, dass der Compiler bestimmte Dinge nicht 
vollautomatisch 100%ig optimieren kann - dafür gibt es viel zu viele 
Möglichkeiten, ganz klar.
Aber dann würde ich mir wünschen entsprechende Statements zu haben,
mit denen ich selber den Code nach Wunsch optimieren kann bzw. dem
Compiler ganz genau mitteilen, was ich möchte.

Gruß
- Karl

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

lo = _LO(word)

entspricht

lo = word & 0xFF;

hi = _HI(word)

enspricht

hi = *(((uint8_t *) &word) + 1);

Je nach Byte-Order kann das natürlich auch genau andersherum sein.


Wie der daraus erzeugte Code Deines Compilers aussieht, müsstest Du 
allerdings selbst untersuchen, weder nutze ich avr-gcc noch habe ich den 
hier irgendwo installiert.

von Karl F. (kafido)


Lesenswert?

Rufus Τ. Firefly schrieb:
> lo = _LO(word)
>
> entspricht
>
> lo = word & 0xFF;

das hab ich probiert und was bei mir herauskam war genau das was da 
steht:
1. laden eines 16-bit Wertes in ein Registerpaar
2. and mit 0x00ff

natürlich funktioniert das - ist aber nicht effizient.


> hi = *(((uint8_t *) &word) + 1);

dsa typecasting muss ich nochmal versuchen.
Analog müßte dann ja auch ein:

lo = *((uint8_t *) &word);

oder gleich ein

lo = (uint8_t) word;

funktionieren - werd ich nochmal testen.

Ich wollte ja auch nur wissen, ob es evtl. noch ein tolles Kommando 
gibt, dass ich in meiner grenzelosen Unwissenheit nicht kenne. Ich hab 
nämlich schon mehr als einmal das Rad neu erfunden und hinterher 
festgestellt, dass es das schon gibt ... ärgerlich.

Wenn es nichts dergleichen gibt, fein. Damit kann ich auch leben.

Vielen Dank für die Antworten.

Gruß
- Karl

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl F. schrieb:
> Da Atmel selbst den AVR-GCC im AVR-Studio einsetzt hätte ich eigentlich
> erwartet, dass die den irgendwie subventionieren!? Der Erfolg der
> Prozessorfamilie liegt ja schließlich nicht zuletzt an der freien
> Verfügbarkeit der Entwicklungstools.

Das verstehen eben nicht alle Hardwarehersteller, insbesondere auch im 
Bezug auf GCC, der hier IMO unterschätzt wurde/wird, vor allem auch im 
Hinblick auf sein Potential. Vergleicht man den Aufwand, den in PowerPC, 
x86, Sparc, ARM und wie sie alle heissen reingesteckt wird (und 
natürlich auch die Ergebnisse, die dabei herauskommen), dann wird klar, 
daß avr-gcc ein absolutes Waisenkind ist.

Die Atmel-Policy ist mir nicht bekannt; aktive avr-gcc Entwickler von 
seiten Atmels sind mir nicht bekannt – ausser Eric, der aber in binutils 
und avr-libc unterwegs ist und WinAVR releast. Von Anitha hab ich länger 
nix mehr gehört. Atmel scheint eher darauf konzentriert, private 
Änderungen in seinem avr-gcc Fork zu pflegen (ATXmega, ATwinzig, 
FixedPoint, ...) und bringt diese aber nicht ins offizielle Repository 
ein — sei es aus lizenzrechtlichen Gründen oder aus technischen 
Widerständen.

Gerüchteweise hat Atmel GCC-Entwickler gesucht aber keine gefunden, was 
mir durchaus glaubhaft plausibel erscheint. Momentan liegt die 
offizielle Toolchain brach, und nur hin und wieder verirrt sich jemand 
dahin. Die Atmel-Entwicklung dürfte i.W. damit beschäftigt sein, die 
ganzen Patches up to date zu halten.

Karl F. schrieb:
> gibt es nun noch eine andere, möglichst elegante Variante um direkt
> auf das HIGH oder LOW Byte eines 16bit-Wertes zuzugreifen oder nicht?

Am elegentesten ist der Weg ohne Verrenkung über die Operationen in 
deinem OP.

Ansonsten ... kommt drauf an

· Soll es leserlich sein?
· Soll es effizient sein?
· Bezieht es sich auf Register oder Speicher?
· Soll nur lesend und/oder schreibend zugegriffen werden?
· Welcher C-Standard?
· Ist (Inline-)Asm ok?
· Spielt Portabilität eine Rolle (Endianess)
· Wie sieht's mit Type Punning/Strict Aliasing aus?
· Wozu brauchst du es überhaupt?
· Gibt es ein übersetzbares Beispiel?

von Karl F. (kafido)


Lesenswert?

Johann L. schrieb:
>
> Ansonsten ... kommt drauf an
>
> · Soll es leserlich sein?
> · Soll es effizient sein?
> · Bezieht es sich auf Register oder Speicher?
> · Soll nur lesend und/oder schreibend zugegriffen werden?
> · Welcher C-Standard?
> · Ist (Inline-)Asm ok?
> · Spielt Portabilität eine Rolle (Endianess)
> · Wie sieht's mit Type Punning/Strict Aliasing aus?
> · Wozu brauchst du es überhaupt?
> · Gibt es ein übersetzbares Beispiel?

Nun, in erster Linie soll es effizient sein.
Die meisten Zugriffe, um die es geht, sind lesend.

Inline-ASM ist vollkommen ok, Portabilität ist nicht gefragt.
(wenn ich die Zeit hätte, würde ich vermutlich das ganze Programm in ASM 
schreiben, aber in C geht das halt doch ein ganzes Stückchen schneller)

"Type Punning/Strict Aliasing":
Hab ich nicht grade unter http://gcc.gnu.org/bugs/#known gelesen, dass 
man das nicht utn soll?

Beispiele wofür das gebraucht wird:

Ich übergebe einen uint16_t an eine Funktion und möchte in dieser 
Funktion z.B. (zunächst) nur wissen, ob die Zahl gerade ist. Dafür 
reicht es, das lo-Byte zu testen ...
Oder ich möchte wissen, ob der Wert größer als 1024 ist - dafür reicht 
ein Test des hi-bytes. Bzw. zum Vorzeichen testen reicht auch das 
Hi-Byte.

Weiterhin war es die unsägliche immer wiederkehrende Division durch 10, 
z.B. wenn man eine Zahl zur Ausgabe vorbereitet (Display, Seriell):

Dazu hatte ich mit Routinen wie dieser experimentiert:
Q: http://www.cs.uiowa.edu/~jones/bcd/decimal.html
1
    void putdec( int16_t n )
2
    {
3
        uint8_t d4, d3, d2, d1, d0, q;
4
5
        if (n < 0) {
6
            putchar( '-' );
7
            n = -n;
8
        }
9
10
        d1 = (n>>4)  & 0xF;
11
        d2 = (n>>8)  & 0xF;
12
        d3 = (n>>12) & 0xF;
13
14
        d0 = 6*(d3 + d2 + d1) + (n & 0xF);
15
        q = (d0 * 0xCD) >> 11;
16
        d0 = d0 - 10*q;
17
18
        d1 = q + 9*d3 + 5*d2 + d1;
19
        q = (d1 * 0xCD) >> 11;
20
        d1 = d1 - 10*q;
21
22
        d2 = q + 2*d2;
23
        q = (d2 * 0x1A) >> 8;
24
        d2 = d2 - 10*q;
25
26
        d3 = q + 4*d3;
27
        d4 = (d3 * 0x1A) >> 8;
28
        d3 = d3 - 10*d4;
29
30
        putchar( d4 + '0' );
31
        putchar( d3 + '0' );
32
        putchar( d2 + '0' );
33
        putchar( d1 + '0' );
34
        putchar( d0 + '0' );
35
    }

Dabei war mir aufgefallen, dass die anfängliche Aufteilung:
1
        d1 = (n>>4)  & 0xF;
2
        d2 = (n>>8)  & 0xF;
3
        d3 = (n>>12) & 0xF;
nicht besonders elegant übersetzt wird.
Auch bei Dingen wie:
1
q = (d1 * 0xCD) >> 11;
wäre es effizienter sagen zu können:
1
q = _HI((d1 * 0xCD)) >> 3;
denn auch hier reicht das hi-Byte ...
Außerdem sind hier beide Werte - sowohl d1 als auch 0xCD nur Bytes 
(uint8_t), aber ich glaube (bin mir nicht mehr ganz sicher) der Compiler 
hatte die erst mal bedie in 16bit gewandelt und dann erst eine 16bit-
Multiplikation gemacht, obwohl eine 8bit-Multiplikation vollkommen 
gereicht hätte ...

Langer Rede kurzer Sinn:
An manchen Stellen - wenn man optimieren möchte - wäre es schön, dem 
Compiler durch irgendwelche Flags, typecasting, _atribute_ oder sonst 
was genau sagen zu können, was er tun soll, statt vom Compiler 
Optimierungswunder zu erwarten. Letztendlich weiß doch nur der 
Programmierer, was er bezwecken will ...

Gruß
- Karl

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hast du versucht
1
void putdec (int16_t sn)
2
{
3
    uint16_t n;
4
    uint8_t d4, d3, d2, d1, d0, q;
5
6
    if (sn < 0) 
7
    {
8
        putchar( '-' );
9
        sn = -sn;
10
    }
11
  
12
    n = sn;
13
    ...

Vorzeichen machen nur das Leben schwer. Ausserdem kommt's in der Ausgabe 
doch nicht wirklich auf Geschwindigkeit an (es sei denn, du malst auf ne 
Kathodenstrahlröhre ;-)).

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


Lesenswert?

Johann L. schrieb:
> Atmel scheint eher darauf konzentriert, private
> Änderungen in seinem avr-gcc Fork zu pflegen (ATXmega, ATwinzig,
> FixedPoint, ...) und bringt diese aber nicht ins offizielle Repository
> ein — sei es aus lizenzrechtlichen Gründen oder aus technischen
> Widerständen.

Eher aufgrund fehlender Kapazität.  Der Xmega-Patch wäre wohl in einem
Stadium, dass man ihn tatsächlich einbringen könnte, der Lizenzkram
ist mittlerweile ja wohl in Sack und Tüten.  Keine Ahnung, ob dies nun
auf Erics Tisch liegt, vermutlich.  Der Tiny-Kram ist nach letzten
Erfahrungen wohl noch reichlich buggy, und wenn sie überhaupt jemanden
im Moment haben, der irgendwas am GCC entwickelt (ich glaube mich zu
erinnern, da mal einen indisch klingenden Namen gelesen zu haben, aber
nicht Anitha, die macht eher avr-libc), dann wird der wohl damit zu
tun haben, die Tiny10-Familie da in Gang zu bekommen.  Von fixed point
weiß ich gerade nichts.  Wenn sie da interne Patches haben, dann ist
es irgendwas, was mal bei avrfreaks gepostet worden war, nichts
eigenes.

> Gerüchteweise hat Atmel GCC-Entwickler gesucht aber keine gefunden, was
> mir durchaus glaubhaft plausibel erscheint.

GCC-Interna sind leider nicht gerade ein einfaches Feld.  Da genügt
es nicht nur, einen Willen zu haben, etwas beizusteuern, sondern man
muss sich schon mächtig in RMS' Denkweise reinfühlen können.  Ich tu'
mir vieles im Opensource-Bereich an, aber da muss ich leider auch
passen.  So wird es (leider) auch einigen anderen gehen, es genügt
also für einen CPU-Hersteller nicht, nur überhaupt bereit zu sein,
jemanden zu bezahlen dafür, sondern man muss erstmal jemanden finden,
der es überhaupt kann (und dann muss der auch noch bezahlbar sein ;).

von Karl F. (kafido)


Lesenswert?

Wow ... da hab ich ja eine Lawine losgetreten ...

Eigentlich hab ich ja nur gefragt, ob es eine Funktion oder ein Makro 
gibt,
die/das ich evtl. nicht kenne - sowas wie die _BV() Makros z.Beispiel.
Makro macht natürlich nur dann Sinn wenn es was ist, was dann vom 
Compiler auch wirklich effizient übersetzt wird, so wie z.B. ein

PORTB |= 0x40
oder
PORTB |= _BV(6)

wirklich in ein

sbi PORTB, 6

übersetzt wird.


Johann L. schrieb:
>
> Vorzeichen machen nur das Leben schwer. Ausserdem kommt's in der Ausgabe
> doch nicht wirklich auf Geschwindigkeit an (es sei denn, du malst auf ne
> Kathodenstrahlröhre ;-)).

Den Spruch hab ich jetzt schon mehrfach zu hören bekommen.
Das mit dem putchar() ist ja auch nur ein Beispiel.
MIR kommt es bei meiner Programmieraufgabe sehr wohl auf Geschwindigkeit
an, wobei die Erläuterung der Gründe hier eigentlich off-topic ist.

Nur so viel:
Es passiert alles in Interrupt-Routinen, die ja bekanntlich so kurz wie 
möglich sein sollten.

Ich erhalte z.B. Messwerte in einer Interrupt-Routine und Display bzw. 
Serialport wird in einer anderen Interrupt-Routine behandelt.
Wenn ich jetzt die Werte erst mal ans main() übergeben muss, um sie dort 
"langsam" zu behandeln, muss ich die entsprechenden Variablen alle als 
volatile deklarieren was die Sache auch nicht unbedingt schneller macht.
Bleibt die Behandlung vollständig in Interrupte (die sich gegenseitig 
nicht unterbrechen) kann ich mir das sparen.

Gruß
- Karl


Ich kann

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Johann L. schrieb:
>> Atmel scheint eher darauf konzentriert, private
>> Änderungen in seinem avr-gcc Fork zu pflegen (ATXmega, ATwinzig,
>> FixedPoint, ...) und bringt diese aber nicht ins offizielle Repository
>> ein — sei es aus lizenzrechtlichen Gründen oder aus technischen
>> Widerständen.
>
> Eher aufgrund fehlender Kapazität.  Der Xmega-Patch wäre wohl in einem
> Stadium, dass man ihn tatsächlich einbringen könnte, der Lizenzkram
> ist mittlerweile ja wohl in Sack und Tüten.  Keine Ahnung, ob dies nun
> auf Erics Tisch liegt, vermutlich.

So wie ich ihn verstanden habe, ja. Ich wundere mich allerdings, daß es 
nicht längst committed oder zumindest im Review ist – wobei Eric 
letzteres ja garnicht braucht. Sooo viel Zeit ist nicht mehr, 
angepeiltes Ende von 4.7 Stage 1 ist Ende Oktober. Ich kann mir aber gut 
vorstellen, daß er ziemlich mit WinAVR 4.6.2 beschäftigt ist.

> Der Tiny-Kram ist nach letzten Erfahrungen wohl noch reichlich buggy,

Von mir aus kann das Tiny-Zeugs bei Atmel bleiben. Ich versteh immer 
noch nicht, was sie mit diesem Silizium wirklich wollen, bzw. was 
sie/jemand mit diesem Silizium + GCC will.

> und wenn sie überhaupt jemanden
> im Moment haben, der irgendwas am GCC entwickelt (ich glaube mich zu
> erinnern, da mal einen indisch klingenden Namen gelesen zu haben, aber
> nicht Anitha, die macht eher avr-libc), dann wird der wohl damit zu
> tun haben, die Tiny10-Familie da in Gang zu bekommen.

Abnikant Singh?

> Von fixed point weiß ich gerade nichts.
> Wenn sie da interne Patches haben, dann ist es irgendwas, was mal
> bei avrfreaks gepostet worden war, nichts eigenes.

AFAIK von Sean D'Epagnier aka. geckosenator (mit FSF-CA).

>> Gerüchteweise hat Atmel GCC-Entwickler gesucht aber keine gefunden, was
>> mir durchaus glaubhaft und plausibel erscheint.
>
> GCC-Interna sind leider nicht gerade ein einfaches Feld.  Da genügt
> es nicht nur, einen Willen zu haben, etwas beizusteuern, sondern man
> muss sich schon mächtig in RMS' Denkweise reinfühlen können.

RMS ist da schon lange nicht mehr unterwegs, und ich denke, daß sich in 
jedem Compiler dieser Liga ähnliche Strukturen, Probleme und 
Problemlösungen ergeben: Rumtanzen auf SSA-Trees, Data- und Code-Flow 
Analyse, PRE, CSE, DSE, CIM, LCM, Registerallocation, Instruction 
Combining, Scheduling und weiß-der-Teudel-was-noch für Optimierungen und 
Algorithmen.

Der Teufel im Detail sieht dagegen überall anders aus, und bei den 
vielen Details in GCC gibt's auch ensprechend viele Teufelchen.

Wenn man damit anfängt, kann es schon frustrieren sein, sich an einer 
"trivialen" Aufgabe wie den hier angesprochenen 
Byte-Operationen/-Optimierungen die Zähne auszubeissen um nach 
Tagen/Wochen frustriert aufzugeben – abgesehen von sonstigen Schikanen 
wie Regression-Tests, Reviews und zu schauen, daß nicht anderer Code 
schlechter wird.

> Ich tu' mir vieles im Opensource-Bereich an, aber da muss ich
> leider auch passen.  So wird es (leider) auch einigen anderen gehen,

Schade eigentlich. Aber bei dir denk ich daß du ansonsten schon genug 
Projekte am Bein hast. Wenn man allerdings die Hacks, Würgarounds und 
Verwünschungen und fruchtlosen Forendiskussionen in einen Topf wirft, 
könnte man locker 10 AVR-Backends chic machen oder komplett neu 
hochziehen ;-)

> es genügt also für einen CPU-Hersteller nicht, nur überhaupt bereit
> zu sein, jemanden zu bezahlen dafür, sondern man muss erstmal
> jemanden finden, der es überhaupt kann (und dann muss der auch
> noch bezahlbar sein ;).

An der nächsten Straßenecke wird man einen Richard Guenther, Ian L. 
Taylor, Joseph S. Myers oder Michael Meissner garantiert nicht finden.
Die Arbeitgeber lesen sich wie ein who-is-who: Google, IBM, SuSE, ARM, 
Codesourcery, Redhead, ... Ich möchte garnicht wissen, was so jemand 
kostet, und Geld alleine macht's da bestimmt nicht. So jemand will auch 
ein entsprechendes Arbeits- und Lebensumfeld, Team, kreative Freiheit 
usw. vorfinden und nicht als lone Hacker in einem Konzern untergehen, wo 
er hier und da ein paar Tweaks oder Erweiterungen an einem ferner-liefen 
Backend machen darf.

Atmel macht hier vermutlich den Fehler zu glauben, einen Entwickler 
einfach einkaufen zu können. Stattdessen muss hier auch kontinuerlich 
daran gearbeitet werden, ein eigenes Compilerteam aufzubauen und eine 
Mindestmaß an kritischer Masse zu erreichen, um 
Compilerentwicklung/anpassung sinnvoll zu machen. Arbeit gibt's da 
genug, und ich weiß auch nicht, wie Atmel den AVR32-Port gestemmt hat.

Ansonsten ist das AVR-Backend quasi tot. Anatoly ist nicht mehr aktiv 
und Andy Hutchinson seit Jahren nicht mehr gesehen. Eric fügt 
bestenfalls neue copy-paste Derivate ein und Denis beschränkt sich aufs 
Review der spärlichen Patches (immerhin!).

Karl F. schrieb:
> Eigentlich hab ich ja nur gefragt, ob es eine Funktion oder ein Makro
> gibt, die/das ich evtl. nicht kenne -
> sowas wie die _BV() Makros z.Beispiel.
> Makro macht natürlich nur dann Sinn wenn es was ist, was dann vom
> Compiler auch wirklich effizient übersetzt wird, so wie z.B. ein
>
> PORTB |= 0x40
> oder
> PORTB |= _BV(6)
>
> wirklich in ein
>    sbi PORTB, 6
> übersetzt wird.

_BV mach aber nix ausser Textersatz und hilft die Quelle zu obfuskieren 
;-) Die Abbildung auf SBI et al. macht der Compiler auch ohne dieses 
tolle Makro.

> Johann L. schrieb:
>>
>> Vorzeichen machen nur das Leben schwer. Ausserdem kommt's in der Ausgabe
>> doch nicht wirklich auf Geschwindigkeit an (es sei denn, du malst auf ne
>> Kathodenstrahlröhre ;-)).
>
> Den Spruch hab ich jetzt schon mehrfach zu hören bekommen.
> Das mit dem putchar() ist ja auch nur ein Beispiel.
> MIR kommt es bei meiner Programmieraufgabe sehr wohl auf Geschwindigkeit
> an, wobei die Erläuterung der Gründe hier eigentlich off-topic ist.

Naja, man darf einen Blick über den Tellerrand wagen.

> Nur so viel:
> Es passiert alles in Interrupt-Routinen, die ja bekanntlich so kurz wie
> möglich sein sollten.
>
> Ich erhalte z.B. Messwerte in einer Interrupt-Routine und Display bzw.
> Serialport wird in einer anderen Interrupt-Routine behandelt.

Standardansart ist dann mit zwei atomaren volatile-Variablen V1 und V2:

ISR1 → V1 → V2 → ISR2

wobei die Applikation die Umwandlungsroutine V1 → V2 ausführt. Und 
natürlich reduziert man die Zugriffe auf V1/V2 auf ein Minimum d.h. der 
Algorithmus operiert nicht auf diesen Variablen sondern mach sich lokale 
Kopien.

> Wenn ich jetzt die Werte erst mal ans main() übergeben muss, um sie dort
> "langsam" zu behandeln, muss ich die entsprechenden Variablen alle als
> volatile deklarieren was die Sache auch nicht unbedingt schneller macht.

S.o.

> Bleibt die Behandlung vollständig in Interrupte (die sich gegenseitig
> nicht unterbrechen) kann ich mir das sparen.

Zurück zu Thema :-)

Der verlinkte Artikel ist interessante Lekture und es kommt ein Punkt 
hinzu:

· Gibt es einen Hardware-Multiplier?

Ohne diesen nimmt man die Subtraktion von 10000/1000/100/10 wie im 
Artikel ganz oben beschrieben.

Mit MUL kommt einem die C-Semantik quer denn 6·char wird gemäß dieser 
auf 16-Bit Ebene ausgeführt. Um die Arithmetik wirklich auf 8 Bits zu 
drücken und den Algorithmus optimal umzusetzen fürht also kein Weg an 
Assembler vorbei. Bei avr-gcc kommt hinzu, daß nach jedem MUL das 
0-Register gelöscht werden muss und kein Multiply-Add auf R0/R1 
ausgeführt wird [1], d.h. das Multiplikationsergebnis muss immer aus 
R0/R1 herausbefördert werden.

Auf C-Ebene bekommt man das nicht so gut hin wie mit Assembler und der 
Code wird zunehmend unleserlich. Bei uint8_t
1
a + b + c
werden also mindestens erweiternde Additionen ausgeführt anststt das auf 
8-Bit-Ebene zu tun.
1
unsigned char t = a + b;
2
t += c;
kann sich da anbieten, was teilweise Casts überlegen ist.

Ähnlich sieht es mit Multiplikationen aus, die immer auf 16 Bits 
erweitern. Erschwerend kommt da hinzu, daß erst in 4.7 erweiternde 
Multiplikationen besser implementiert sind: http://gcc.gnu.org/PR49687
Das allerdings nur wenn es ein MUL gibt, der Wolf, den man sich ohne MUL 
machen muss, war mir echt zu viel...

Zur Extraktion der Nippel kann man sich erst mal die Bytes besorgen:
1
uint16_t n = ...;
2
uint8_t hi, lo;
3
uint8_t n3, n2, n1, n0;
4
5
hi = n >> 8;
6
lo = n;
7
8
n3 = hi >> 4;
9
n2 = hi & 0xf;
10
n1 = lo >> 4;
11
n0 = lo & 0xf;

Dann wie beschrieben häppchenweise weiter.
Oder eben tabula rasa und mit Assembler anfangen.

[1] Da würde sich auch ne Riesen-Baustelle auftun:
1
int madd (int i, char a, char b)
2
{
3
    return i + a*b;
4
}
wird von avr-gcc 4.6 übersetzt zu
1
madd:
2
    muls r22,r20
3
    movw r20,r0
4
    clr __zero_reg__
5
    add r20,r24
6
    adc r21,r25
7
    movw r24,r20
8
    ret
Aber es ginge auch
1
madd:
2
    muls r22,r20
3
    add r24, r0
4
    adc r25, r1
5
    clr __zero_reg__
6
    ret

von Karl F. (kafido)


Lesenswert?

Schweinkram - mein letzter Antwortpost ist wohl irgendie in /dev/null 
verlorengegangen. Naja, vermutlich sitzt das Problem - wie fast immer - 
vor der Tastatur ...


Johann L. schrieb:
>>
>> wirklich in ein
>>    sbi PORTB, 6
>> übersetzt wird.
>
> _BV mach aber nix ausser Textersatz und hilft die Quelle zu obfuskieren
> ;-) Die Abbildung auf SBI et al. macht der Compiler auch ohne dieses
> tolle Makro.

klar - deswegen hatte ich ja auch "PORTB |= 0x40" oder "PORTB |= 
_BV(6)" geschrieben.


> Der verlinkte Artikel ist interessante Lekture ...
... das fand ich auch ;-)
Besonders die ASCII-Arithmetik hatte es mir angetan:
(http://www.cs.uiowa.edu/~jones/bcd/bcd.html#ascii)
Aber das ist ein ganz anderes Thema ...

Nun denn, dann werde ich wohl dort, wo es darauf ankommt,
mit inline-Assembler arbeiten.


Zurück zur Compiler-Optimierung:
Manche Compiler erkennen doch auch Dinge wie "x /= 2 und ersetzen diese 
durch "x >>= 1" u.ä. Da wäre es doch naheliegend, auch "x /= 10" durch 
eine effizientere Divisionsroutine zu ersetzen als die normale Division. 
Immerhin ist 10 (nach 2) mit an Sicherheit grenzender Wahrscheinlichkeit 
die am häufigsten verwendete Divisor-Konstante überhaupt ...

Aber ich weiß: wir sind hier nicht bei "wünsch Dir was" ;-)

Nun denn, nochmal vielen Dank Johann für die Erläuterungen.
Und - wie mein Boss jetzt sagen würde - keep up the good work!

Gruß
- Karl

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl F. schrieb:

> Zurück zur Compiler-Optimierung:
> Manche Compiler erkennen doch auch Dinge wie "x /= 2 und ersetzen diese
> durch "x >>= 1" u.ä. Da wäre es doch naheliegend, auch "x /= 10" durch
> eine effizientere Divisionsroutine zu ersetzen als die normale Division.

Sofern wir von avr-gcc reden musst du dafür auf avr-gcc 4.7 warten (oder 
dir nen Snapshot selber generieren).

Für eine Speed-optimierte Division durch 10 sieht der Code aus wie
1
unsigned char udiv10_speed (unsigned char n)
2
{
3
    return high (205*n) >> 3;
4
}
Frag mich jetzt nicht, wie der Code für /5 oder /3 oder signed aussieht. 
Das ist alles GCC-Magie, die es schon längt gibt. Man muss lediglich in 
der avr-Beschreibung im richtigen Loch rumstochern um sie zu bekommen 
;-)

Für Size-optimierten Code wird wie bisher eine Division ausgeführt weil 
Code aus der libgcc wiederverwendet werden kann.

> Immerhin ist 10 (nach 2) mit an Sicherheit grenzender Wahrscheinlichkeit
> die am häufigsten verwendete Divisor-Konstante überhaupt ...

Ich würd tippen daß 256 häufiger vorkommt als 10.

von Karl F. (kafido)


Lesenswert?

Johann L. schrieb:
>
> Für eine Speed-optimierte Division durch 10 sieht der Code aus wie
>
1
> unsigned char udiv10_speed (unsigned char n)
2
> {
3
>     return high (205*n) >> 3;
4
> }
5
>

klar, reziproke Multiplikation ...
Nur bei Werten größer 8 Bit ist das leider nicht mehr ganz so einfach 
...

ABER:
1
return high (205*n) >> 3;
2
       ^^^^
DAS ist doch genau das, wonach ich suche!
Wie komme ich direkt an das high (oder low) Byte eines uint16_t ???
Und damit meine ich jetzt eben nicht ein ">> 8" bzw. "& 0xff"


> Frag mich jetzt nicht, wie der Code für /5 oder /3 oder signed aussieht.

findet sich übrigens alles auch in dem Artikel:
http://www.cs.uiowa.edu/~jones/bcd/divide.html


>> Immerhin ist 10 (nach 2) mit an Sicherheit grenzender Wahrscheinlichkeit
>> die am häufigsten verwendete Divisor-Konstante überhaupt ...
>
> Ich würd tippen daß 256 häufiger vorkommt als 10.

Ja, klar, ich meinte ja auch alle 2er-Potenzen.
Genauso wie ich mit 10 nicht nur 10, sondern auch 100, 1000, 10000 usw.
gemeint hab.

Gruß
- Karl

von Johann L. (gjlayde) Benutzerseite


Angehängte Dateien:

Lesenswert?

Karl F. schrieb:
> Johann L. schrieb:
>>
>> Für eine Speed-optimierte Division durch 10 sieht der Code aus wie
>>
1
>> unsigned char udiv10_speed (unsigned char n)
2
>> {
3
>>     return high (205*n) >> 3;
4
>> }
5
>>
>
> klar, reziproke Multiplikation ...
> Nur bei Werten größer 8 Bit ist das leider nicht mehr ganz so einfach

So klar finde ich das nicht. Das Pronzip ist klar aber nicht, warum 
man es für eine gegebene Konstante für alle Dividenden ohne Fehler 
machen kann. Aber darüber haben sich schon genug Jungs den Kopf 
zerbrochen und ich brauch's zum Glück nicht. Für das obige Beispiel hab 
ich einfach geschaut, was avr-gcc 4.7 ausspuckt.

Übrigens macht er es auch für 16-Bit Divisionen mit bekanntem Divisor.

> ABER:
>
1
> return high (205*n) >> 3;
2
>        ^^^^
3
>
> DAS ist doch genau das, wonach ich suche!

Nö, das ist nur Pseudo-Code um zu veranschaulichen, wie GCC es macht. 
Der liefert es natürlich als Assembler-Code.

> Wie komme ich direkt an das high (oder low) Byte eines uint16_t ???
> Und damit meine ich jetzt eben nicht ein ">> 8" bzw. "& 0xff"

Die Werte durch eine Union durchzuschleusen (s. Anhang) gibt bestimmt 
fürchterlich unleserlichen Code.

Ok... hab's mit mal im Detail angeschaut für folgenden Code (modulo 
Tippfehler):
1
#include <stdint.h>
2
3
#define put_digit(X) *s++ = (X)
4
5
#if 0
6
#define umul_hi(a,b) \
7
 ({ uint8_t _c; \
8
    asm ("mul %1, %2"  "\n\t"\
9
         "mov %0, R1"  "\n\t"\
10
         "clr __zero_reg__"\
11
         : "=r" (_c) : "r" ((char) a), "r" ((char) b));\
12
         _c;})
13
#else
14
#define umul_hi(a,b) \
15
 ({ uint8_t _a=a, _b=b; \
16
    uint8_t _c=_a*_b; _c;})
17
#endif
18
19
void putdec (uint16_t n, char *s)
20
{
21
    uint8_t d4, d3, d2, d1, d0, q;
22
23
    if (n >= 0x8000)
24
    {
25
        put_digit ('-');
26
        n = -n;
27
    }
28
    
29
    d0 = n;
30
    d1 = d0 >> 4;
31
    d0 &= 0xf;
32
33
    d2 = n >> 8;
34
    d3 = d2 >> 4;
35
    d2 &= 0xf;
36
37
    d0 += 6 * (d3 + d2 + d1);
38
    q = umul_hi (d0, 0xCD);
39
    q >>= 3;
40
    d0 -= 10*q;
41
42
    d1 = q + 9*d3 + 5*d2 + d1;
43
    q = umul_hi (d1, 0xCD);
44
    q >>= 3;
45
    d1 -= 10*q;
46
47
    d2 = q + 2*d2;
48
    q = umul_hi (d2, 0x1A);
49
    d2 -= 10*q;
50
51
    d3 = q + 4*d3;
52
    d4 = umul_hi (d3, 0x1A);
53
    d3 -= 10*d4;
54
55
    put_digit (d4 + '0');
56
    put_digit (d3 + '0');
57
    put_digit (d2 + '0');
58
    put_digit (d1 + '0');
59
    put_digit (d0 + '0');
60
    put_digit (0);
61
}
Die Funktion macht keine Ausgabe, sondern schreibt lediglich 7 Zeichen 
in den Übergebenen char*. Dadurch spart man Funktionsaufrufe und die 
Funktion wird zum Blatt. Sie nimmt ein unsigned int entgegen.

avr-gcc -Os -mmcu=atmega8 (Größe in Bytes)
1
         Asm    ohne Asm
2
3.4.6    254    252
3
4.2.2    290    262
4
4.3.3    260    260
5
4.5.2    206    206
6
4.6.1    186    186
Für 4.6 gibt es ausser dem n=-n am Anfang keine 16-Bit Operationen mehr 
im Code, d.h. auf C-Ebene dürfte bei ca. 180 Bytes Ende der Fahnenstange 
sein – zumindest für 4.6.

"Asm" bezieht sich auf den Inline-Asm für den High-Teil einer 
8*8-Multiplikation. Als einziger gewinnt dadurch 4.2.

Fazit

Der Code ist ausser dem kurzen Stückchen am Anfang linear. Gehen wir 
großzügigerweise davon aus, daß die eigentliche Routine ohne den String 
zu schreiben 160 Ticks braucht, dann landen wir bei 40 Ticks pro 
Ziffer!!! (mit 4 Ziffern veranschlagt)

Da ist ein simples Abziehen von 10000, 1000, 100, 10 wesentlich 
einfacher zu implementieren und zu lesen und im Mittel womöglich sogar 
schneller, zumal du wahrscheinlich nicht avr-gcc 4.6 im Einsatz hast! 
Oben habe ich mit 4 Ziffern verglichen, weil man bei der Abzieh-Methode 
Ziffer 0 für lau bekommt.

Bei mir sieht eine Abzieh-Methode so aus, wobei dort keine führenden 
Nullen ausgegeben werden. Die Funktion ist i.W. auf Größe optimiert (62 
Bytes):
1
static const uint16_t pows10[] PROGMEM = 
2
{
3
    10000, 1000, 100, 10
4
};
5
6
// Wandelt N in eine ASCII-Dezimalzahl um. Die Darstellung wird
7
// mit abschliessender '\0' als Stringende nach STR geschrieben.
8
// Return: Adresse der abschliessenden '\0'.
9
char * u16_to_string (char * str, uint16_t n)
10
{
11
    register const uint16_t * p asm ("r30") = pows10;
12
    
13
    uint16_t pow10;
14
    uint8_t not0 = 0;
15
16
    do
17
    {
18
        pow10 = pgm_read_word_inc (p);
19
        char c = '0';
20
        
21
        while (n >= pow10)
22
            not0 = 1, n -= pow10, c++;
23
            
24
        if (not0)
25
            *str++ = c;
26
            
27
    } while (! (pow10 & 2)); // pow10 != 10
28
    
29
    // Einer
30
    *str++ = n+'0';
31
    *str   = '\0';
32
    
33
    return str;
34
}

Um 12345 auszugeben messe ich da 165 Ticks und für eine 1 nur 81. Für 
9999 allerdings ≈300.

von Abdul K. (ehydra) Benutzerseite


Lesenswert?

Kleine Zahlen kommen statistisch viel häufiger vor als große Zahlen. Ja, 
das ist wohl eine Binsenweisheit. Das gilt aber auch erstaunlicherweise 
für Ziffern!!

Daher bekommt durchschnittlich eine Subtraktionsmethode sogar nochmals 
Schub...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Abdul K. schrieb:
> Kleine Zahlen kommen statistisch viel häufiger vor als große Zahlen. Ja,
> das ist wohl eine Binsenweisheit. Das gilt aber auch erstaunlicherweise
> für Ziffern!!

Nicht von Binsen, sondern von Benford ;-)

http://de.wikipedia.org/wiki/Benfordsches_Gesetz

von Karl F. (kafido)


Lesenswert?

Johann L. schrieb:
> Um 12345 auszugeben messe ich da 165 Ticks und für eine 1 nur 81. Für
> 9999 allerdings ≈300.

Danke Johann, dass Du Dir die Zeit genommen hast.

Mir ist ein definiertes Zeitverhalten lieber als ein variables.
d.h. immer 200 Ticks sind mir lieber als durchschnittlich 160
die aber manchmal auch 300 sein koennen.
Sowas fuehrt naemlich zu den schoenen race-conditions, bei denen 
irgendwas irgendwann mal an die Wand läuft und kein Schwein weiss warum.
Am liebsten ist mir also eine Routine, die ganz ohne "if" auskommt.

- Karl

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


Lesenswert?

Johann L. schrieb:

(Xmega)

>> Keine Ahnung, ob dies nun
>> auf Erics Tisch liegt, vermutlich.
>
> So wie ich ihn verstanden habe, ja. Ich wundere mich allerdings, daß es
> nicht längst committed oder zumindest im Review ist – wobei Eric
> letzteres ja garnicht braucht. Sooo viel Zeit ist nicht mehr,
> angepeiltes Ende von 4.7 Stage 1 ist Ende Oktober. Ich kann mir aber gut
> vorstellen, daß er ziemlich mit WinAVR 4.6.2 beschäftigt ist.

Ja, vermute ich auch, ich müsste ihn mal fragen.

>> Der Tiny-Kram ist nach letzten Erfahrungen wohl noch reichlich buggy,

> Von mir aus kann das Tiny-Zeugs bei Atmel bleiben. Ich versteh immer
> noch nicht, was sie mit diesem Silizium wirklich wollen,

Verkaufen. ;-)

Ganz ehrlich: wenn da nicht irgendwelche Millionenstückzahlen dahinter
stecken würden, hätte sowas sicher niemand dort angefangen.  Es ist ja
letztlich eine recht umfangreiche Produktentwicklung mit einem neuen
Core, nicht nur das 125. Derivat eines bereits existierenden AVRs, bei
dem man "nur" die Funktionsblöcke mal neu sortieren und anordnen muss.
Wenn du nun siehst, dass man die Teile bei Digikey für 44 Cent bekommt
(Stückpreis bei Abnahme einer Rolle) und Digikey auch noch was
verdienen will dabei, dann werden die Teile vielleicht 10 oder 15 Cent
Gewinn abwerfen.  Nun halt' das mal gegen eine Produktentwicklung mit
Kosten von (grob geraten) vielleicht 10 Millionen, dann sollte klar
werden, um welche Stückzahlen es hier geht — und dass die paar
Hobbyisten in dieser Rechnung ganz gewiss keine Rolle spielen.

> bzw. was
> sie/jemand mit diesem Silizium + GCC will.

Naja, auch dort hast du bei einer Produktentwicklung in C eine bessere
Kosteneffizienz, nicht nur bei der Erstellung, sondern auch bei der
Pflege.  (Außerdem soll's die Teile ja am Ende wohl bis zu einem
ATiny40 geben.)

Was ich mir bei derart kleinen Controllern gut vorstellen kann ist,
dass sie einen Markt im sicherheitstechnischen Bereich haben: eine
Firmware dieser Dimension lässt sich mit brauchbarem Aufwand noch
komplett testen, mit all ihren Eventualitäten.

>> (ich glaube mich zu
>> erinnern, da mal einen indisch klingenden Namen gelesen zu haben, aber
>> nicht Anitha, die macht eher avr-libc)

> Abnikant Singh?

Ja, Abnikant.

>> Ich tu' mir vieles im Opensource-Bereich an, aber da muss ich
>> leider auch passen.  So wird es (leider) auch einigen anderen gehen,
>
> Schade eigentlich. Aber bei dir denk ich daß du ansonsten schon genug
> Projekte am Bein hast.

Ja, das ohnehin.  Außerdem darfst du nicht vergessen: ich bein kein
Informatiker, ich bin Elektronikingenieur (eigentlich Elektronik-
technologe).  Ich habe nur während meines Studiums halt auch
programmieren gelernt, weil mir schon damals klar war, dass die
fachspezifischen Computeraufgaben nur von den Fachleuten selbst gelöst
werden können, nicht etwa von Informatikern.  Von denen kann man nur
Hilfe bei Algorithmen und Werkzeugen (Compilern ;-) erwarten.

Insofern fehlen mir einfach mal einige wesentliche Grundlagen im
Hinblick auf Compiler-Architektur, und ich habe weder Zeit noch
Nerven, das nachzuholen.

> Atmel macht hier vermutlich den Fehler zu glauben, einen Entwickler
> einfach einkaufen zu können. Stattdessen muss hier auch kontinuerlich
> daran gearbeitet werden, ein eigenes Compilerteam aufzubauen und eine
> Mindestmaß an kritischer Masse zu erreichen, um
> Compilerentwicklung/anpassung sinnvoll zu machen.

Es ist wohl in einer Firma, die sich als Hardwarehersteller sieht,
nicht ganz einfach, in der Chefetage die Notwendigkeit von Kompetenz
im Softwarebereich ins Blickfeld zu rücken.  Kommt hinzu, dass AVR
historisch ja überhaupt nicht in Richtung GCC geguckt hat, sondern
sich erstmal voll auf IAR stützen wollte.  Der AVR-GCC ist eine reine
Community-Entwicklung, und es hat einige Jahre gedauert, bis Atmel
dann erkannt hat, wie viel ihnen dieses Teil an Reputation und damit
perspektivisch auch an Gewinn wirklich bringt.

> Ansonsten ist das AVR-Backend quasi tot. Anatoly ist nicht mehr aktiv
> und Andy Hutchinson seit Jahren nicht mehr gesehen. Eric fügt
> bestenfalls neue copy-paste Derivate ein und Denis beschränkt sich aufs
> Review der spärlichen Patches (immerhin!).

Denis als ursprünglicher Autor hatte sich von AVR eigentlich komplett
zurückgezogen und mittlerweile andere GCC-Backends gebastelt
(möglicherweise bezahlt, keine Ahnung).  Anatoly ist dieses Jahr Vater
geworden, und da es sein erstes Kind ist (und nicht das dritte wie bei
Eric und mir, und die gehen nun auch schon alle in die Schule ;),
schränkt das verständlicherweise sein Freizeitbudget erst einmal
kräftig ein.  Aber es soll ja da noch einen Johann-Georg geben, der
mittlerweile sehr aktiv ist. :-)  So wechseln halt die Gesichter über
die Jahre, und das ist meines Erachtens das beste Zeichen dafür, dass
es durchaus am Leben ist.

von dummy (Gast)


Lesenswert?

1
typedef union tBuffer16 {
2
  uint16_t _w;
3
  uint8_t _a[2];
4
};
5
6
#define _HI8(w) (((tBuffer16*)(&w))->_a[1])
7
#define _LO8(w) (((tBuffer16*)(&w))->_a[0])

so, gehts eigentlich in allen meinen Projekten ...

Gruss

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


Lesenswert?

dummy schrieb:

> #define _HI8(w) (((tBuffer16*)(&w))->_a[1])
> #define _LO8(w) (((tBuffer16*)(&w))->_a[0])

> so, gehts eigentlich in allen meinen Projekten ...

Glück gehabt.  Bezeichner, die mit einem Unterstrich, gefolgt von
einem Großbuchstaben beginnen, sind "reserved for the implementation".

Lass den Unterstrich lieber weg, auch wenn er dir vielleicht den
Code "professioneller" aussehen lassen mag. ;-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

dummy schrieb:
>
1
> typedef union tBuffer16 {
2
>   uint16_t _w;
3
>   uint8_t _a[2];
4
> };
5
>
>
> so, gehts eigentlich in allen meinen Projekten ...

Nicht ganz, das tBuffer16 steht an der falschen Stelle.

Richtig ist:
1
typedef union {
2
  uint16_t _w;
3
  uint8_t _a[2];
4
} tBuffer16;

Funktioniert so aber nur auf Little-Endian-Prozessoren...

Frage: Kann man "At-Compile-Time" den Endian des Prozessors (am besten 
per Preprocessor) herausfinden?

Ich habs ausprobiert für einen ATmega168 mit dem avr-gcc 4.3.3:
1
#include <inttypes.h>
2
3
#define F_CPU 8000000LU              //CPU Takt
4
5
volatile uint8_t low;
6
volatile uint8_t high;
7
volatile uint16_t word = 0x1234;
8
9
typedef union
10
{
11
  uint16_t _w;
12
  uint8_t _a[2];
13
} tBuffer16;
14
15
#define HI8(w) (((tBuffer16*)(&w))->_a[1])
16
#define LO8(w) (((tBuffer16*)(&w))->_a[0])
17
18
int main ()
19
{
20
    low = word & 0xFF;
21
    high = word >> 8;
22
    low = LO8(word);
23
    high = HI8(word);
24
}

Ergebnis:
1
int main ()
2
{
3
    low = word & 0xFF;
4
  5e:  80 91 60 00   lds  r24, 0x0060
5
  62:  90 91 61 00   lds  r25, 0x0061
6
  66:  80 93 63 00   sts  0x0063, r24
7
    high = word >> 8;
8
  6a:  80 91 60 00   lds  r24, 0x0060
9
  6e:  90 91 61 00   lds  r25, 0x0061
10
  72:  90 93 62 00   sts  0x0062, r25
11
    low = LO8(word);
12
  76:  80 91 60 00   lds  r24, 0x0060
13
  7a:  80 93 63 00   sts  0x0063, r24
14
    high = HI8(word);
15
  7e:  80 91 61 00   lds  r24, 0x0061
16
  82:  80 93 62 00   sts  0x0062, r24
17
}
18
  86:  80 e0         ldi  r24, 0x00  ; 0
19
  88:  90 e0         ldi  r25, 0x00  ; 0
20
  8a:  08 95         ret

Beim Maskieren bzw. Schieben wird tatsächlich das komplette Wort in zwei 
8-Bit-Register eingelesen, obwohl nur eines von den beiden anschließend 
genutzt wird.

Bei der Makro-Version Hi8()/LO8() entfällt jeweils der überflüssige 
Lesebefehl. Gefällt mir ganz gut, bis auf die fehlende Portabilität 
bzgl. Endian der CPU.

Gruß,

Frank

von Karl F. (kafido)


Lesenswert?

Frank M. schrieb:
> Beim Maskieren bzw. Schieben wird tatsächlich das komplette Wort in zwei
> 8-Bit-Register eingelesen, obwohl nur eines von den beiden anschließend
> genutzt wird.

Hallo Frank,

danke für's ausprobieren.

Das ist ja das, was mich so genervt hatte ...
Einerseits ist der Compiler intelligent genug, ganze Schleifen bzw. 
Variablen wegzuoptimieren - auch wenn man das manchmal gar nicht will ;)
und andererseits werden hier Register geladen, deren Inhalt nie 
gebraucht wird. Sowas müsste sich doch in einem zweiten Durchlauf 
erschlagen lassen, oder?


> Bei der Makro-Version Hi8()/LO8() entfällt jeweils der überflüssige
> Lesebefehl. Gefällt mir ganz gut, bis auf die fehlende Portabilität
> bzgl. Endian der CPU.

Gefällt mir auch gut! Sobald ich anfange bei ATmega & Co. irgendwelche 
besonderen Hardware-Ressourcen auszunutzen (Timer, ICP, usw.) hat sich 
das mit der Portabilität ohnehin ganz schnell erledigt ...

Gruß
- Karl

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Karl F. schrieb:

> Gefällt mir auch gut!

Ich habe es gerade mal mit einem realen Source aus der Praxis 
ausprobiert:
1
#include <inttypes.h>
2
3
#define F_CPU 8000000LU              //CPU Takt
4
5
typedef union
6
{
7
  uint16_t _w;
8
  uint8_t _a[2];
9
} tBuffer16;
10
11
#if 1
12
#define HI8(w) (((tBuffer16*)(&w))->_a[1])
13
#define LO8(w) (((tBuffer16*)(&w))->_a[0])
14
#else
15
#define HI8(w) ((w) >> 8)
16
#define LO8(w) ((w) & 0xFF)
17
#endif
18
19
void
20
itox (unsigned char * buf, uint8_t i)
21
{
22
    if (i < 10)
23
    {
24
        *buf = i + '0';
25
    }
26
    else
27
    {
28
        *buf = 'A' + i - 10;
29
    }
30
}
31
32
void
33
itoxx (unsigned char * buf, uint8_t i)
34
{
35
    itox (buf, (i & 0xF0) >> 4);
36
    itox (buf + 1, i & 0x0F);
37
}
38
39
void
40
itoxxxx (unsigned char * buf, uint16_t i)
41
{
42
    itoxx (buf, HI8(i));
43
    itoxx (buf + 2, LO8(i));
44
}
45
46
int main ()
47
{
48
    unsigned char buffer[4];
49
    itoxxxx (buffer, 0x1234);
50
}

Witzigerweise braucht hier die Makro-über-union-Version 16 Byte mehr als 
die Maskier-/Schiebevariante. Hier ist also das Verhältnis ungünstiger. 
Das Verhältnis bleibt auch so, wenn man die ito*-Funktionen static 
deklariert, und sie dann inline übersetzt werden. Wahrscheinlich verhält 
sich der gcc lediglich bei volatiles so ungünstig beim Low-Byte-Zugriff 
über Schieben/Maskieren. Ich hatte in meinem künstlichen Beispiel oben 
mit Absicht volatiles gewählt, um Optimierungen seitens des Compilers 
auszuschließen. Vielleicht war das eine falsche Testbedingung ;-)

Hier der Assembler-Output:

Maskieren/Schieben:
1
void
2
itoxxxx (unsigned char * buf, uint16_t i)
3
{
4
  6c:  ff 92         push  r15
5
  6e:  0f 93         push  r16
6
  70:  1f 93         push  r17
7
  72:  8c 01         movw  r16, r24
8
  74:  f6 2e         mov  r15, r22
9
  76:  67 2f         mov  r22, r23
10
    itoxx (buf, HI8(i));
11
  78:  e7 df         rcall  .-50       ; 0x48 <itoxx>
12
    itoxx (buf + 2, LO8(i));
13
  7a:  c8 01         movw  r24, r16
14
  7c:  02 96         adiw  r24, 0x02  ; 2
15
  7e:  6f 2d         mov  r22, r15
16
  80:  e3 df         rcall  .-58       ; 0x48 <itoxx>
17
}
18
  82:  1f 91         pop  r17
19
  84:  0f 91         pop  r16
20
  86:  ff 90         pop  r15
21
  88:  08 95         ret

Makros über union:
1
void
2
itoxxxx (unsigned char * buf, uint16_t i)
3
{
4
  6c:  0f 93         push  r16
5
  6e:  1f 93         push  r17
6
  70:  df 93         push  r29
7
  72:  cf 93         push  r28
8
  74:  00 d0         rcall  .+0        ; 0x76 <itoxxxx+0xa>
9
  76:  cd b7         in  r28, 0x3d  ; 61
10
  78:  de b7         in  r29, 0x3e  ; 62
11
  7a:  8c 01         movw  r16, r24
12
  7c:  7a 83         std  Y+2, r23  ; 0x02
13
  7e:  69 83         std  Y+1, r22  ; 0x01
14
    itoxx (buf, HI8(i));
15
  80:  6a 81         ldd  r22, Y+2  ; 0x02
16
  82:  e2 df         rcall  .-60       ; 0x48 <itoxx>
17
    itoxx (buf + 2, LO8(i));
18
  84:  c8 01         movw  r24, r16
19
  86:  02 96         adiw  r24, 0x02  ; 2
20
  88:  69 81         ldd  r22, Y+1  ; 0x01
21
  8a:  de df         rcall  .-68       ; 0x48 <itoxx>
22
}
23
  8c:  0f 90         pop  r0
24
  8e:  0f 90         pop  r0
25
  90:  cf 91         pop  r28
26
  92:  df 91         pop  r29
27
  94:  1f 91         pop  r17
28
  96:  0f 91         pop  r16
29
  98:  08 95         ret

Fazit: ich bleibe beim Maskieren/Schieben. Wenn der Source nicht so 
künstlich, sondern eher praxisgerecht ist, ist die portable Variante 
wohl sogar die bessere.

Gruß,

Frank

von Karl F. (kafido)


Lesenswert?

Naja, das größte Problem hab ich eigentlich bei volatiles, sprich in ISR 
Routinen wo es mitunter wirklich völlig unnötig (und störend) ist, alle 
zwei/view Bytes zu laden, wenn ich nur eines brauche.

Es geht (mir) auch nicht immer um Code-Größe, sondern öfters auch mal um 
Geschwindigkeit. Wenn der Speicher nicht reicht, nehm ich zur Not den 
nächstgrößeren AVR - wenn ich mit der Geschwindigkeit nicht hinkomme, 
muß ich auf eine ganz andere CPU umsteigen - das ist deutlich mehr 
Aufwand.

Oft ist (mir) auch reproduzierbare Geschwindigkeit wichtig. Deswegen 
hatte ich auch weiter oben geschrieben, dass mir die 10000/1000/100/10 
Subtraktionsmethode nicht so gut gefällt. Mich stört manchmal schon, 
dass alleine das Konstrukt if/else je nach Bedingung einen Takt mehr 
oder weniger braucht - das kann man aber leicht mit einem asm("nop") 
wieder grade biegen.

Ich muß mich wohl noch mehr mit inline Assembler beschäftigen.
Assembler kann ich. C auch. Aber beim inline-Assembler tut der
Compiler nicht immer so ganz das, was ich gerne hätte :-/

naja ... dies ist ja ein recht langer Thread geworden, obwohl es 
eigentlich nur um den direkten Zugriff auf ein Byte ging ;-)

Danke an alle, die mitgegrübelt haben - scheint ja alles nicht so 
einfach zu sein.

Gruß
- Karl

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl F. schrieb:
> Naja, das größte Problem hab ich eigentlich bei volatiles, sprich in ISR
> Routinen wo es mitunter wirklich völlig unnötig (und störend) ist, alle
> zwei/view Bytes zu laden, wenn ich nur eines brauche.

Sowas darf der Compiler garnicht "optimieren", weil es die 
volatile-Korrektheit zerstören würde.

von Volkmar D. (volkmar)


Lesenswert?

Auch wenn zwischenzeitlich ähnliches geschrieben wurde, hier noch mein 
'Senf' dazu:

Frank M. schrieb:
> Ich habs ausprobiert für einen ATmega168 mit dem avr-gcc 4.3.3:
...
1
> typedef union
2
> {
3
>   uint16_t _w;
4
>   uint8_t _a[2];
5
> } tBuffer16;
6
> 
7
> #define HI8(w) (((tBuffer16*)(&w))->_a[1])
8
> #define LO8(w) (((tBuffer16*)(&w))->_a[0])

Ich habe es eben mal in mein Projekt eingesetzt und kam leider zu einem 
negativen Ergebnis, zumindest an der Stelle, an der ich direkt ein 
Rechenergebnis verwenden wollte:
1
out_pwm_ptr->option |= HI8(max_delay * rnd()) & DELAY_MASK;
Das gibt schon mal eine Fehlermeldung, es wird eine Variable als 
Parameter für HI8() benötigt, und kein Ausdruck.

Aber selbst
1
uint16_t temp = max_delay * rnd();
2
out_pwm_ptr->option |= HI8(temp) & DELAY_MASK;
bringt kein optimales Ergebnis, es benötigt 14 Bytes mehr als das 
Anfangs erwähnte Union-Konstrukt, das ich üblicherweise in solchen 
Fällen verwende.

Was bei mir alternativ zu dem Union-Konstrukt auch klappt:
1
typedef union
2
{
3
  uint16_t _w;
4
  uint8_t _a[2];
5
} tBuffer16;
6
7
static inline uint8_t LO8(uint16_t) __attribute__((always_inline));
8
static inline uint8_t HI8(uint16_t) __attribute__((always_inline));
9
10
uint8_t LO8(uint16_t w) {
11
  tBuffer16 temp;
12
  temp._w = w;
13
  return temp._a[0];
14
}
15
16
uint8_t HI8(uint16_t w) {
17
  tBuffer16 temp;
18
  temp._w = w;
19
  return temp._a[1];
20
}
und dann
1
uint16_t temp = max_delay * rnd();
2
out_pwm_ptr->option |= HI8(temp) & DELAY_MASK;
Wenn ich den Ausdruck ins HI8() reinziehe, gibt es zwar keine 
Fehlermeldung, der Compiler benötigt aber insgesamt 2 Byte mehr (wobei 
mir auf die Schnelle nicht klar geworden ist, wo er die benötigt).

Volkmar

von Peter (Gast)


Lesenswert?

@Frank M. (ukw) Benutzerseite

>Beim Maskieren bzw. Schieben wird tatsächlich das komplette Wort in zwei
>8-Bit-Register eingelesen, obwohl nur eines von den beiden anschließend
>genutzt wird.

Das ist auch richtig so, der Compiler tut genau das, wass er nach 
Konvention auch tun soll: Die Variable "word" und der direkte Zahlenwert 
"0xFF" werden als integer behandelt (beim AVR 16Bit)

Konsequentes Casting auf 8 Bit sollte aber das Problem lösen, aber 
natürlich wäre es schöner, wenn der Optimizer diese Fälle selber 
optimieren würde...
1
#include <inttypes.h>
2
3
#define F_CPU 8000000LU              //CPU Takt
4
5
volatile uint8_t low;
6
volatile uint8_t high;
7
volatile uint16_t word = 0x1234;
8
9
typedef union
10
{
11
  uint16_t _w;
12
  uint8_t _a[2];
13
} tBuffer16;
14
15
#define HI8(w) (((tBuffer16*)(&w))->_a[1])
16
#define LO8(w) (((tBuffer16*)(&w))->_a[0])
17
18
int main ()
19
{
20
    low = (uint8_t)word & (uint8_t)0xFF;
21
    high = (uint8_t)word >> 8;
22
}

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter schrieb:
> Das ist auch richtig so, der Compiler tut genau das, wass er nach
> Konvention auch tun soll: Die Variable "word" und der direkte Zahlenwert
> "0xFF" werden als integer behandelt (beim AVR 16Bit)

Ja, natürlich. Zumindest beim Schieben um 8 Bit nach rechts muss er 
"word" als Integer behandeln. Aber er braucht den Low-Wert von "word" 
dafür nicht extra in einem Register ablegen. Naja, ob er das bei einer 
volatile-Variable trotz Nichtgebrauch machen soll, darüber lässt sich 
trefflich streiten :-)

>     low = (uint8_t)word & (uint8_t)0xFF;

Deine Casts hier sind unnötig, da kannst Du auch direkt

      low = word;

schreiben. Es kommt auch derselbe Assembler-Output raus. Der Compiler 
muss einen 16-Bit-Wert in einen 8-Bit-Variable quetschen. Er macht genau 
dasselbe mit und ohne Maskierung und Cast.

>     high = (uint8_t)word >> 8;

Dein Cast hier ist falsch! Wenn Du einen 8-Bit-Wert (durch Deinen Cast) 
um 8 Bit nach rechts schiebst, kommt immer 0 raus ;-)

Beweis:

    high = (uint8_t)word >> 8;
  6a:  80 91 60 00   lds  r24, 0x0060
  6e:  90 91 61 00   lds  r25, 0x0061
  72:  10 92 62 00   sts  0x0062, r1

"word" wird nach r24/r25 geladen und anschließend wird in "high" das 
Register r1 (was wohl 0 ist) gespeichert.

Auch hier wird die volatile-Variable "word" geladen, obwohl sie danach 
komplett ignoriert wird.

Gruß,

Frank

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Sowas darf der Compiler garnicht "optimieren", weil es die
> volatile-Korrektheit zerstören würde.

Das sehe ich anders. Ich kann nicht erkennen, warum ein unnötiges Laden 
des Highbyte in ein Register bei

    low = word >> 8;

die "volatile-Korrektheit" mehr erhält als wenn er dieses unterlassen 
würde. Bei der union-Variante lädt er das Highbyte ja auch nicht.

Zur Erinnerung:
1
    high = word >> 8;
2
  6a:  80 91 60 00   lds  r24, 0x0060
3
  6e:  90 91 61 00   lds  r25, 0x0061
4
  72:  90 93 62 00   sts  0x0062, r25
5
6
    high = HI8(word);
7
  7e:  80 91 61 00   lds  r24, 0x0061
8
  82:  80 93 62 00   sts  0x0062, r24

Meines Erachtens ist der Befehl an der Stelle 6a: hyperfluid - egal, ob 
volatile oder nicht.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Hier noch ein anschaulicher Knüller:
1
#include <inttypes.h>
2
3
volatile uint8_t low;
4
volatile uint32_t longword = 0x12345678;
5
6
int main ()
7
{
8
    low = longword >> 24;
9
}

Ergebnis:
1
int main ()
2
{
3
    low = longword >> 24;
4
  5e:  80 91 60 00   lds  r24, 0x0060
5
  62:  90 91 61 00   lds  r25, 0x0061
6
  66:  a0 91 62 00   lds  r26, 0x0062
7
  6a:  b0 91 63 00   lds  r27, 0x0063
8
  6e:  8b 2f         mov  r24, r27
9
  70:  99 27         eor  r25, r25
10
  72:  aa 27         eor  r26, r26
11
  74:  bb 27         eor  r27, r27
12
  76:  80 93 64 00   sts  0x0064, r24
13
}
14
  7a:  80 e0         ldi  r24, 0x00  ; 0
15
  7c:  90 e0         ldi  r25, 0x00  ; 0
16
  7e:  08 95         ret

Es werden hier also alle 4 Byte von "longword" in Register geladen. 
Anschließend wird das Register, welches das oberste Byte beherbergt, in 
ein 5. Register umgeladen, danach werden die anderen 3 Register 
gelöscht(!) und letztendlich wird das Register r24 dann in low 
gespeichert. Das könnte man reduzieren auf 2 Zeilen:
1
  lds  r24, 0x0063
2
  sts  0x0064, r24

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


Lesenswert?

Frank M. schrieb:
> Das sehe ich anders. Ich kann nicht erkennen, warum ein unnötiges Laden
> des Highbyte in ein Register bei
>
>     low = word >> 8;
>
> die "volatile-Korrektheit" mehr erhält als wenn er dieses unterlassen
> würde.

Wenn "word" volatile markiert ist, dann zwingst du damit den
Compiler, es auf jeden Fall komplett zu lesen, mit allen Bits,
egal, ob sie danach gebraucht werden oder nicht.  Denn volatile
besagt ja genau das: "Tu, was ich dir hingeschrieben habe, egal
ob du denkst, dass das nützlich ist."

> Bei der union-Variante lädt er das Highbyte ja auch nicht.

Weil dort dein Typecast-Gewurschtel dem Compiler exakt sagt, dass
er nur 8 bit davon lesen soll.

Frank M. schrieb:
> Es werden hier also alle 4 Byte von "longword" in Register geladen.

Der "Knüller" daran ist nur, dass du offenbar die Semantik hinter
volatile einfach nicht verstanden hast.  Du kannst nicht mit volatile
die Optimierung unterdrücken und dich anschließend drüber aufregen,
dass er nicht optimiert.

von (prx) A. K. (prx)


Lesenswert?

Frank M. schrieb:

> Das sehe ich anders. Ich kann nicht erkennen, warum ein unnötiges Laden
> des Highbyte in ein Register bei

Denk beispielsweise an I/O-Register, bei denen der Lesevorgang selbst 
schon was auslöst, wie bei den 16-Bit Timern vom AVR. Wenn du da den 
ersten der beiden Ladebefehle weglässt, dann liest der zweite Ladebefehl 
Unsinn.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Wenn "word" volatile markiert ist, dann zwingst du damit den
> Compiler, es auf jeden Fall komplett zu lesen, mit allen Bits,
> egal, ob sie danach gebraucht werden oder nicht.  Denn volatile
> besagt ja genau das: "Tu, was ich dir hingeschrieben habe, egal
> ob du denkst, dass das nützlich ist."

Dann habe ich "volatile" bisher falsch verstanden. Ich dachte bisher, 
ich sage damit dem Compiler:

"Der Wert dieser Variablen kann sich während der Verarbeitung ändern. Du 
musst ihn also immer neu lesen und darfst ihn nicht (über Register) 
cachen".

Danke, da habe ich wieder etwas dazugelernt :-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

A. K. schrieb:
> Denk beispielsweise an I/O-Register, bei denen der Lesevorgang selbst
> schon was auslöst, wie bei den 16-Bit Timern vom AVR. Wenn du da den
> ersten der beiden Ladebefehle weglässt, dann liest der zweite Ladebefehl
> Unsinn.

Vielen Dank für das plastische Beispiel des I/O-Registers. Das hat mich 
endgültig überzeugt.

Bisher konnte ich mir einfach kein Szenario vorstellen, wie die 
Daten-Integrität eines volatiles verletzt werden könnte, wenn man auf 
das Lesen einzelner Bytes desselben verzichtet. Klar, bei einem 
I/O-Register wäre das u.U. fatal.

Man lernt nie aus :-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Sorry, ich muss jetzt doch noch mal quengeln ;-)

Ich habe jetzt alle volatiles entfernt. Leider werden immer noch alle 
Bytes der 32-Bit-Variablen gelesen, obwohl sie nicht genutzt werden.

Code:
1
#include <inttypes.h>
2
3
uint8_t     low;
4
uint32_t    longword = 0x12345678;
5
6
uint8_t     low2;
7
uint32_t    longword2 = 0x12345678;
8
9
typedef union
10
{
11
  uint16_t _w;
12
  uint8_t _a[4];
13
} tBuffer32;
14
15
#define HI8L(lw) (((tBuffer32*)(&lw))->_a[3])
16
17
int main ()
18
{
19
    low = HI8L(longword);
20
    low2 = longword2 >> 24;
21
}

Ergebnis:
1
int main ()
2
{
3
    low = HI8L(longword);
4
  5e:  80 91 63 00   lds  r24, 0x0063
5
  62:  80 93 68 00   sts  0x0068, r24
6
    low2 = longword2 >> 24;
7
  66:  80 91 64 00   lds  r24, 0x0064
8
  6a:  90 91 65 00   lds  r25, 0x0065
9
  6e:  a0 91 66 00   lds  r26, 0x0066
10
  72:  b0 91 67 00   lds  r27, 0x0067
11
  76:  8b 2f         mov  r24, r27
12
  78:  99 27         eor  r25, r25
13
  7a:  aa 27         eor  r26, r26
14
  7c:  bb 27         eor  r27, r27
15
  7e:  80 93 69 00   sts  0x0069, r24
16
}
17
  82:  80 e0         ldi  r24, 0x00  ; 0
18
  84:  90 e0         ldi  r25, 0x00  ; 0
19
  86:  08 95         ret

Das Makro machts also in 2 Zeilen (wie eigentlich erwartet), der Shift 
braucht unverändert dafür 9 Zeilen - auch ohne volatile.

Ich schiebe das jetzt mal auf die schlechte Unterstützung des gcc von 
8-Bit-Prozessoren.... und finde mich damit ab :-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Sorry, ich muss jetzt doch noch mal quengeln ;-)
>
> Ich habe jetzt alle volatiles entfernt. Leider werden immer noch alle
> Bytes der 32-Bit-Variablen gelesen, obwohl sie nicht genutzt werden.

Also mein avr-gcc macht die Zugriffe kurz:
1
extern char c;
2
extern unsigned long l;
3
4
void shift24 (void)
5
{
6
    c = l >> 24;
7
}
8
9
void shift16 (void)
10
{
11
    c = l >> 16;
12
}
13
14
char rshift24 (void)
15
{
16
    return l >> 24;
17
}
18
19
void shift25 (void)
20
{
21
    c = l >> 25;
22
}

Wird mit avr-gcc-4.6.1 -S -Os zu
1
shift24:
2
  lds r24,l+3
3
  sts c,r24
4
  ret
5
6
shift16:
7
  lds r24,l+2
8
  sts c,r24
9
  ret
10
11
rshift24:
12
  lds r24,l+3
13
  ret

> Ich schiebe das jetzt mal auf die schlechte Unterstützung des gcc von
> 8-Bit-Prozessoren.... und finde mich damit ab :-)

No, eher auf eine atwas angestaubte avr-gcc Version. Im avr-Backend 
gibt's dafür keine Zauberei, es wird alles im maschinenunabhängigen Teil 
erledigt.

Wenn allerdings nicht auf einzelne Bytes zugegriffen wird, wie das bei 
shift25() der Fall ist, wird's länglich: Laden, Shiften, Speichern; fein 
säuberlich getrennt:
1
shift25:
2
  lds r24,l
3
  lds r25,l+1
4
  lds r26,l+2
5
  lds r27,l+3
6
  ldi r18,25
7
1:  lsr r27
8
  ror r26
9
  ror r25
10
  ror r24
11
  dec r18
12
  brne 1b
13
  sts c,r24
14
  ret

Wer das im avr-Backend (oder sonstwo in GCC) smarter machen will, kann 
es gerne tun. Mir ist das Feld zu schwierig, und mit meinem momentanen 
Wissensstand über GCC und Zeit, die ich in der Lage bin, darin zu 
investieren, werde ich es nicht anfassen.

Vor einiger Zeit gab es einen ähnlich gelagerten Optimierungsfall ohne 
Shift; was daraus geworden ist, weiß ich nicht. Wahrscheinlich nix.
  http://lists.gnu.org/archive/html/avr-gcc-list/2011-05/msg00001.html

Und für 16-Bit Linksshifts, von denen der High-Teil nicht verwendet 
wird, hat's immerhin 4½ Jahre gebraucht...

http://gcc.gnu.org/PR29560

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Also mein avr-gcc macht die Zugriffe kurz:
> [...]
> Wird mit avr-gcc-4.6.1 -S -Os zu
> [...]

Gibt es eine einfache Möglichkeit, den avr-gcc-4.6.1 mit dem AVR Studio 
4 für Windows zu verheiraten?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Johann L. schrieb:
>> bzw. was
>> sie/jemand mit diesem Silizium [ATtiny] + GCC will.
>
> Naja, auch dort hast du bei einer Produktentwicklung in C eine bessere
> Kosteneffizienz, nicht nur bei der Erstellung, sondern auch bei der
> Pflege.  (Außerdem soll's die Teile ja am Ende wohl bis zu einem
> ATtiny40 geben.)
>
> Was ich mir bei derart kleinen Controllern gut vorstellen kann ist,
> dass sie einen Markt im sicherheitstechnischen Bereich haben: eine
> Firmware dieser Dimension lässt sich mit brauchbarem Aufwand noch
> komplett testen, mit all ihren Eventualitäten.

Gibt für größere AVRs oder andere µC aber ebenso; ein Programm wird ja 
nicht deshalb besser statisch analysierbar, daß man das Silizium bis zur 
Unkenntlichkeit eindampft. Ich tippe eher auf Billigkram auf China wo's 
auf 1/100 Cent ankommt.

Für Sicherheitstechnik fürde ich auch nicht einen neuen Core einsetzen 
sondern einen, wo man sich halbwegs sicher sein kann, daß alle 
Silicon-Bugs bekannt sind. Zudem evtl. Radiation Hardening oder was auch 
immer und in dem Bereich wird eh nicht so gebitpopelt, zB keine 
Optmiierung im Compiler erlaubt, etc.

>>> Ich tu' mir vieles im Opensource-Bereich an, aber da muss ich
>>> leider auch passen.  So wird es (leider) auch einigen anderen gehen,
>>
>> Schade eigentlich. Aber bei dir denk ich daß du ansonsten schon genug
>> Projekte am Bein hast.
>
> Ja, das ohnehin.  Außerdem darfst du nicht vergessen: ich bein /kein/
> Informatiker, ich bin Elektronikingenieur (eigentlich Elektronik-
> technologe).

Informatiker bin ich auch nicht, ich komm von der Algebraische 
Zahlentheorie her.

> Insofern fehlen mir einfach mal einige wesentliche Grundlagen im
> Hinblick auf Compiler-Architektur, und ich habe weder Zeit noch
> Nerven, das nachzuholen.

Davon muss man zum Glück nicht viel wissen, wenn man nur ein Backend 
etaw aufpolieren möchte. Zazu muss man nicht im Gedärm von GCC 
rumrühren.

>> Atmel macht hier vermutlich den Fehler zu glauben, einen Entwickler
>> einfach einkaufen zu können. Stattdessen muss hier auch kontinuerlich
>> daran gearbeitet werden, ein eigenes Compilerteam aufzubauen und eine
>> Mindestmaß an kritischer Masse zu erreichen, um
>> Compilerentwicklung/anpassung sinnvoll zu machen.
>
> Es ist wohl in einer Firma, die sich als Hardwarehersteller sieht,
> nicht ganz einfach, in der Chefetage die Notwendigkeit von Kompetenz
> im Softwarebereich ins Blickfeld zu rücken.  Kommt hinzu, dass AVR
> historisch ja überhaupt nicht in Richtung GCC geguckt hat, sondern
> sich erstmal voll auf IAR stützen wollte [...], und es hat einige
> Jahre gedauert, bis Atmel dann erkannt hat, wie viel ihnen dieses
> Teil an Reputation und damit perspektivisch auch an Gewinn wirklich
> bringt.

Hätten sie besser mal Wikipedia gelesen ;-)
1
GCC has been ported to a wide variety of processor architectures, and
2
is widely deployed as a tool in commercial, proprietary and closed
3
source software development environments. GCC is also available for
4
most embedded platforms, for example [...] The compiler can target a
5
wide variety of platforms, including [...]. Several companies make a
6
business out of supplying and supporting GCC ports to various
7
platforms, and chip manufacturers today consider a GCC port almost
8
essential to the success of an architecture.

> Der AVR-GCC ist eine reine Community-Entwicklung

Keine Ahnung, wer was warum macht im GCC. Jedenfalls gehort einiges 
dazu, gcc für ein neues Target anzupassen, als Hobby hat Denis das 
garantiert nicht gemacht.

Übrigens ist avr-gcc bereits über 11 Jahre alt. Das avr-Backend wurde am 
11. Februar 2000 eingespielt, allerdings noch als Frau ohne Unterleib; 
letzerer kam dann am 16. Februar hinzu:

http://gcc.gnu.org/viewcvs?view=revision&revision=31935
http://gcc.gnu.org/viewcvs?view=revision&revision=32002

>> Ansonsten ist das AVR-Backend quasi tot. Anatoly ist nicht mehr aktiv
>> und Andy Hutchinson seit Jahren nicht mehr gesehen. Eric fügt
>> bestenfalls neue copy-paste Derivate ein und Denis beschränkt sich aufs
>> Review der spärlichen Patches (immerhin!).
>
> Denis als ursprünglicher Autor hatte sich von AVR eigentlich komplett
> zurückgezogen und mittlerweile andere GCC-Backends gebastelt
> (möglicherweise bezahlt, keine Ahnung).

Weißt du für welche Maschine(n)? Würd mich interessieren. Ansonsten ist 
Klatsch und Tratsch nicht so mein Metier :-)

> Aber es soll ja da noch einen Johann-Georg geben, der mittlerweile
> sehr aktiv ist. :-)  So wechseln halt die Gesichter über die Jahre,
> und das ist meines Erachtens das beste Zeichen dafür, dass es durchaus
> am Leben ist.

Naja, das ist Tropfen auf den heißen Stein, die wirklichen Nüsse sind so 
nicht zu knacken. Das würde locker eine volle Stelle abgeben.

Adacore mischt doch bei avr/gcc mit (GNAT etc.), warum versucht's Atmel 
nicht mal bei denen...?

Frank M. schrieb:
> AVR Studio
¿¿¿ Was ist AVR Studio???

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Johann L. schrieb:

> Ok... hab's mit mal im Detail angeschaut für folgenden Code (modulo
> Tippfehler):
1
>#define umul_hi(a,b) \
2
> ({ uint8_t _c; \
3
>    asm ("mul %1, %2"  "\n\t"\
4
>         "mov %0, R1"  "\n\t"\
5
>         "clr __zero_reg__"\
6
>         : "=r" (_c) : "r" ((char) a), "r" ((char) b));\
7
>         _c;})
8
...
9
>  #define umul_hi(a,b) \
10
>   ({ uint8_t _a=a, _b=b; \
11
>      uint8_t _c=_a*_b; _c;})
12
>  #endif

Muss natürlich heissen
1
#define umul_hi(a,b) \
2
 ({ uint8_t _c, _a=(a), _b=(b); \
3
    asm ("mul %1, %2"  "\n\t"\
4
         "mov %0, R1"  "\n\t"\
5
         "clr __zero_reg__"\
6
         : "=r" (_c) : "r" ((char) _a), "r" ((char) _b));\
7
         _c;})
8
...
9
#define umul_hi(a,b) \
10
 ({ uint8_t _a=a, _b=b; \
11
    uint16_t _c=_a*_b; _a=_c>>8; _a;})
12
#endif
Warum sagt denn keiner was? ;-)

Damit ist die Zeitmessung Makulatur, also nochmal:

avr-gcc -Os -mmcu=atmega8 (Größe in Bytes)
1
         Asm    ohne Asm
2
3.4.6    254    214
3
4.2.2    290    244
4
4.3.3    260    226
5
4.5.2    206    176
6
4.6.1    186    160

Irgendwie kann ich diese Ergebnisse nicht ganz glauben, bzw. daß es so 
große Unterschiede zwischen den Compiler-Versionen gibt und daß 
Inline-Assembler das Resultat verschlechtert (vermultich weil kein CSE 
mehr möglich ist. Hier stirbt gerade eine Legende ;-)

... 4.3 zeigt eine nicht gerade überzeugende Registeralliokierung, da 
ist 4.5 merklich besser, allerdings stolpert der über fake X-addressing 
(PR46278). 4.6 sieht brauchbar aus. Das Ergebnis für 4.3 im Vergleich 
mit 3.4 ist plausibel: 3.4 war keine schlechte Version, allerdings kann 
er noch kein SSA und macht viele Operationen unnötigerweise als int – 
liegt aber dennoch vor 4.3.

Was 4.7 so treibt, danach schau ich mal die Tage.  Momentan ist eine 
Optimierung in der Mache, die nochmals ein paar Bytes/Ticks soll.

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


Lesenswert?

Johann L. schrieb:

> Gibt für größere AVRs oder andere µC aber ebenso; ein Programm wird ja
> nicht deshalb besser statisch analysierbar, daß man das Silizium bis zur
> Unkenntlichkeit eindampft.

Nein, aber dadurch, dass es insgesamt klein bleibt.  Wenn man aber
sowieso klein bleiben muss für eine bestimmte Aufgabe, dann kann
man auch das Silizium klein machen und damit billig.

> Ich tippe eher auf Billigkram auf China wo's
> auf 1/100 Cent ankommt.

Nicht nur in China wird billig gebaut. ;-)

> Hätten sie besser mal Wikipedia gelesen ;-)

Gab's damals noch nicht. ;-)

>> Der AVR-GCC ist eine reine Community-Entwicklung
>
> Keine Ahnung, wer was warum macht im GCC. Jedenfalls gehort einiges
> dazu, gcc für ein neues Target anzupassen, als Hobby hat Denis das
> garantiert nicht gemacht.

Da hab' ich keine Ahnung.  Von Anatoly kann ich dir mit Sicherheit
sagen, dass er das nur als Hobby gemacht hat, denn mit ihm habe ich
mich schon unterhalten können (so gut wie's geht: er kann zwar
Englisch lesen und schreiben, aber nur mit Wörterbuch, sodass wir
uns für die mündliche Kommunikation weitgehend auf mein ziemlich
rostiges Russisch stützen mussten ;-).  Bei Marek Michalkiewicz
bin ich mir auch einigermaßen sicher, dass er das damals alles als
studentisches Freizeitprojekt gemacht hat.  Nach dem Studium ist er
dann zu Intel und hat sich aufgrund irgendwelcher Klauseln in seinem
Arbeitsvertrag dann lieber aus der Opensource-Welt zurückgezogen.

> Übrigens ist avr-gcc bereits über 11 Jahre alt.

Ja, ohne das genaue Datum zu kennen, hatte ich das so ungefähr im
Gefühl.  Ich habe Ende des Jahres nach langer Abstinenz in diesem
Bereich ein Controller-Projekt mit einem PIC gemacht.  Das war,
nach all den vielen Jahren, die ich zuvor in C, C++ oder Skript-
sprachen programmiert habe, so frustrierend, den Assemblerhaufen
zum Spielen zu bekommen, dass ich mir vorgenommen habe, dass mein
nächster Controller einer mit einem C-Compiler sein wird.  Aufgrund
weiterer Randbedingungen (sollte nach Möglichkeit Opensource sein,
Pflichtforderung war Lauffähigkeit auf FreeBSD) bin ich dann beim
AVR mit seinem noch vergleichsweise jungen Port von GCC, binutils
(immerhin schon, davor wurde ja nur mit AVRa assembliert) und den
Anfängen der avr-libc gelandet.

>> Denis als ursprünglicher Autor hatte sich von AVR eigentlich komplett
>> zurückgezogen und mittlerweile andere GCC-Backends gebastelt
>> (möglicherweise bezahlt, keine Ahnung).
>
> Weißt du für welche Maschine(n)?

Hab' ich vergessen.  Wenn man jetzt nach seinem Namen gugelt, scheint
er vor allem bei OpenERP zugange zu sein.

von Frank M. (ukw) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Johann L. schrieb:
> Frank M. schrieb:
>> AVR Studio
> ¿¿¿ Was ist AVR Studio???

Die IDE von ATMEL, in welcher standardmäßig avr-gcc 4.3.3 verwendet 
wird.

von Oliver (Gast)


Lesenswert?

Frank M. schrieb:
> Johann L. schrieb:
>> Frank M. schrieb:
>>> AVR Studio
>> ¿¿¿ Was ist AVR Studio???
>
> Die IDE von ATMEL, in welcher standardmäßig avr-gcc 4.3.3 verwendet
> wird.

Na ja, erstens weiß der Johann das, und zweitens ist die Antoert in 
Bezug auf das Studio 4 falsch. Das Studio 4 ist völlig unabhängig von 
irgend einem avr-gcc. Das ruft lediglich über ein plugin den avr-gcc, 
der gerade auf dem System installiert ist, auf. Die Compilerveriosn ist 
dem Studio 4 egal.

Oliver

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Oliver schrieb:
> Na ja, erstens weiß der Johann das,

Das hab ich befürchtet. Angesichts der multiplen Fragezeichen von Johann 
war ich dann aber doch etwas verunsichert. Offenbar waren das versteckte 
Ironie-Tags ;-)

> und zweitens ist die Antoert in
> Bezug auf das Studio 4 falsch. Das Studio 4 ist völlig unabhängig von
> irgend einem avr-gcc. Das ruft lediglich über ein plugin den avr-gcc,
> der gerade auf dem System installiert ist, auf. Die Compilerveriosn ist
> dem Studio 4 egal.

Das dachte ich mir bereits. Damit reduziert sich meine ursprüngliche 
Frage auf die unausgesprochenen Worte: Wo bekomme ich den avr-gcc-4.6.1 
für Windows her? Auf Sourceforge finde ich nur einen WinAVR vom 
20.01.2010. Das ist aber meines Wissens nach die gcc-Version 4.3.3, die 
ich schon habe.

Gruß,

Frank

Edit:

Habs gefunden: Beitrag "avr-gcc 4.6.1 für Windows"

Danke

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


Lesenswert?

Frank M. schrieb:
> Wo bekomme ich den avr-gcc-4.6.1
> für Windows her?

Wahrscheinlich da, wo Johann seine Version auch herbekommen hat: aus
dem Quellcode.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Wahrscheinlich da, wo Johann seine Version auch herbekommen hat: aus
> dem Quellcode.

Danke, das weiß ich auch ;-) Bereits 1985 habe ich den gcc als 
CrossCompiler für VME-Bus-Systeme ohne jegliches Betriebssystem auf 
UNIX-System-V-Rechner portiert. Wie das geht, weiß ich also auch. Aber 
es ist Arbeit ;-)

Und im fortgeschrittenen Alter wird man da etwas "fauler" und schaut 
erstmal, ob es nicht schon einer gemacht hat. Daher meine Frage. Ich bin 
auch unter

  Beitrag "avr-gcc 4.6.1 für Windows"

fündig geworden. Mittlerweile habe ich den avr-gcc-4.6.1 laufen und 
direkt erste Tests gemacht: Johann hat recht, der "neue" gcc reduziert 
tatsächlich die byteweisen Shifts auf 2 Befehle. Sehr schön. Schade, 
dass avr-size wegen -C noch nicht funktioniert. So hätte ich direkt mal 
fertige AVR-Projekte von der Größe her vergleichen können.

So warte ich jetzt ungeduldig auf den avr-gcc-4.6.2, welcher dann wohl 
als nächste WinAVR-Version rauskommen soll - so wie ich das verstanden 
habe.

Vielen Dank an Johann.

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


Lesenswert?

Frank M. schrieb:
> Schade,
> dass avr-size wegen -C noch nicht funktioniert.

Dann lass das blöde -C weg.  Nimm die Standardeinstellung, und
vergleich die paar Zahlen im Kopf.  Ich fand diesen Hack von Eric
schon immer gruselig, vor allem deshalb, weil er absolut keine
Chance hat, jemals seinen Weg in die binutils zu finden.

von Johann L. (gjlayde) Benutzerseite


Angehängte Dateien:

Lesenswert?

Johann L. schrieb:
> avr-gcc -Os -mmcu=atmega8 (Größe in Bytes)
1
>          Asm    ohne Asm
2
> 4.6.1    186    160

hmmm. ich hab das mal mit einem nativ generierten avr-gcc-4.6.2-exp 
erzeugt (oben ist -rc1), dafür bekomme ich
1
           Asm    ohne Asm
2
 4.6.1-rc1 186    160
3
 4.6.2-exp 186    190
4
 4.7.0-exp 184    190
Das -exp steht füht "experimental" und -rc für "release candidate". 
Irgendwas scheint im 4.6 faul zu sein.

Frank M. schrieb:
>   Beitrag "avr-gcc 4.6.1 für Windows"

Das ist nur eine prerelease zu Rumspielen und dafür, sich den Compiler 
vor der geplanten WinAVR-Release mal näher betrachten zu begutachten zu 
können. Die "Release Notes" stehen in dem Link zu avr-freaks.

Inzwischen wurde schon einige Fehler behoben, siehe avr-gcc Bugs im 
Wiki.

Frank M. schrieb:
> Mittlerweile habe ich den avr-gcc-4.6.1 laufen

Macht er wenigstens, was er soll? Der Unterschied 160 (die Version -rc1, 
die du hast) und -exp dürften eigentlich kein Unterschied zeigen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Das ist nur eine prerelease zu Rumspielen und dafür, sich den Compiler
> vor der geplanten WinAVR-Release mal näher betrachten zu begutachten zu
> können. Die "Release Notes" stehen in dem Link zu avr-freaks.

Ja, ich hatte gelesen, dass es sich um eine RC1 handelte.

> Macht er wenigstens, was er soll? Der Unterschied 160 (die Version -rc1,
> die du hast) und -exp dürften eigentlich kein Unterschied zeigen.

Ich hatte es nur mal angetestet mit den obigen Codebeispielen. Ich werde 
in den nächsten Tagen mal einige Projekte (IRMP, SOUNDRX, MCURSES) mit 
dem avr-gcc-4.6.1 übersetzen und durchchecken. Kann aber etwas dauern, 
bis ich dazu komme.

Gruß,

Frank

von Johann L. (gjlayde) Benutzerseite


Angehängte Dateien:

Lesenswert?

Johann L. schrieb:
1
>            Asm    ohne Asm
2
>  4.6.1-rc1 186    160
3
>  4.6.2-exp 186    190
4
>  4.7.0-exp 184    190
War wohl nur der Tipp-Teufel: avr-gcc-4.6.1-rc1 bringt ebenfalls 190 
Bytes ohne Asm. Hier nochmal die komplette Liste ohne Tippos:
1
            Asm    ohne Asm
2
3.4.6       254    274
3
4.2.2       290    296
4
4.3.3       260    264
5
4.5.2       206    214
6
4.6.1       186    190
7
4.7.0-exp   184    190
Und anbei die Quelle, die ich verwendete, einmal mit -Os -mmcu=avr4 
-DX=0 (ihne Asm) und einmal mit -Os -mmcu=avr4 -DX=1 (mit Asm).

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.