Forum: Compiler & IDEs GCC inline assembler


von Hagen R. (hagen)


Lesenswert?

Hi Experten,

gesetzt den folgenden Code
1
{
2
3
   uint32_t d = pgm_read_dword(address);
4
5
   glcd.uint8_t_0 = d >> 24;
6
   glcd.uint8_t_1 = d >> 16;
7
   glcd.uint8_t_2 = d >>  8;
8
   glcd.uint8_t_3 = d;
9
}

man lädt also einen DWord und möchte diese aufsplitten in seine 4 Bytes.
Der GCC erzeugte Code speichert "d" in 4 nachfolgende Register, gut.
Beim speichern dieser 4 register in die 4 globalen SRAM Bytes erzeugt er 
aber zusätzlichen code. Das sieht dann so aus:
1
 1878                 /* #APP */
2
 1879 0b40 2591          lpm r18, Z+
3
 1880 0b42 3591          lpm r19, Z+
4
 1881 0b44 4591          lpm r20, Z+
5
 1882 0b46 5491          lpm r21, Z
6
 1883                   
7
 1884                 /* #NOAPP */
8
 1885 0b48 852F          mov r24,r21
9
 1886 0b4a 9927          clr r25
10
 1887 0b4c AA27          clr r26
11
 1888 0b4e BB27          clr r27
12
 1889 0b50 8093 0000     sts glcd+41,r24
13
14
 1890 0b54 CA01          movw r24,r20
15
 1891 0b56 AA27          clr r26
16
 1892 0b58 BB27          clr r27
17
 1893 0b5a 8093 0000     sts glcd+42,r24
18
19
 1894 0b5e BB27          clr r27
20
 1895 0b60 A52F          mov r26,r21
21
 1896 0b62 942F          mov r25,r20
22
 1897 0b64 832F          mov r24,r19
23
 1898 0b66 8093 0000     sts glcd+43,r24
24
25
 1899 0b6a 2093 0000     sts glcd+39,r18

wie man sieht viel unnötiges gemove und gecleare von unnötigen 
Registern.

erwartet hätte ich es so:
1
 1878                 /* #APP */
2
 1879 0b40 2591          lpm r18, Z+
3
 1880 0b42 3591          lpm r19, Z+
4
 1881 0b44 4591          lpm r20, Z+
5
 1882 0b46 5491          lpm r21, Z
6
 1883                   
7
 1884                 /* #NOAPP */
8
 1889 0b50 8093 0000     sts glcd+41,r21
9
 1893 0b5a 8093 0000     sts glcd+42,r20
10
 1898 0b66 8093 0000     sts glcd+43,r19
11
 1899 0b6a 2093 0000     sts glcd+39,r18

immerhin 11 Takte schneller für die 8 Takte zum Speichern im SRAM.
Nebenbei: ein sonstwie gearteter TypCast hate keinen Erfolg !

Nun zur eigentlichen Frage zum inline Assembler:

Wie müsste ich 4 Makros deklarieren die inetwa so aussähen
1
uint8_t = HiHi8(uint32_t);
2
uint8_t = HiLo8(uint32_t);
3
uint8_t = LoHi8(uint32_t);
4
uint8_t = LoLo8(uint32_t);

und die dabei auf die 4 Register in denen der uint32_t gespeichert ist 
direkt zugreifen.

Im Beispiel von ob soll also das Makro HiHi8() -> "r21" zurückliefern 
damit es dann als Parameter für sts glcd+41, r21 benutzt wird.

Ist das überhaupt mit dem Compiler vereinbar ?

Gruß Hagen

von Hagen R. (hagen)


Lesenswert?

ok, einen Teilerfolg habe ich schon mal
1
 1878                 /* #APP */
2
 1879 0b40 8591          lpm r24, Z+
3
 1880 0b42 9591          lpm r25, Z+
4
 1881 0b44 A591          lpm r26, Z+
5
 1882 0b46 B491          lpm r27, Z
6
 1883                   
7
 1884 0b48 2B2F          mov r18, r27
8
 1885                   
9
 1886                 /* #NOAPP */
10
 1887 0b4a 2093 0000     sts glcd+41,r18
11
 1888                 /* #APP */
12
 1889 0b4e 2A2F          mov r18, r26
13
 1890                   
14
 1891                 /* #NOAPP */
15
 1892 0b50 2093 0000     sts glcd+42,r18
16
 1893                 /* #APP */
17
 1894 0b54 292F          mov r18,r25
18
 1895                   
19
 1896                 /* #NOAPP */
20
 1897 0b56 2093 0000     sts glcd+43,r18
21
 1898                 /* #APP */
22
 1899 0b5a 882F          mov r24,r24
23
 1900                   
24
 1901                 /* #NOAPP */
25
 1902 0b5c 8093 0000     sts glcd+39,r24

mit
1
#define HiHi8(addr)      \
2
(__extension__({                    \
3
    uint32_t __addr32 = (uint32_t)(addr); \
4
    uint8_t __result;               \
5
    __asm__                         \
6
    (                               \
7
        "mov %0, %D1" "\n\t"         \
8
        : "=r" (__result)           \
9
        : "r" (__addr32)           \
10
    );                              \
11
    __result;                       \
12
}))
13
14
#define HiLo8(addr)      \
15
(__extension__({                    \
16
    uint32_t __addr32 = (uint32_t)(addr); \
17
    uint8_t __result;               \
18
    __asm__                         \
19
    (                               \
20
        "mov %0, %C1" "\n\t"         \
21
        : "=r" (__result)           \
22
        : "r" (__addr32)           \
23
    );                              \
24
    __result;                       \
25
}))
26
27
#define LoHi8(addr)      \
28
(__extension__({                    \
29
    uint32_t __addr32 = (uint32_t)(addr); \
30
    uint8_t __result;               \
31
    __asm__                         \
32
    (                               \
33
        "mov %0,%B1" "\n\t"         \
34
        : "=r" (__result)           \
35
        : "r" (__addr32)           \
36
    );                              \
37
    __result;                       \
38
}))
39
40
#define LoLo8(addr)      \
41
(__extension__({                    \
42
    uint32_t __addr32 = (uint32_t)(addr); \
43
    uint8_t __result;               \
44
    __asm__                         \
45
    (                               \
46
        "mov %0,%A1" "\n\t"         \
47
        : "=r" (__result)           \
48
        : "r" (__addr32)           \
49
    );                              \
50
    __result;                       \
51
}))
52
53
void glcdSelectFont(void *data) {
54
55
    glcd.FontData = (glcdFontData_t)(data);
56
57
    uint32_t d = pgm_read_dword(glcd.FontData);
58
    glcd.FontWidth = HiHi8(d);
59
    glcd.FontHeight = HiLo8(d);
60
    glcd.FontBitsPixel = LoHi8(d);
61
    glcd.FontFirstChar = LoLo8(d);
62
}

Der Overhead ist nun nur noch 4 unnötige Takte statt 11, aber immer noch 
nicht zufriedenstellend.

Gehts besser ?

Gruß Hagen

von Hagen R. (hagen)


Lesenswert?

Ok, es geht
1
typedef union {
2
    uint32_t dword;
3
    struct {
4
    uint8_t a,b,c,d;
5
    };
6
7
} uint32_t_u;
8
9
void glcdSelectFont(void *data) {
10
11
    glcd.FontData = (glcdFontData_t)(data);
12
13
    uint32_t_u d;
14
 
15
    d.dword = pgm_read_dword(glcd.FontData);
16
17
    glcd.FontWidth = d.a;
18
    glcd.FontHeight = d.b;
19
    glcd.FontBitsPixel = d.c;
20
    glcd.FontFirstChar = d.d;
21
}
1
 1878                 /* #APP */
2
 1879 0b40 8591          lpm r24, Z+
3
 1880 0b42 9591          lpm r25, Z+
4
 1881 0b44 A591          lpm r26, Z+
5
 1882 0b46 B491          lpm r27, Z
6
 1883                   
7
 1884                 /* #NOAPP */
8
 1885 0b48 8093 0000     sts glcd+41,r24
9
 1886 0b4c 9093 0000     sts glcd+42,r25
10
 1887 0b50 A093 0000     sts glcd+43,r26
11
 1888 0b54 B093 0000     sts glcd+39,r27

Lösung ist aber nicht sonderlich schön.

Gruß Hagen

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

So ins blaue hinein:

Warum erweiterst Du den "glcdFontData_t"-Typen nicht um die erwähnte 
Union?

In etwa so *untested*:
1
typedef union {
2
    uint32_t DataDword;
3
    struct {
4
    uint8_t FontWidth,
5
            FontHeight,
6
            FontBitsPixel,
7
            FontFirstChar;
8
    };
9
10
} uint32_t_u;
11
12
typedef struct
13
glcdFontData_s
14
{
15
    /* irgendwelche anderen daten... */
16
    uint32_t_u DataUnion;
17
} glcdFontData_t;
18
19
void glcdSelectFont(void *data) {
20
{
21
    glcd.FontData = (glcdFontData_t)(data);
22
    glcd.DataUnion.DataWord = pgm_read_dword(glcd.FontData);
23
}

  

von Hagen R. (hagen)


Lesenswert?

Ja das wäre auch ne Möglichkeit allerdings eben noch unsauberer :(
Denn obige globale Member der glcd Struktur sind nur ein Teil des 
Ganzen. Und ich hasse es wenn 
Implementations-relevante-Optimierungs-Sachen nach Aussen in der 
"Schnittstelle" sichtbar werden. Hm, anders ausgedrückt: auf diese 
Struktur greift der Entwickler ja aktiv zu. Hab ich dort schon 
"rum-gemorkst" dann versaue ich mir ja quasi die Schnittstelle zu meiner 
GLCD Library aus Sicht des Entwicklers. Am liebsten wäre es mir wenn ich 
aktiv einen uint32_t TypCasten könnte mit obiger Struct. Das habe ich 
aber noch nicht hinbekommen !

Also inetwa so:
1
  #define HH8(d)  (uint32_t_u)(d).a 
2
3
  uint32_t d = pgm_read_dword();
4
   
5
  glcd.FontWidth  = HH8(d); //  = (uint32_t_u)(d).a
6
  glcd.FontHeight = HL8(d);  
7
  glcd.BitsPixel  = LH8(d);

Ich hasse C das kann ich dir sagen und am meisten hasse ich mich das ich 
immerwieder mit solchem Mist Probleme habe und einfach das Wissen fehlt.

Man muß sich das mal vorstellen: da programmiert einer seit 20 Jahren 
professionell und verdient Kohle damit. Er kann unzählige 
Programmiersprachen: PASCAL, Delphi, PL4, COBOL, BASIC, Assembler 
AVR,ARM,6201 usw. und in jeder dieser Sprachen sind solche Konstrukte 
wie oben eine Selbstverständlichkeit und absolut intuitiv nur eben im 
fu..ing C  lernt man es nie. Ich wundere mich wirklich nicht das die 
meiste Frage über C die Frage ist wie man nit Zeigern umgeht. Betrachtet 
man das zb. in PASCAL so wird man sehen wie wirklich einfach, sicher und 
sauber es gehen könnte. Das ist bei mir Unterrichtsstoff von ne halben 
Stunde und schon habens meine Lehrlinge intus. Aber in C gibts nur 
Probleme.

Wenn ich in PASCAL,COBOL etc. sage "nutze als Parameter 1 Byte" dann 
macht er das auch, ausser im C "der Sprache die ja so Hardwarenah ist 
wie keine andere, der Sprache mit der man alles machen kann, da wird 
idiotischer Weise mit einem festen Datentyp int gearbeitet, weil der 
Standard verkorkst ist".

Sorry, ich bin übernächtigt, musste mal raus. Die nächste Frage bei der 
ich nicht weiterweis habe ich schon parat !

Gruß Hagen

von FBI (Gast)


Lesenswert?

Hi Hagen,

mit diesen Makros sollte es gehen
1
#define HH8(dw)  (*(((uint8_t*)&dw)+3))
2
#define HL8(dw)  (*(((uint8_t*)&dw)+2))
3
#define LH8(dw)  (*(((uint8_t*)&dw)+1))
4
#define LL8(dw)  ((uint8_t)dw)
also dann in etwa so
1
uint32_t dw;
2
3
dw = pgm_read_dword();
4
5
glcd.FontWidth = HH8(dw);
6
glcd.FontHeight = HL8(dw);
7
glcd.FontBitsPixel = LH8(dw);
8
glcd.FontFirstChar = LL8(dw);
eventuell stimmt die Reihenfolge der Bytes nicht, dann so rum
1
glcd.FontWidth = LL8(dw);
2
glcd.FontHeight = LH8(dw);
3
glcd.FontBitsPixel = HL8(dw);
4
glcd.FontFirstChar = HH8(dw);
CU

von Der A. (der-albi)


Lesenswert?

Wenn man davon ausgeht, dass in der Struktur die Members FontWidth, 
FontHeight, FontBitsPixel, FontFirstChar direkt hintereinander und immer 
in der Reihnfolge liegen könnte man das doch auch einfach casten, oder?

*((DWORD*)&glcd.FontWidth) = dwordvalue;

MFG

von FBI (Gast)


Lesenswert?

@Albi:
Ja das sollte auch gehen. Eventuell muß man dafür aber beim gcc noch die 
Option "-fpack-struct" mit angeben. Bei einzelnen Bytes (uint8_t) sollte 
er das aber eigentlich immer so machen. Bin jetzt aber zu faul 
nachzuschauen :)


Ansonsten kann man auch einfach die Bytes einzeln aus dem PGM lesen und 
sich die lokale Variable komplett sparen.
Die Funktion würde dann etwa so aussehen
1
void glcdSelectFont(void *data) {
2
  glcd.FontData = (glcdFontData_t)(data);
3
4
  glcd.FontWidth = pgm_read_byte(((uint8_t*)data)+3);
5
  glcd.FontHeight = pgm_read_byte(((uint8_t*)data)+2);
6
  glcd.FontBitsPixel = pgm_read_byte(((uint8_t*)data)+1);
7
  glcd.FontFirstChar = pgm_read_byte(data);
8
}

Wenn man aus dem Funtionsparameter gleich ein "uint8_t *data" macht, 
vereinfacht sich auch die Schreibweise noch etwas
1
void glcdSelectFont(uint8_t *data) {
2
  glcd.FontData = (glcdFontData_t)(data);
3
4
  glcd.FontWidth = pgm_read_byte(data+3);
5
  glcd.FontHeight = pgm_read_byte(data+2);
6
  glcd.FontBitsPixel = pgm_read_byte(data+1);
7
  glcd.FontFirstChar = pgm_read_byte(data);
8
}

CU Frank

von Hagen R. (hagen)


Lesenswert?

@Frank,

dedin letzter Vorschlag ist es den ich bisher benutzt habe. Ein Blick in 
die *.LST Datei verät dann das der GCC wiederum unnötige Operationen 
einfügt. Das war ja der Grund warum ich nach einer besseren Lösung 
suchte.

Deine Makros sind exakt das was ich suchte, danke. Ich werde sie noch 
testen und mich dann nochmal melden. Essentiell war es einfach das 
Problem das ich die richtigen Typcast nicht kenne. Allerdings könnte das 
#define LL8(dw)  ((uint8_t)dw) wieder zu einem Problem führen. Wenn ich 
einen Tipp abgeben sollte dann meine ich GCC wird bei diesem Makro 
erstmal 4 Register kopieren, davon dann 3 clearen und dann nur 1 
Register tatsächlöich benutzen, statt sofort und direkt nur 1 Register 
in dem der uint32_t gespeichert wurde zu benutzen. Es ging ja darum das 
der GCC 19 Takte benötigte für eine einfache Speihceroperation die 8 
Takte braucht.

@Albi,

Hm, wenn machbar würde ich solche Tricks eben vermeiden. Einfach um den 
Source übersichtlich zu halten.

Gruß Hagen

von Hagen R. (hagen)


Lesenswert?

1
#define HH8(dw)  (*(((uint8_t*)&dw)+3))
2
#define HL8(dw)  (*(((uint8_t*)&dw)+2))
3
#define LH8(dw)  (*(((uint8_t*)&dw)+1))
4
#define LL8(dw)  ((uint8_t)dw)

Shit, das geht auch nicht, bzw. erzeugt andere Probleme ;)

Der Cast zwingt den Compiler zu einem Stackframe, damit er auf Variable 
dw per Zeiger typcasten kann. Er muß also dw auf dem Stack ablegen damit 
der Cast dann funktionieren kann. Von der Effizienz her also noch 
ungünstiger als die anderen Vorschläge.

Bisher hat mein Cast über die Union die besten Resultate erzeugt, auch 
wenn der Sourcecode dadurch nicht mehr so elegant erscheint.

Der direkte Zugriff über pgm_read_byte() ist die zweitbeste Methode das 
sie
1.) den besten Sourcecode darstellt, eben straightforward
2.) nur 1 Taktzyklus zusätzlich pro Bytezugriff verschwendet, denoch 
unnötiger weise

Gruß Hagen

von Hagen R. (hagen)


Lesenswert?

So ich habs endlich. Vielleicht hiltfs ja auch anderen ;)

Nachfolgend erstmal die Funktionen um die 4 Bytes eines DWords zu 
extrahieren, ohne das

1.) lokal ein Stackkopie des DWords benötigt wird, bei Typcast über 
Zeiger ja nötig
2.) der GCC zusaätzliche Opcodes die sinnlos sind erzeugt
1
typedef union {
2
   uint32_t dword;
3
   struct {
4
     uint8_t a,b,c,d;
5
   };
6
} uint32_t_u;
7
8
static inline uint8_t HH8(uint32_t d) __attribute__((always_inline));
9
static inline uint8_t HH8(uint32_t d) {
10
11
   uint32_t_u r;
12
   r.dword = d;
13
   return(r.a);
14
}
15
16
static inline uint8_t HL8(uint32_t d) __attribute__((always_inline));
17
static inline uint8_t HL8(uint32_t d) {
18
19
   uint32_t_u r;
20
   r.dword = d;
21
   return(r.b);
22
}
23
24
static inline uint8_t LH8(uint32_t d) __attribute__((always_inline));
25
static inline uint8_t LH8(uint32_t d) {
26
27
   uint32_t_u r;
28
   r.dword = d;
29
   return(r.c);
30
}
31
32
static inline uint8_t LL8(uint32_t d) __attribute__((always_inline));
33
static inline uint8_t LL8(uint32_t d) {
34
35
   uint32_t_u r;
36
   r.dword = d;
37
   return(r.d);
38
}

Vielleicht findet ja einer noch eine bessere Lösung, bzw. er sagt einen 
Grund warum obige Lösung eventuell problembehaftet sein kann.

Angewendet wirds dann so:
1
void glcdSelectFont(void *data) {
2
3
    glcd.FontData = (glcdFontData_t)(data);
4
    uint32_t d = pgm_read_dword(glcd.FontData);
5
6
    glcd.FontWidth = HH8(d);
7
    glcd.FontHeight = HL8(d);
8
    glcd.FontBitsPixel = LH8(d);
9
    glcd.FontFirstChar = LL8(d);
10
}


und erzeugt dieses assembly:
1
 2026                 .global  glcdSelectFont
2
 2028                 glcdSelectFont:
3
 2029                 /* prologue: frame size=0 */
4
 2030                 /* prologue end (size=0) */
5
 2031 0b34 FC01          movw r30,r24
6
 2032 0b36 9093 0000     sts (glcd+44)+1,r25
7
 2033 0b3a 8093 0000     sts glcd+44,r24
8
 2034                 /* #APP */
9
 2035 0b3e 8591          lpm r24, Z+
10
 2036 0b40 9591          lpm r25, Z+
11
 2037 0b42 A591          lpm r26, Z+
12
 2038 0b44 B491          lpm r27, Z
13
 2039                   
14
 2040                 /* #NOAPP */
15
 2041 0b46 8093 0000     sts glcd+41,r24
16
 2042 0b4a 9093 0000     sts glcd+42,r25
17
 2043 0b4e A093 0000     sts glcd+43,r26
18
 2044 0b52 B093 0000     sts glcd+39,r27
19
 2045                 /* epilogue: frame size=0 */
20
 2046 0b56 0895          ret


Diese Funktionen sind ein sehr sinnvoller Ersatz für zb. Shifts der 
folgenden Art:
1
{
2
3
  uint32_t x = xyz;
4
5
  uint8_t a,b,c,d;
6
7
  a = x >> 24;
8
  b = x >> 16;
9
  c = x >>  8;
10
  a = x;
11
12
// stattdessen so
13
14
  a = HH8(x);
15
  b = HL8(x);
16
  c = LH8(x);
17
  d = LL8(x);
18
}

so hoffe ich ;)

Beipsiel:
1
uint8_t DoTest(uint32_t x) {
2
3
    uint8_t a,b,c,d;
4
5
    a = x >> 24;
6
    b = x >> 16;
7
    c = x >>  8;
8
    d = x;
9
10
    return(a ^ b ^ c ^ d);
11
}

erzeugt
1
2069                 .global  DoTest
2
 2071                 DoTest:
3
 2072                 /* prologue: frame size=0 */
4
 2073                 /* prologue end (size=0) */
5
 2074 0b68 9B01          movw r18,r22
6
 2075 0b6a AC01          movw r20,r24
7
 2076 0b6c 852F          mov r24,r21
8
 2077 0b6e 9927          clr r25
9
 2078 0b70 AA27          clr r26
10
 2079 0b72 BB27          clr r27
11
 2080 0b74 682F          mov r22,r24
12
 2081 0b76 CA01          movw r24,r20
13
 2082 0b78 AA27          clr r26
14
 2083 0b7a BB27          clr r27
15
 2084 0b7c 782F          mov r23,r24
16
 2085 0b7e BB27          clr r27
17
 2086 0b80 A52F          mov r26,r21
18
 2087 0b82 942F          mov r25,r20
19
 2088 0b84 832F          mov r24,r19
20
 2089 0b86 6727          eor r22,r23
21
 2090 0b88 6827          eor r22,r24
22
 2091 0b8a 6227          eor r22,r18
23
 2092 0b8c 862F          mov r24,r22
24
 2093 0b8e 9927          clr r25
25
 2094                 /* epilogue: frame size=0 */
26
 2095 0b90 0895          ret

und
1
uint8_t DoTest(uint32_t x) {
2
3
    uint8_t a,b,c,d;
4
5
    a = HH8(x);
6
    b = HL8(x);
7
    c = LH8(x);
8
    d = LL8(x);
9
10
    return(a ^b ^c ^d);
11
}

erzeugt
1
2069                 .global  DoTest
2
 2071                 DoTest:
3
 2072                 /* prologue: frame size=0 */
4
 2073                 /* prologue end (size=0) */
5
 2074 0b68 DC01          movw r26,r24
6
 2075 0b6a CB01          movw r24,r22
7
 2076 0b6c 282F          mov r18,r24
8
 2077 0b6e 2927          eor r18,r25
9
 2078 0b70 2A27          eor r18,r26
10
 2079 0b72 2B27          eor r18,r27
11
 2080 0b74 822F          mov r24,r18
12
 2081 0b76 9927          clr r25
13
 2082                 /* epilogue: frame size=0 */
14
 2083 0b78 0895          ret

statt 20 Takte nur noch 8 Takte ;)

Gruß Hagen

von Hagen R. (hagen)


Lesenswert?

und noch eins ;)
1
typedef union {
2
   int word;
3
   struct {
4
     uint8_t a,b;
5
   };
6
} int_u;
7
8
static inline uint8_t H8(int d) __attribute__((always_inline));
9
static inline uint8_t H8(int d) {
10
11
   int_u r;
12
   r.word = d;
13
   return(r.b);
14
}
15
16
static inline uint8_t L8(int d) __attribute__((always_inline));
17
static inline uint8_t L8(int d) {
18
19
   int_u r;
20
   r.word = d;
21
   return(r.a);
22
}
1
uint8_t DoTest(uint16_t x) {
2
3
    return((x >> 8) ^ (x));
4
}
1
 2074 0b68 292F          mov r18,r25
2
 2075 0b6a 3327          clr r19
3
 2076 0b6c 8227          eor r24,r18
4
 2077 0b6e 9927          clr r25
5
 2079 0b70 0895          ret
1
uint8_t DoTest(uint16_t x) {
2
3
    return(H8(x) ^ L8(x));
4
}
1
 2074 0b68 8927          eor r24,r25
2
 2075 0b6a 9927          clr r25
3
 2077 0b6c 0895          ret

Scheint das man das also generalisieren kann und der GCC damit immer 
besseren Code erzeugt. Besonderst das letzte ASM geht manuell gecodet 
nicht besser zu machen.

Gruß Hagen

von FBI (Gast)


Lesenswert?

geht alles :)
1
typedef union {
2
   uint32_t dword;
3
   struct {
4
     uint8_t a,b,c,d;
5
   };
6
} uint32_t_u;
7
8
#define HH8(dw)  (((uint32_t_u)dw).a)
9
#define HL8(dw)  (((uint32_t_u)dw).b)
10
#define LH8(dw)  (((uint32_t_u)dw).c)
11
#define LL8(dw)  (((uint32_t_u)dw).d)
12
13
void glcdSelectFont(void *data) {
14
  uint32_t d;
15
16
  glcd.FontData = (glcdFontData_t)(data);
17
  d = pgm_read_dword(glcd.FontData);
18
19
  glcd.FontWidth = HH8(d);
20
  glcd.FontHeight = HL8(d);
21
  glcd.FontBitsPixel = LH8(d);
22
  glcd.FontFirstChar = LL8(d);
23
}
1
typedef union {
2
   uint16_t word;
3
   struct {
4
     uint8_t a,b;
5
   };
6
} uint16_t_u;
7
8
#define H8(w)  (((uint16_t_u)w).a)
9
#define L8(w)  (((uint16_t_u)w).b)
10
11
uint8_t DoTest(uint16_t x) {
12
13
    return(H8(x) ^ L8(x));
14
}
erzeugt bei mir
1
43:       void glcdSelectFont(void *data) {
2
+00000051:   01FC        MOVW    R30,R24          Copy register pair
3
46:         glcd.FontData = (glcdFontData_t)(data);
4
+00000052:   93900105    STS     0x0105,R25       Store direct to data space
5
+00000054:   93800104    STS     0x0104,R24       Store direct to data space
6
47:         d = pgm_read_dword(glcd.FontData);
7
+00000056:   9185        LPM     R24,Z+           Load program memory and postincrement
8
+00000057:   9195        LPM     R25,Z+           Load program memory and postincrement
9
+00000058:   91A5        LPM     R26,Z+           Load program memory and postincrement
10
+00000059:   91B4        LPM     R27,Z            Load program memory
11
49:         glcd.FontWidth = HH8(d);
12
+0000005A:   93800106    STS     0x0106,R24       Store direct to data space
13
50:         glcd.FontHeight = HL8(d);
14
+0000005C:   93900107    STS     0x0107,R25       Store direct to data space
15
51:         glcd.FontBitsPixel = LH8(d);
16
+0000005E:   93A00108    STS     0x0108,R26       Store direct to data space
17
52:         glcd.FontFirstChar = LL8(d);
18
+00000060:   93B00109    STS     0x0109,R27       Store direct to data space
19
+00000062:   9508        RET                      Subroutine return
bzw.
1
66:       uint8_t DoTest(uint16_t x) {
2
+00000063:   2789        EOR     R24,R25          Exclusive OR
3
+00000064:   2799        CLR     R25              Clear Register
4
+00000065:   9508        RET                      Subroutine return

CU Frank

von FBI (Gast)


Lesenswert?

... und auch noch einer :)
diesmal auch noch ohne defines
1
typedef union {
2
   uint32_t dword;
3
   struct {
4
     uint8_t a,b,c,d;
5
   };
6
} uint32_t_u;
7
8
void glcdSelectFont(void *data) {
9
  glcd.FontData = (glcdFontData_t)(data);
10
  uint32_t_u d = (uint32_t_u)pgm_read_dword(glcd.FontData);
11
  glcd.FontWidth = d.a;
12
  glcd.FontHeight = d.b;
13
  glcd.FontBitsPixel = d.c;
14
  glcd.FontFirstChar = d.d;
15
}
1
typedef union {
2
   uint16_t word;
3
   struct {
4
     uint8_t a,b;
5
   };
6
} uint16_t_u;
7
8
uint8_t DoTest(uint16_t x) {
9
    return(((uint16_t_u)x).a ^ ((uint16_t_u)x).b);
10
}

CU

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.