Forum: Compiler & IDEs Verschiedene Bits effizient auslesen


von Michael K. (damichl)


Lesenswert?

Hallo nochmal,

ich habe da noch ein kleines Problem.

Gegeben eine 40-Bit-Variable. Von der möchte ich nun z.B. die Bits 
0,3,6,14,27,38 in eine neue Variable übernehmen.
Natürlich könnte man das jetzt hin- und hershiften und die Bits mit UND 
auslesen. Da ich das ganze aber ca. 20 mal machen muss, stellt sich die 
Frage, ob man das nicht irgendwie einfacher bzw. effizienter machen 
könnte.

Falls jemand eine Idee hat wäre ich sehr dankbar.

mfg

Michael

von (prx) A. K. (prx)


Lesenswert?

Es hängt auch etwas vom Prozessor ab, welcher Weg effizient ist.

von DirkB (Gast)


Lesenswert?

Wie groß soll denn die neue Variable sein? 8, 16, 32 oder auch 40 Bit?

von Michaelk (Gast)


Lesenswert?

Die Ergebnisvariable hat immer 10 Bit.

von (prx) A. K. (prx)


Lesenswert?

Es hängt auch etwas davon ab, ob es immer die gleichen Bits sind, oder 
ob die Liste der Bits sich ändert.

von Karl H. (kbuchegg)


Lesenswert?

Michael K. schrieb:
> Hallo nochmal,
>
> ich habe da noch ein kleines Problem.
>
> Gegeben eine 40-Bit-Variable. Von der möchte ich nun z.B. die Bits
> 0,3,6,14,27,38 in eine neue Variable übernehmen.
> Natürlich könnte man das jetzt hin- und hershiften und die Bits mit UND
> auslesen.

Da würde ich nicht lange Shiften, sondern ganz einfach abfragen ob das 
jeweilige Bits gesetzt ist und wenn ja, dann in der Zielvariablen 
ebenfalls das entsprechende Bit setzen.

    targe = 0;

    if( source & ( 1 << 0 )
      target |= 0x01;

    if( source & ( 1 << 3 )
      target |= 0x02;

    if( source & ( 1 << 6 )
      target |= 0x04;

von Michael K. (damichl)


Lesenswert?

Danke. So ist es wirklich einfacher.
Ich nutze jetzt die Gelegenheit einfach mal und frage,
was es mit dieser Notation auf sich hat.

Mit ( 1 << 0 ) schiebe ich eine 1 an das 0. Bit. Kann man sich das so 
wie eine imaginäre Vergleichsvariable vorstellen?


mfg

Michael

von Rolf Magnus (Gast)


Lesenswert?

Michael K. schrieb:
> Danke. So ist es wirklich einfacher.

Je nach Prozessor ggf. auch schneller.

> Ich nutze jetzt die Gelegenheit einfach mal und frage,
> was es mit dieser Notation auf sich hat.
>
> Mit ( 1 << 0 ) schiebe ich eine 1 an das 0. Bit.

Quasi. Du hast eine 1 und schiebst sie um 0 Bits. Das ist zwar das 
gleiche, als wenn du sie gar nicht schieben würdest, aber paßt von der 
Schreibweise her besser zu den anderen Zeilen und mach so den Code 
übersichtlicher.

> Kann man sich das so wie eine imaginäre Vergleichsvariable vorstellen?

Es ist eine Maske. Mit "source & ( 1 << 0 )" legst du eine temporäre 
Kopie von source an, wo du alle Bits bis auf das nullte gelöscht werden. 
Wenn das Ergebnis dann nicht 0 ist, muß das bedeuten, daß in source das 
nullte Bit gesetzt ist. Du legst also quasi eine Maske über source, die 
dir nur das nullte Bit zeigt und den Rest "verdeckt" (ausmasikert).

von Michael K. (damichl)


Lesenswert?

Es gibt leider ein kleines Problem:

if( source & ( 1 << 15 ))... funktioniert,

if( source & ( 1 << 20 )) nicht mehr.

source ist ein uint64_t, die Maske aber anscheinend nicht.
Kann es sein, dass ich jetzt einen Typecast brauche? Wenn ja, wo?


Danke!


Michael

Edit: Hab es gefunden, if( source & ((uint64_t)1 << 20 )) funktioniert 
:)

von Michael K. (damichl)


Lesenswert?

Letzte Frage für heute:

ich will Bits, z.B 1101 0000 um 4 Stellen nach rechts schieben (durch 16 
teilen): Schreibweise?

t = 4 >> ROW; funktioniert nicht, ebensowenig die gewohnte Schreibweise 
aus C++: t = ROW >> 4;

von Rolf Magnus (Gast)


Lesenswert?

Michael K. schrieb:
> Edit: Hab es gefunden, if( source & ((uint64_t)1 << 20 )) funktioniert
> :)

Alternativ: if( source & (1ULL << 20 ))
Man benötigt das hier, weil 1 und 20 vom Typ int sind und damit die 
Schiebeoperation mit diesem Typ durchgeführt wird. Und da läuft dann das 
Ergebnis über. Wenn du für wenigstens einen der beiden Operanden 
explizit einen ausreichend großen Typ angibst, wird auch der Shift mit 
dem entsprechenden Typ durchgeführt.

Michael K. schrieb:
> Letzte Frage für heute:
>
> ich will Bits, z.B 1101 0000 um 4 Stellen nach rechts schieben (durch 16
> teilen): Schreibweise?
>
> t = 4 >> ROW; funktioniert nicht, ebensowenig die gewohnte Schreibweise
> aus C++: t = ROW >> 4;

Wie äußert sich "funktioiniert nicht" in deinem Programm? Die 
Fehlerbeschreibung könnte etwas detailierter sein. Die "gewohnte 
Schreibweise aus C++" ist richtig.

von Klaus W. (mfgkw)


Lesenswert?

Was heißt "funktioniert nicht"?

von Karl H. (kbuchegg)


Lesenswert?

Michael K. schrieb:
> Letzte Frage für heute:
>
> ich will Bits, z.B 1101 0000 um 4 Stellen nach rechts schieben (durch 16
> teilen): Schreibweise?
>
> t = 4 >> ROW; funktioniert nicht,

logisch. Das ist ja auch eine ganz andere Operation.

Zwischen   25/16  und  16/25   besteht nun mal ein Unterschied im 
Zahlenwert des Ergebnisses.

> ebensowenig die gewohnte Schreibweise
> aus C++: t = ROW >> 4;


Wenn du durch 16 teilen willst, dann wäre die gewohnte Schreibweise

   t = ROW / 16;

und sofern deine Operation am besten umgangssprachlich mit dem Terminus 
"dividiert" beschrieben wird, solltst du das auch so verwenden. Wenn 
diese Division mittels einer Shift Operation implementiert werden kann, 
dann wird der Compiler das auch mittels Shift machen.

von Flusskontrolle (Gast)


Lesenswert?

Michael K. schrieb:
> Es gibt leider ein kleines Problem:
>
> if( source & ( 1 << 15 ))... funktioniert,
>
> if( source & ( 1 << 20 )) nicht mehr.
>
> source ist ein uint64_t, die Maske aber anscheinend nicht.
> Kann es sein, dass ich jetzt einen Typecast brauche? Wenn ja, wo?

Die 1 ist ein Integer (der Standardtyp halt). Wenn du etwas anderes 
möchtest, kannst du das auch durch Suffixe angeben:
L für long
U für unsigned
LL für long long
Man kann auch das U mit den anderen Kombinieren:
UL für unsigned long
ULL für unsigned long long

Bei dir wäre das dann (source & ( 1ULL << 20 ))

Du kannst für die Suffixe auch Kleinbuchstaben nehmen.

von Stefan E. (sternst)


Lesenswert?

Rolf Magnus schrieb:
> Alternativ: if( source & (1ULL << 20 ))
> Man benötigt das hier, weil 1 und 20 vom Typ int sind und damit die
> Schiebeoperation mit diesem Typ durchgeführt wird. Und da läuft dann das
> Ergebnis über. Wenn du für wenigstens einen der beiden Operanden
> explizit einen ausreichend großen Typ angibst, wird auch der Shift mit
> dem entsprechenden Typ durchgeführt.

Stimmt nicht ganz. Eine Vergrößerung der 20 würde nicht helfen. Bei den 
Schiebeoperatoren findet keine Größenangleichung der Typen der beiden 
Operanden statt.

von Peter D. (peda)


Lesenswert?

Michael K. schrieb:
> source ist ein uint64_t

Wenn Du den AVR-GCC benutzt, schließen sich Effizienz und 64 Bit 
gegenseitig aus.
64 Bit ist sogar noch langsamer und größer, als float.

Zerlege die 64 Bit in 2 * 32 Bit und Dein Programm läuft mindestens 
10-mal schneller.


Peter

von Michael K. (damichl)


Lesenswert?

Hallo nochmal.

leider stimmt irgendwas nicht.

Daten: 0xFF80609613D4EC6C
1
ROW = Daten & 0x7800;

ROW: 0x0000000000006800
1
t = ROW >> 1;

Ergebnis: NOT IN SCOPE

t und ROW sind lokale (funktionseigene) Variablen.

Das mit der Aufteilung in 2 x 32 Bit klingt interessant.

mfg

Michael

von Karl H. (kbuchegg)


Lesenswert?

Michael K. schrieb:

> ROW: 0x0000000000006800
>
>
1
t = ROW >> 1;
>
> Ergebnis: NOT IN SCOPE

Schalte den Optimizer aus. Der hat schlicht und ergreifend deine 
Variable t wegoptimiert

> Das mit der Aufteilung in 2 x 32 Bit klingt interessant.

Ist auch (zumindest für mich) übersichtlicher, als wie wenn man da 
ständig mit so großen Zahlen hantieren muss.

von Michael K. (damichl)


Lesenswert?

Die Optimierung steht bereits auf -Oo, leider mit dem selben Ergebnis.

mfg

von Ralf G. (ralg)


Lesenswert?

Michael K. schrieb:
> Die Optimierung steht bereits auf -Oo, leider mit dem selben Ergebnis.
Ausnahmsweise die Variable mal zum Testen 'volatile' setzen.

von Michael K. (damichl)


Lesenswert?

Hier nochmal die komplette Funktion:
1
extern int CheckParity(uint64_t Daten) 
2
{
3
  //Vergleichsvektor f. Zeilenparität DPROW anlegen
4
  
5
  uint16_t DPROW = 0;
6
  
7
  if(Daten & ((uint64_t)1 << 50))   //PR0
8
    DPROW |= 0x01;
9
  if(Daten & ((uint64_t)1 << 45))  //PR1
10
    DPROW |= 0x02;
11
  if(Daten & ((uint64_t)1 << 40))  //PR2
12
    DPROW |= 0x04;
13
  if(Daten & ((uint64_t)1 << 35))  //PR3
14
    DPROW |= 0x08;
15
  if(Daten & ((uint64_t)1 << 30))  //PR4
16
    DPROW |= 0x10;
17
  if(Daten & ((uint64_t)1 << 25))  //PR5  
18
    DPROW |= 0x20;
19
  if(Daten & ((uint64_t)1 << 20))  //PR6
20
    DPROW |= 0x40;
21
  if(Daten & (1 << 15))  //PR7
22
    DPROW |= 0x80;
23
  if(Daten & (1 << 10))  //PR8
24
    DPROW |= 0x100;
25
  if(Daten & (1 << 5))  //PR9
26
    DPROW |= 0x200;
27
28
29
  //Vergleichsvektor f. Spaltenparität DPCOL anlegen
30
  
31
  uint8_t DPCOL = 0;
32
  
33
  if(Daten & (1 << 4))
34
    DPCOL |= 0x01;
35
  if(Daten & (1 << 3))
36
    DPCOL |= 0x02;
37
  if(Daten & (1 << 2))
38
    DPCOL |= 0x04;
39
  if(Daten & (1 << 1))
40
    DPCOL |= 0x08;
41
42
  //Vektoren für berechnete Parität anlegen
43
  uint16_t PROW=0;
44
  uint8_t PCOL=0;
45
  uint64_t ROW=0, t=0;
46
47
            //PR8 berechnen
48
  ROW = Daten & 0x7800;  //ROW8
49
  t = ROW>>1;    //DAS HIER FUNKTIONIERT NICHT
50
  
51
  t = t^3;    //Dummykrempel wg. Optimierung
52
  if(ROW==0x73FCA0000)
53
    if(t==0x31)
54
    return 0;
55
  return 1;
56
};


Die Funktion wird in main mit
1
valid = CheckParity(Data);

aufgerufen.

Also der Optimierer macht einem das debuggen echt nicht leicht, 
wenngleich hier anscheinend ein anderes Problem vorliegt (wie gesagt - 
Opt. steht auf -O0)

Vielen Dank nochmal für die Hilfe!

mfg

Michael

von Ralf G. (ralg)


Lesenswert?

Nachtrag:
Die Variable ist möglicherweise nicht wegoptimiert, sondern nur in einem 
Register abgelegt, welches in der Funktion öfter verwendet wird.

von Karl H. (kbuchegg)


Lesenswert?

Michael K. schrieb:
> Hier nochmal die komplette Funktion:

Du magst mich blind nennen, aber ich kann da nicht erkennen, dass t 
innerhalb der Funktion eine lokale Variable wäre.

von Michael K. (damichl)


Lesenswert?

uint64_t ROW=0, t=0;

von Michael K. (damichl)


Lesenswert?

Habe das Problem entdeckt.
Wenn ich die Zeile mit "Step into" ausführe, geht es nicht.
Mit "Step over" funktioniert es.

Weiß jemand wieso das so ist?


mfg

Michael

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
> Michael K. schrieb:
>> source ist ein uint64_t
>
> Wenn Du den AVR-GCC benutzt, schließen sich Effizienz und 64 Bit
> gegenseitig aus.
> 64 Bit ist sogar noch langsamer und größer, als float.
>
> Zerlege die 64 Bit in 2 * 32 Bit und Dein Programm läuft mindestens
> 10-mal schneller.

Wenn es C-Typen mit 512 Bits gäbe — was auf einem 64-Bit System einem 
64-Bit Typ auf AVR entspricht — glaub mir, auch die würden verwendet 
werden...

von Michael K. (damichl)


Angehängte Dateien:

Lesenswert?

Also irgendwie mag mich gcc nicht sonderlich :)

ich rufe die Funktion
1
extern void myfkt(uint8_t vec)
2
{
3
  vec = (vec*3)^2;
4
  if(vec == 0xFF)
5
  res=1;
6
  return;
7
};

z.b. folgendermaßen (vereinfacht) aus einer anderen Funktion auf:
1
uint8_t res;
2
res = 7;
3
myfkt(res);

und bekomme die angezeigten Werte.
Der Wert ändert sich bei der Übergabe, obwohl beide den selben Datentyp 
haben.

Also zur Zeit ist echt irgendwie der Wurm drin. Was mache ich nur 
falsch? Und was bedeuten die Zeichen, z.B. '-' hinter einer Zahl im 
Watch?

Danke für die Geduld mit mir.


mfg

Michael

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Michael K. schrieb:

Ich hab stark den Eindruck, du versuchst eine Programmiersprache 
mithilfe von Debugger und Versuch+Irrtum zu erlernen.

Die Frustrationsgrenze bei dem Ansatz ist nicht fern...

von Michael K. (damichl)


Lesenswert?

Es stimmt, ich bin noch ziemlich am Anfang was C angeht. Insbesondere 
die Eigenheiten bei der Hardwareprogrammierung (also so Sachen, dass 
Codeteile, die ich zum Testen einbaue, einfach wegoptimiert werden oder 
die Sache mit dem nötigen Typecast) machen mir noch Probleme.

Nichtsdestotrotz weiß ich nicht was bei dem obigen Funktionsaufruf 
falsch sein soll. Bei anderen Funktionen geht das ohne Probleme, hier 
plötzlich nicht mehr. Das ist es auch, was mich irgendwie etwas 
frustriert, es scheint irgendwie willkürlich zu sein.
Ich meine ich könnte natürlich alles global machen. Aber es stört mich 
immer gewaltig, wenn ich etwas nicht verstanden habe. Deshalb reite ich 
dann auch so lange darauf rum.



Michael

von Peter D. (peda)


Lesenswert?

Johann L. schrieb:
> Wenn es C-Typen mit 512 Bits gäbe — was auf einem 64-Bit System einem
> 64-Bit Typ auf AVR entspricht — glaub mir, auch die würden verwendet
> werden...

Was aber überhaupt nichts mit meiner Aussage zu tun hat, daß auf dem 
AVR-GCC die 64Bit grottenschlecht implementiert sind.

Wenn man performante 64Bit haben will, muß man zu einem 
kostenpflichtigen AVR-Compiler greifen, z.B. IAR.


Peter

von Peter D. (peda)


Lesenswert?

Ich weiß nicht, ob überhaupt jemand wegen der schlechten Implementierung 
die 64Bit ernsthaft verwendet.

Es könnte daher gut sein, daß die Probleme des OP nicht an seinen 
C-Kenntnissen liegen, sondern daß da einige Bugs drin sind.

Ich hätte sie mal auf dem ATtiny2313 benötigt, aber da haben die 5kB 
64Bit-Lib nicht reingepaßt.
Ich habs dann in Assembler gelöst.


Peter

von Michael K. (damichl)


Lesenswert?

Aber wieso klappt es dann nicht mal mit einem 8-Bit-int?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
>
> Wenn man performante 64Bit haben will, muß man zu einem
> kostenpflichtigen AVR-Compiler greifen, z.B. IAR.

GCC (und auch avr-gcc) sind freie Software und jeder der wirklich 
will, kann dazu beitragen.  Solche Features werden idR von demjenigen 
imlementiert/beigesteuert, dem es am wichtigsten ist.  Im Umkehrschluß 
folgt daraus, daß es niemandem wichtig genug ist.

Wenn man all die Zeit und Beiträge zusammenzählt, in denen darüber 
lamentiert wurde, hätte man bestimmt schon mindestens 10 long long 
Implementierungen für avr-gcc ;-)

Peter Dannegger schrieb:
> Ich weiß nicht, ob überhaupt jemand wegen der schlechten Implementierung
> die 64Bit ernsthaft verwendet.
>
> Es könnte daher gut sein, daß die Probleme des OP nicht an seinen
> C-Kenntnissen liegen, sondern daß da einige Bugs drin sind.

Die Logik erschliesst sich mir nicht. Es gibt keine 64-Bit 
Implementierung in avr-gcc (ausser Shifts ab 4.7).  Alles, was mit long 
long zu tun hat, wird vom maschinen*un*abhängigen Teil von GCC 
verarbeitet, und der ist weit besser getestet als der AVR-Teil.

Was den OP angeht, so ist res im Schnipsel
1
uint8_t res;
2
res = 7;
3
myfkt (res);
eine lokale Variable, während sie in
1
void myfkt (uint8_t vec)
2
{
3
  vec = (vec*3)^2;
4
  if (vec == 0xFF)
5
  res = 1;
6
}
offenbar global ist (avr-gcc unterstützt keine lokalen Funktionen).

Zudem dünkt mir, daß ^2 Quadrieren darstellen soll und nicht 
Exclusiv-Oder?

von MichaelK (Gast)


Lesenswert?

Danke. Zunächst mal ist der Inhalt der Funktion willkürlich (ich wollte 
nur sicherstellen dass es nicht wieder wegoptimiert wird).

Wieso ist vec global? So wie ich das sehe existiert sie nur in myfkt.
Kannst Du die Sache mit den nichtunterstützten lokalen Funktionen 
genauer erklären? Wäre sehr daran interessiert!


mfg

Michael

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

MichaelK schrieb:
> Danke. Zunächst mal ist der Inhalt der Funktion willkürlich (ich wollte
> nur sicherstellen dass es nicht wieder wegoptimiert wird).

Wenn ich mir die Funktion anschaue und den Wert von vec, dann sehe ich, 
daß res in myfkt nicht verändert wird. Und wenn ich das sehe, kann es 
ein Compiler prinzipiell auch :-)

Was die nervigen Optimierungen angeht, ist bestimmt auch 
Compilerfehler eine interessante Lektüre für dich.

von Peter D. (peda)


Lesenswert?

Johann L. schrieb:
> Solche Features werden idR von demjenigen
> imlementiert/beigesteuert, dem es am wichtigsten ist.  Im Umkehrschluß
> folgt daraus, daß es niemandem wichtig genug ist.

Nö, damit hat es überhaupt garnichts zu tun.
Es gibt eben nur wenige, die wissen, wie man einen Compiler compiliert.

Den Assemblercode für die 4 Grundrechenarten 64bittig hinzuschreiben, 
ist Pippifax, das schreib ich Dir schnell eben mal hin.
Aber wie man sowas in einen Compiler reinpfrimelt, da guck ich wie ein 
Schwein ins Uhrwerk.


Peter

von Michael K. (damichl)


Lesenswert?

Also es funktioniert nun. War tatsächlich (wieder) ein Problem mit der 
Optimierung. Gibt es denn keine Möglichkeit, diese zumindest zum Testen 
der Funktionen komplett auszuschalten? Selbst mit -O0 wird trotzdem 
(wenn wohl auch weniger) optimiert.

Vielen Dank für eure Hilfe!

mfg

Michael

von Oliver (Gast)


Lesenswert?

Michael K. schrieb:
> War tatsächlich (wieder) ein Problem mit der
> Optimierung.

Es gibt tatsächlich weder jetzt noch wieder Probleme mit der 
Optimierung. Es gibt nur fehlerhaften Code, die der Optimierer dann 
anders versteht, als der Programmierer.

> Selbst mit -O0 wird trotzdem (wenn wohl auch weniger) optimiert.

Schlicht falsch.

Oliver

von Rolf Magnus (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Johann L. schrieb:
>> Solche Features werden idR von demjenigen
>> imlementiert/beigesteuert, dem es am wichtigsten ist.  Im Umkehrschluß
>> folgt daraus, daß es niemandem wichtig genug ist.
>
> Nö, damit hat es überhaupt garnichts zu tun.
> Es gibt eben nur wenige, die wissen, wie man einen Compiler compiliert.

Das ist aber kein Geheimnis. Es läßt sich dank Internet leicht 
herausfinden.

> Den Assemblercode für die 4 Grundrechenarten 64bittig hinzuschreiben,
> ist Pippifax, das schreib ich Dir schnell eben mal hin.
> Aber wie man sowas in einen Compiler reinpfrimelt, da guck ich wie ein
> Schwein ins Uhrwerk.

Gut, das ist nicht ganz einfach. Da muß man schon etwas Zeit 
investieren. Aber wie Johann schon schrieb: Wenn du das nicht tust, ist 
es dir wohl auch nicht so wichtig. Dann solltest du dich aber nicht 
beschweren, daß andere das nicht für dich implementieren.

von Peter D. (peda)


Lesenswert?

Rolf Magnus schrieb:
> Das ist aber kein Geheimnis. Es läßt sich dank Internet leicht
> herausfinden.

Den Eindruck habe ich aber ganz und garnicht.
Wenn ich so sehe, wie komplex die Erstellung einer neuen WINAVR Version 
ist, dann sehe ich für mich überhaupt nicht die geringste Chance.

Ich komme ja aus der Hardware-Ecke. Ich hab mal ein paar DOS-Programme 
auf dem PC entwickelt (Turbo-Pascal, -C), mehr nicht.
Ich müßte total vom Urschleim anfangen und erstmal Windows-Programme 
erstellen lernen.


Rolf Magnus schrieb:
> Gut, das ist nicht ganz einfach.

Das ist dann quasi das Kill-Kriterium, wenn es sogar schon für einen 
Fachmann wie Dich nicht einfach ist.


Rolf Magnus schrieb:
> Da muß man schon etwas Zeit
> investieren.

"Etwas Zeit" ist lustig. Ich würde bei meinem Kenntnisstand nicht unter 
ein Mannjahr ansetzen.


Peter

von (prx) A. K. (prx)


Lesenswert?

Peter Dannegger schrieb:

> Ich müßte total vom Urschleim anfangen und erstmal Windows-Programme
> erstellen lernen.

Mit Windows hat das wenig zu tun, ausser dass der Compiler auch darunter 
läuft. Der GCC Build-Vorgang entstammt einer Unix-Umgebung mit den dort 
üblichen und ggf. nach Windows rüber geschleppten Tools. Der Einstieg 
ist daher in einer Linux-Umgebung etwas einfacher. Mit der 
Standardversion von GCC - also ohne bei AVRs nötige Patch-Orgien - ist 
das fast Plug-and-Play.

Programme erstellen musst du dazu ohnehin nicht. Nur in der Lage sein, 
den Build-Vorgang fehlerfrei durchziehen zu können. Denn es geht hier 
darum, den bestehenden Code zu modifizieren/erweitern und Lib-Code zu 
erzeugen. Oder wolltest du gleich den ganzen Compiler mitsamt einer 
Windows-GUI neu schreiben?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
> Rolf Magnus schrieb:
>> Das ist aber kein Geheimnis. Es läßt sich dank Internet leicht
>> herausfinden.
>
> Den Eindruck habe ich aber ganz und garnicht.
> Wenn ich so sehe, wie komplex die Erstellung einer neuen WINAVR Version
> ist, dann sehe ich für mich überhaupt nicht die geringste Chance.

WinAVR ist wesentlich mehr als ein schlichter Build der avr-Tools: Es 
gibt zahlreiche Patches, einen Installer, avrdude, simulavr, Doku, 
Beispielprogramme, etc. die man alle für eine Arbeit an avr-gcc nicht 
braucht und schon garnicht deren Generierung/Distribution.

> Ich komme ja aus der Hardware-Ecke.

Und ich komme aus der Mathematik/Physik-Ecke. Die Ausrede zählt also 
nicht :-)

> Ich müßte total vom Urschleim anfangen und erstmal Windows-Programme
> erstellen lernen.

Der Urschleim ist hier eine unixoide Shell, zB unter irgendeinem Linux 
nebst Editor.  Programme aus der Unix-Welt für MS-Windows zu erzeugen 
ist nochmal was anderes, als nativ unter Linux zu arbeiten. Aber das 
brauchst du alles nicht; es genügt, unter Linux zu bleiben.

An Editoren gibt es i.W. zwei: Emacs und vi/vim.  Vielleicht gibt's auch 
Exoten, die was anderes verwenden; ist mir aber noch nicht zu Ohren 
gekommen.

> Rolf Magnus schrieb:
>> Da muß man schon etwas Zeit investieren.
>
> "Etwas Zeit" ist lustig. Ich würde bei meinem Kenntnisstand nicht unter
> ein Mannjahr ansetzen.

Da gibt's zwei Optionen:

· Die Light-Version: Alles, was in der libgcc gemacht werden kann,
  dort implementieren. Das ist in Assembler und kein Problem hinzu-
  schreiben.  Am eigentlichen Compiler ändert sich nichts.
  Arbeitsschritte sind dann
     1) Den Lizenzkram abhaken
     2) Asm in libgcc hinzufügen
     3) Den Build auf die Reihe bekommen
     4) Regression-Tests laufen lassen, if error goto 2)
     5) Patch machen, Review + Commit
  Dies geht für Multiplikation, Division und Modulo, jedoch nicht für
  Addition, Subtraktion und Vergleich, die haupt Performance-Bremsen
  bleiben also. Aber man lernt schon mal mit dem Monstrum GCC umzugehen.
  Ist bereits gemacht für einfache Funktionen wie Shifts, Parity, etc.

· Die Dröhn-Packung:
     6) Implementiere a = b für 64-Bit Typen in avr-gcc
     7) Rest ist Kinderkram. Was zu aufwändig ist, um inline
        auszugeben: siehe oben.

1) ist nervig aber diesen Punkt ist alles andere Makulatur.

Peter Dannegger schrieb:
> Johann L. schrieb:
>> Solche Features werden idR von demjenigen
>> imlementiert/beigesteuert, dem es am wichtigsten ist.  Im Umkehrschluß
>> folgt daraus, daß es niemandem wichtig genug ist.
>
> Nö, damit hat es überhaupt garnichts zu tun.
> Es gibt eben nur wenige, die wissen, wie man einen Compiler compiliert.

Das ist kein Geheimnis und das Leichteste von allem.

Um ein neues Feature ein GCC zu bekommen gibt es zwei Wege: Man macht's 
selber oder beauftragt jemanden, der es tut.  Letzteres scheitert wohl 
an mancher Firmenphilosophie nach dem Motto: Anstatt einen Entwickler 
zur Implementierung von Feature X anzuheuern, bezahle ich lieber das 
gleiche Geld von mehreren 1000€ für einen anderen Compiler. Nach dem 
Motto: Wenn ich die Entwicklung bezahlte, würden ja auch andere davon 
profitieren, und das geht nun wirklich zu weit.

Andererseits scheint selbst Atmel Probleme zu haben, GCC-Entwickler an 
Land ziehen zu können. Die gibt's eben nicht an jeder Straßenecke...

> Den Assemblercode für die 4 Grundrechenarten 64bittig hinzuschreiben,
> ist Pippifax, das schreib ich Dir schnell eben mal hin.
> Aber wie man sowas in einen Compiler reinpfrimelt, da guck ich wie ein
> Schwein ins Uhrwerk.

He he, den Spruch kannte ich bisher noch nicht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Oliver schrieb:
> Michael K. schrieb:
>>
>> Selbst mit -O0 wird trotzdem (wenn wohl auch weniger) optimiert.
>
> Schlicht falsch.

Einige wenige Dinge werden auch mit -O0 "optimiert", zB Faltung von 
Konstanten. Ansonsten wäre eine globale Variable nicht einfach per
1
int a = 40 + 2;
initialisierbar und müsste aufwändig irgendwo im Startup-Code geschehen.

von cskulkw (Gast)


Lesenswert?

Schon einmal etwas von BitVariablen in C gehört?
struct{
 uint_16 Bit1 :1;
 uint_16 Bit2 :1;
 ...

 uint_16 Bit10 :1;
 uint_16 rest :6;// wichtig sonst meckert der Compiler
}Ergebnisvariable;

if(Quelle & Bitmaske)
 Ergebnisvariable.Bitx (x = 1..10) = 1;
else
 Ergebnisvariable.Bitx (x = 1..10) = 0;

Könnte man auch als Makro mit dem Fragezeichenoperator schreiben. Da 
habe ich aber nicht so den Zugang gefunden.

Die Art hätte den Charme, dass man die Strukturvariable über eine UNION 
definiert. Auf der Füllseite bitorientiert zugreifen und auf der anderen 
Seite wordorientiert weiterverarbeiten könnte.

Ist übrigens ANSI-C-Standard.

Ist ein Vorsschlag, viel Erfolg

von Karl H. (kbuchegg)


Lesenswert?

cskulkw schrieb:
> Schon einmal etwas von BitVariablen in C gehört?

Schon mal was davon gehört, dass Bitfelder in C weit weniger stark 
definiert sind, als die meisten Programmierer gemeinhin annehmen?

Zum Beispiel ist m.W. nicht definiert in welcher Reihenfolge der 
COmpiler die Bits anordnen muss. Fängt er beim LSB an oder beim MSB? 
Muss er die Bits in derselben Reihenfolge in die Bytes packen in der du 
sie angegeben hast? Was ist das geforderte Verhalten, wenn ein Bitfeld 
über eine Bytegrenze geht, wie hat sich der Compiler dann zu verhalten, 
welche Möglichkeiten hat er?

Wenn du bei deiner Aufgabenstellung dich dann mal fragst: Ist eine oder 
mehrere der obigen Fragen (und noch ein paar andere, die mir momentan 
nicht einfallen) in meiner konkreten Aufgabenstellung wichtig (wie es zb 
beim Einlesen von Daten von einem File ist, die dann auf Bitebene 
auseinanderklamüsert werden müssen) und du beantwortest dir diese Frage 
mit "ja, ist bei mir wichtig", dann solltest du von Bitfeldern Abstand 
nehmen. Selbst dann, wenn es mit deiner jetzigen Compilerversion 
funktioniert. Mit der nächsten Compilerversion oder gar einem ganz 
anderen Compiler kann nämlich alles wieder ganz anders sein.

von Klaus W. (mfgkw)


Lesenswert?

Im Prinzip hast du Recht, aber man muß es auch nicht übertreiben.

Ich bin meistens ein ziemlicher Pedant, wenn es um portables 
Programmieren geht.
Aber Bitfummelei in den Registern eines AVR oder jedes anderen MC ist 
inhärent komplett unportabel.
Und daß im gcc die Reihenfolge der Bitfelder gedreht wird, werde ich 
nicht mehr erleben (jaja, ist sowieso nicht mehr weit bis dahin, 
trotzdem).

Das ganze Gefummel nicht mehr über den ganzen Quelltext zu verstreuen, 
sondern einmal Bitfelder zu definieren, und dann mit z.B.
1
typedef struct
2
{
3
   unsigned  rot:   2;
4
   unsigned  gruen: 2;
5
   unsigned  blau:  2;
6
} mein_farbregister_t;
7
8
// Referenzen aus C++ sparen Zeiger :-)
9
mein_farbregister_t   &meinFarbRegister = *(mein_farbregister_t*)&PORTA;
10
mein_farbregister_t   &meinFarbRegister_ddr = *(mein_farbregister_t*)&DDRA;
11
12
...
13
14
// Richtung setzen der Bits in Port A:
15
meinFarbRegister_ddr.rot   = 0b11;
16
meinFarbRegister_ddr.gruen = 0b11;
17
meinFarbRegister_ddr.blau  = 0b11;
18
19
// Ausgabe von Werten in Port A:
20
meinFarbRegister.rot   = 0;
21
meinFarbRegister.gruen = 2;
22
meinFarbRegister.blau  = 3;
Bits setzen und löschen zu können, finde ich schon wesentlich lesbarer 
und fehlerärmer als mit manuellem Bitschieben und & und |:
1
#define   PORT_FARBE  (PORTA)
2
#define   DDR_FARBE   (DDRA)
3
#define   PIN_ROT     (4)
4
#define   PIN_GRUEN   (2)
5
#define   PIN_BLAU    (0)
6
7
// Richtung setzen der Bits in Port A:
8
DDR_FARBE |= 0b11 << PIN_ROT;
9
DDR_FARBE |= 0b11 << PIN_GRUEN;
10
DDR_FARBE |= 0b11 << PIN_BLAU;
11
12
// Ausgabe von Werten in Port A:
13
PORT_FARBE &= ~(0b11 << PIN_ROT);   // alten Wert zu 0
14
PORT_FARBE |= 0 << PIN_ROT;         // neue Bits setzen
15
PORT_FARBE &= ~(0b11 << PIN_GRUEN); // alten Wert zu 0
16
PORT_FARBE |= 2 << PIN_GRUEN;       // neue Bits setzen
17
PORT_FARBE &= ~(0b11 << PIN_BLAU);  // alten Wert zu 0
18
PORT_FARBE |= 3 << PIN_BLAU;        // neue Bits setzen

Das Gefummel mit &= und |= macht man nur, wenn man es so gewohnt ist.
Elegant ist es wohl kaum.

In letzterem Beispiel findet man ja kaum noch die Werte 0, 2 und 3, die 
man setzen will, vor lauter Müll drumrum.

Und selbst wenn ich aus irgendwelchen Gründen solange lebe, daß ich die 
Bitfelder noch drehen muß: dann ändere ich im Programmkopf die 
Definitionen der Bitfelder, und fertig.
Der ganze restliche Quelltext bleibt unverändert und lesbar.
Bis dahin hätte ich mich schon mehrfach mit der Bitschieberei und den & 
und | verfranzt.

Das ist wie mit Braunkohl und Korn: man muß da geboren sein, um es zu 
mögen, oder Alkoholiker sein.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> ... dann solltest du von Bitfeldern Abstand
> nehmen. Selbst dann, wenn es mit deiner jetzigen Compilerversion
> funktioniert. Mit der nächsten Compilerversion oder gar einem ganz
> anderen Compiler kann nämlich alles wieder ganz anders sein.

Wieso sollte sich sowas mit der Compilerversion ändern? Ohne triftigen 
Grund wird sich eine ABI nicht "per Magie" ändern, und wenn, wird das 
idR verschaltert so daß man die Wahl hat, zB weil neue Derivate zur 
Architektur hinzukommen.

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.