WINAVR und CarryFlag

OP #991835
Lesenswert?

Hallo,
habe ein kleines Problem beim addieren von bytes. Programmiere in WINAVR 
unter AVRSTUDIO, einen Atmega32.

Beispiel:
unsigned char Zahl1 = Zahl2 = 0xAA;
unsigned char Zahl3 = 0;

Zahl1 = Zahl1 + Zahl2;
Zahl3 = Zahl3 + CARRY;

In Assembler gabs so schöne Befehle die add und adc, aber in C stehe ich 
gerade total aufm Schlauch.
Hoffe das klar geworden ist was ich meine.
Also 2 Zahlen addieren und die nächste Zahl soll mit dem Carry Flag 
zusammen addiert werden, falls es einen Übertrag gab.

Vielen Dank und Gruß, fubu.
#991848
Lesenswert?

@ Fabian Ostner (fubu1000)

>Also 2 Zahlen addieren und die nächste Zahl soll mit dem Carry Flag
>zusammen addiert werden, falls es einen Übertrag gab.

Dazu musst du grössere Variablen verwenden und von Hand den Übertrag 
behandeln. Ist zwar ziemlich ineffizient, geht in C aber nicht anders.

Etwa so.

1
uint16_t z1 = z2 =0xAA;
2
uint16_t z3;
3

4
z1 = z1 +z2;
5
if (z1>255) {
6
  z1 = z1 - 256;
7
  z3 = Z3 +1;
8
}

MFG
Falk
OP #992110
Lesenswert?

Damit Ihr mich nicht für total verrückt haltet warum ich sowas frage.
Ich lese aus einem Fat16 , z.B. VolumeBootRecord aus wieviele Sektoren 
reserviert sind. Möchte diese natürlich mit dem Start der 
VolumeBootRecord addieren, damit ich weiß, wo die die FAT beginnt.

In Assembler schmeiss ich einfach das letzte ausgelesene Byte weg 
(höchste Byte), füge hinten 0x00 an und mach einen "lsl" des untersten 
Bytes und "adc" mit den folgenden Bytes (Registern).

In Assembler super effektiv, aber in C muss ich da mit "long" rumspielen 
und dann wieder in chars wandeln für Addressierung.
Super Uneffektiv !

In Assembler hab ich FAT16 schon in Read und Write umgesetzt und funzt 
super.
Wollte es mal aber ebenso effektiv in C umsetzen.
Aber keine Chance  ;-(

Werde es aber weiter versuchen, muß gehen irgendwie ;-(

GRUß UND DANK AN ALLE , FABIAN.
Persönliche Seite #992127
Lesenswert?

Erstmal heißt es ineffizient ;)
Außerdem effektiv != effizient, effektiv ist das alles! :P

So Spaß beiseite: Du kannst natürlich inline ASM für die betreffende 
Stelle verwenden, man kann dort auch auf C Variablen zugreifen. 
(http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Assembler_und_Inline-Assembler).

Außerdem so ineffizient wie das scheint ist das alles nicht, vieleicht 2 
- 3 Takte langsamer, und wenn du das als Ausdruck formulierst kann der 
Compiler da ggf. auch optimieren.
Gast #992175
Lesenswert?

Hi,

hier eine mögliche Umsetzung des Vorschlags von Läubi Mail@laeubi.de:
1
#include <inttypes.h>
2

3
uint8_t  carry(uint8_t z1, uint8_t z2) {
4
    uint8_t carry;
5
    asm volatile(
6
        "clr %0" "\n\t"
7
        "add %1,%2" "\n\t"
8
        "adc %0, %0"
9
        : "=r" (carry)
10
        : "r" (z1), "r" (z2), "0" (carry)
11
    );
12
    return carry;
13
}
14

15
int main(void){
16
uint8_t Zahl1, Zahl2;
17
volatile uint8_t Zahl3 = 0;
18

19
Zahl1=Zahl2=0xAA;
20
Zahl3+=carry(Zahl1, Zahl2);
21
return 1;
22
}

Gruß
  risu
#992180
Lesenswert?

Fabian Ostner wrote:
> In Assembler super effektiv, aber in C muss ich da mit "long" rumspielen
> und dann wieder in chars wandeln für Addressierung.
> Super Uneffektiv !

Du weißt wohl nicht, wie man Effektivität berechnet?

Du berechnest ne Adresse und liest dann z.B. 512 Byte von dieser ein.
Ein Memcopy dauert 7 Zyklen pro Byte, also 3584 Zyklen.
Nun ärgert Dich tierisch, daß die Adreßberechnung vielleicht 5 Zyklen 
länger dauert, d.h. gerade mal 0,13%.

Also ein Unterschied von 0,13% ist nicht super, sondern nur ein 
Fliegenschiß.


Bevor also etwas optimiert, sollte man erstmal prüfen, ob das überhaupt 
einen merkbaren Effekt hat.


Peter


P.S.:
Man kann einen Quellcode nicht verbal beschreiben.
Daher wäre der Assemblerquelltext dieser Funktion sinnvoll, damit man 
sieht was da überhaupt passiert und wie man das in C machen könnte.

Aber wenn eine Funktion nicht mindestens 10% der CPU-Zeit verbraucht, 
lohnt sich eine Optimierung in den seltensten Fällen.
Gast #992184
Lesenswert?

Hallo Peter,

> Man kann einen Quellcode nicht verbal beschreiben.
> Daher wäre der Assemblerquelltext dieser Funktion sinnvoll,...

das sehe ich auch so. Mir war anhand der Beschreibung des OPs z.B. nicht 
klar, ob er die Summe, deren Übertrag er benötigt, verwirft oder 
verwendet. Deshalb habe ich meine Inline-Assembler-C-Stub-Funktion (oder 
wie immer man die nennt) so ausgerichtet, dass zwar die Summe gebildet, 
aber nur der Übertrag zurückgegeben wird.

Gruß
  risu
#992186
Lesenswert?

@  Peter Dannegger (peda)

>Aber wenn eine Funktion nicht mindestens 10% der CPU-Zeit verbraucht,
>lohnt sich eine Optimierung in den seltensten Fällen.

Richtig. Alte Programmiererregel.

90% der CPU-Leistung werden in 10% des Programms verbraucht.

Diese 10% müssen optimiert werden, der Rest "nur" solide hingeschieben. 
Siehe Soft-PWM, dort lohnt sich eine Optimierung nur in der ISR.

MFg
Falk
Gast #992225
Lesenswert?

Hallo,

hier die korrigierte Version (nur eine Spielerei; wenn die Funktion 
wirklich zeitkritisch wäre, würde ich einen größeren Teil des Codes als 
"*.S" Assembler-Code verpacken):
1
#include <avr/io.h>
2

3
#include <inttypes.h>
4

5
uint8_t  f_carry(uint8_t z1, uint8_t z2) {
6
    uint8_t carry;
7
    asm volatile(
8
        "clr %0" "\n\t"
9
        "add %1,%2" "\n\t"
10
        "adc %0, %0"
11
        : "=r" (carry)
12
        : "r" (z1), "r" (z2), "0" (carry)
13
    );
14
    return carry;
15
}
16

17

18
int main(void){
19
    uint8_t Zahl1, Zahl2;
20
    volatile uint8_t Zahl3 = 0;
21

22

23
    Zahl1=Zahl2=0xAA;
24

25
    Zahl3+=f_carry(Zahl1, Zahl2);
26
    return 1;
27
}
Gruß
 risu

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren