mikrocontroller.net

Forum: Compiler & IDEs GCC inline assembler


Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Experten,

gesetzt den folgenden Code
{

   uint32_t d = pgm_read_dword(address);

   glcd.uint8_t_0 = d >> 24;
   glcd.uint8_t_1 = d >> 16;
   glcd.uint8_t_2 = d >>  8;
   glcd.uint8_t_3 = d;
}

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:
 1878                 /* #APP */
 1879 0b40 2591          lpm r18, Z+
 1880 0b42 3591          lpm r19, Z+
 1881 0b44 4591          lpm r20, Z+
 1882 0b46 5491          lpm r21, Z
 1883                   
 1884                 /* #NOAPP */
 1885 0b48 852F          mov r24,r21
 1886 0b4a 9927          clr r25
 1887 0b4c AA27          clr r26
 1888 0b4e BB27          clr r27
 1889 0b50 8093 0000     sts glcd+41,r24

 1890 0b54 CA01          movw r24,r20
 1891 0b56 AA27          clr r26
 1892 0b58 BB27          clr r27
 1893 0b5a 8093 0000     sts glcd+42,r24

 1894 0b5e BB27          clr r27
 1895 0b60 A52F          mov r26,r21
 1896 0b62 942F          mov r25,r20
 1897 0b64 832F          mov r24,r19
 1898 0b66 8093 0000     sts glcd+43,r24

 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:
 1878                 /* #APP */
 1879 0b40 2591          lpm r18, Z+
 1880 0b42 3591          lpm r19, Z+
 1881 0b44 4591          lpm r20, Z+
 1882 0b46 5491          lpm r21, Z
 1883                   
 1884                 /* #NOAPP */
 1889 0b50 8093 0000     sts glcd+41,r21
 1893 0b5a 8093 0000     sts glcd+42,r20
 1898 0b66 8093 0000     sts glcd+43,r19
 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
uint8_t = HiHi8(uint32_t);
uint8_t = HiLo8(uint32_t);
uint8_t = LoHi8(uint32_t);
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

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, einen Teilerfolg habe ich schon mal
 1878                 /* #APP */
 1879 0b40 8591          lpm r24, Z+
 1880 0b42 9591          lpm r25, Z+
 1881 0b44 A591          lpm r26, Z+
 1882 0b46 B491          lpm r27, Z
 1883                   
 1884 0b48 2B2F          mov r18, r27
 1885                   
 1886                 /* #NOAPP */
 1887 0b4a 2093 0000     sts glcd+41,r18
 1888                 /* #APP */
 1889 0b4e 2A2F          mov r18, r26
 1890                   
 1891                 /* #NOAPP */
 1892 0b50 2093 0000     sts glcd+42,r18
 1893                 /* #APP */
 1894 0b54 292F          mov r18,r25
 1895                   
 1896                 /* #NOAPP */
 1897 0b56 2093 0000     sts glcd+43,r18
 1898                 /* #APP */
 1899 0b5a 882F          mov r24,r24
 1900                   
 1901                 /* #NOAPP */
 1902 0b5c 8093 0000     sts glcd+39,r24

mit
#define HiHi8(addr)      \
(__extension__({                    \
    uint32_t __addr32 = (uint32_t)(addr); \
    uint8_t __result;               \
    __asm__                         \
    (                               \
        "mov %0, %D1" "\n\t"         \
        : "=r" (__result)           \
        : "r" (__addr32)           \
    );                              \
    __result;                       \
}))

#define HiLo8(addr)      \
(__extension__({                    \
    uint32_t __addr32 = (uint32_t)(addr); \
    uint8_t __result;               \
    __asm__                         \
    (                               \
        "mov %0, %C1" "\n\t"         \
        : "=r" (__result)           \
        : "r" (__addr32)           \
    );                              \
    __result;                       \
}))

#define LoHi8(addr)      \
(__extension__({                    \
    uint32_t __addr32 = (uint32_t)(addr); \
    uint8_t __result;               \
    __asm__                         \
    (                               \
        "mov %0,%B1" "\n\t"         \
        : "=r" (__result)           \
        : "r" (__addr32)           \
    );                              \
    __result;                       \
}))

#define LoLo8(addr)      \
(__extension__({                    \
    uint32_t __addr32 = (uint32_t)(addr); \
    uint8_t __result;               \
    __asm__                         \
    (                               \
        "mov %0,%A1" "\n\t"         \
        : "=r" (__result)           \
        : "r" (__addr32)           \
    );                              \
    __result;                       \
}))

void glcdSelectFont(void *data) {

    glcd.FontData = (glcdFontData_t)(data);

    uint32_t d = pgm_read_dword(glcd.FontData);
    glcd.FontWidth = HiHi8(d);
    glcd.FontHeight = HiLo8(d);
    glcd.FontBitsPixel = LoHi8(d);
    glcd.FontFirstChar = LoLo8(d);
}

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

Gehts besser ?

Gruß Hagen

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, es geht
typedef union {
    uint32_t dword;
    struct {
    uint8_t a,b,c,d;
    };

} uint32_t_u;

void glcdSelectFont(void *data) {

    glcd.FontData = (glcdFontData_t)(data);

    uint32_t_u d;
 
    d.dword = pgm_read_dword(glcd.FontData);

    glcd.FontWidth = d.a;
    glcd.FontHeight = d.b;
    glcd.FontBitsPixel = d.c;
    glcd.FontFirstChar = d.d;
}
 1878                 /* #APP */
 1879 0b40 8591          lpm r24, Z+
 1880 0b42 9591          lpm r25, Z+
 1881 0b44 A591          lpm r26, Z+
 1882 0b46 B491          lpm r27, Z
 1883                   
 1884                 /* #NOAPP */
 1885 0b48 8093 0000     sts glcd+41,r24
 1886 0b4c 9093 0000     sts glcd+42,r25
 1887 0b50 A093 0000     sts glcd+43,r26
 1888 0b54 B093 0000     sts glcd+39,r27

Lösung ist aber nicht sonderlich schön.

Gruß Hagen

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So ins blaue hinein:

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

In etwa so *untested*:
typedef union {
    uint32_t DataDword;
    struct {
    uint8_t FontWidth,
            FontHeight,
            FontBitsPixel,
            FontFirstChar;
    };

} uint32_t_u;

typedef struct
glcdFontData_s
{
    /* irgendwelche anderen daten... */
    uint32_t_u DataUnion;
} glcdFontData_t;

void glcdSelectFont(void *data) {
{
    glcd.FontData = (glcdFontData_t)(data);
    glcd.DataUnion.DataWord = pgm_read_dword(glcd.FontData);
}

  

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht 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:

  #define HH8(d)  (uint32_t_u)(d).a 

  uint32_t d = pgm_read_dword();
   
  glcd.FontWidth  = HH8(d); //  = (uint32_t_u)(d).a
  glcd.FontHeight = HL8(d);  
  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

Autor: FBI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Hagen,

mit diesen Makros sollte es gehen
#define HH8(dw)  (*(((uint8_t*)&dw)+3))
#define HL8(dw)  (*(((uint8_t*)&dw)+2))
#define LH8(dw)  (*(((uint8_t*)&dw)+1))
#define LL8(dw)  ((uint8_t)dw)
also dann in etwa so
uint32_t dw;

dw = pgm_read_dword();

glcd.FontWidth = HH8(dw);
glcd.FontHeight = HL8(dw);
glcd.FontBitsPixel = LH8(dw);
glcd.FontFirstChar = LL8(dw);
eventuell stimmt die Reihenfolge der Bytes nicht, dann so rum
glcd.FontWidth = LL8(dw);
glcd.FontHeight = LH8(dw);
glcd.FontBitsPixel = HL8(dw);
glcd.FontFirstChar = HH8(dw);
CU

Autor: Der Albi (der-albi)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: FBI (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
void glcdSelectFont(void *data) {
  glcd.FontData = (glcdFontData_t)(data);

  glcd.FontWidth = pgm_read_byte(((uint8_t*)data)+3);
  glcd.FontHeight = pgm_read_byte(((uint8_t*)data)+2);
  glcd.FontBitsPixel = pgm_read_byte(((uint8_t*)data)+1);
  glcd.FontFirstChar = pgm_read_byte(data);
}

Wenn man aus dem Funtionsparameter gleich ein "uint8_t *data" macht, 
vereinfacht sich auch die Schreibweise noch etwas
void glcdSelectFont(uint8_t *data) {
  glcd.FontData = (glcdFontData_t)(data);

  glcd.FontWidth = pgm_read_byte(data+3);
  glcd.FontHeight = pgm_read_byte(data+2);
  glcd.FontBitsPixel = pgm_read_byte(data+1);
  glcd.FontFirstChar = pgm_read_byte(data);
}

CU Frank

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert


#define HH8(dw)  (*(((uint8_t*)&dw)+3))
#define HL8(dw)  (*(((uint8_t*)&dw)+2))
#define LH8(dw)  (*(((uint8_t*)&dw)+1))
#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

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht 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
typedef union {
   uint32_t dword;
   struct {
     uint8_t a,b,c,d;
   };
} uint32_t_u;

static inline uint8_t HH8(uint32_t d) __attribute__((always_inline));
static inline uint8_t HH8(uint32_t d) {

   uint32_t_u r;
   r.dword = d;
   return(r.a);
}

static inline uint8_t HL8(uint32_t d) __attribute__((always_inline));
static inline uint8_t HL8(uint32_t d) {

   uint32_t_u r;
   r.dword = d;
   return(r.b);
}

static inline uint8_t LH8(uint32_t d) __attribute__((always_inline));
static inline uint8_t LH8(uint32_t d) {

   uint32_t_u r;
   r.dword = d;
   return(r.c);
}

static inline uint8_t LL8(uint32_t d) __attribute__((always_inline));
static inline uint8_t LL8(uint32_t d) {

   uint32_t_u r;
   r.dword = d;
   return(r.d);
}

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:
void glcdSelectFont(void *data) {

    glcd.FontData = (glcdFontData_t)(data);
    uint32_t d = pgm_read_dword(glcd.FontData);

    glcd.FontWidth = HH8(d);
    glcd.FontHeight = HL8(d);
    glcd.FontBitsPixel = LH8(d);
    glcd.FontFirstChar = LL8(d);
}


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


Diese Funktionen sind ein sehr sinnvoller Ersatz für zb. Shifts der 
folgenden Art:
{

  uint32_t x = xyz;

  uint8_t a,b,c,d;

  a = x >> 24;
  b = x >> 16;
  c = x >>  8;
  a = x;

// stattdessen so

  a = HH8(x);
  b = HL8(x);
  c = LH8(x);
  d = LL8(x);
}

so hoffe ich ;)

Beipsiel:
uint8_t DoTest(uint32_t x) {

    uint8_t a,b,c,d;

    a = x >> 24;
    b = x >> 16;
    c = x >>  8;
    d = x;

    return(a ^ b ^ c ^ d);
}

erzeugt
2069                 .global  DoTest
 2071                 DoTest:
 2072                 /* prologue: frame size=0 */
 2073                 /* prologue end (size=0) */
 2074 0b68 9B01          movw r18,r22
 2075 0b6a AC01          movw r20,r24
 2076 0b6c 852F          mov r24,r21
 2077 0b6e 9927          clr r25
 2078 0b70 AA27          clr r26
 2079 0b72 BB27          clr r27
 2080 0b74 682F          mov r22,r24
 2081 0b76 CA01          movw r24,r20
 2082 0b78 AA27          clr r26
 2083 0b7a BB27          clr r27
 2084 0b7c 782F          mov r23,r24
 2085 0b7e BB27          clr r27
 2086 0b80 A52F          mov r26,r21
 2087 0b82 942F          mov r25,r20
 2088 0b84 832F          mov r24,r19
 2089 0b86 6727          eor r22,r23
 2090 0b88 6827          eor r22,r24
 2091 0b8a 6227          eor r22,r18
 2092 0b8c 862F          mov r24,r22
 2093 0b8e 9927          clr r25
 2094                 /* epilogue: frame size=0 */
 2095 0b90 0895          ret

und
uint8_t DoTest(uint32_t x) {

    uint8_t a,b,c,d;

    a = HH8(x);
    b = HL8(x);
    c = LH8(x);
    d = LL8(x);

    return(a ^b ^c ^d);
}

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

statt 20 Takte nur noch 8 Takte ;)

Gruß Hagen

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und noch eins ;)
typedef union {
   int word;
   struct {
     uint8_t a,b;
   };
} int_u;

static inline uint8_t H8(int d) __attribute__((always_inline));
static inline uint8_t H8(int d) {

   int_u r;
   r.word = d;
   return(r.b);
}

static inline uint8_t L8(int d) __attribute__((always_inline));
static inline uint8_t L8(int d) {

   int_u r;
   r.word = d;
   return(r.a);
}
uint8_t DoTest(uint16_t x) {

    return((x >> 8) ^ (x));
}
 2074 0b68 292F          mov r18,r25
 2075 0b6a 3327          clr r19
 2076 0b6c 8227          eor r24,r18
 2077 0b6e 9927          clr r25
 2079 0b70 0895          ret
uint8_t DoTest(uint16_t x) {

    return(H8(x) ^ L8(x));
}
 2074 0b68 8927          eor r24,r25
 2075 0b6a 9927          clr r25
 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

Autor: FBI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
geht alles :)
typedef union {
   uint32_t dword;
   struct {
     uint8_t a,b,c,d;
   };
} uint32_t_u;

#define HH8(dw)  (((uint32_t_u)dw).a)
#define HL8(dw)  (((uint32_t_u)dw).b)
#define LH8(dw)  (((uint32_t_u)dw).c)
#define LL8(dw)  (((uint32_t_u)dw).d)

void glcdSelectFont(void *data) {
  uint32_t d;

  glcd.FontData = (glcdFontData_t)(data);
  d = pgm_read_dword(glcd.FontData);

  glcd.FontWidth = HH8(d);
  glcd.FontHeight = HL8(d);
  glcd.FontBitsPixel = LH8(d);
  glcd.FontFirstChar = LL8(d);
}
typedef union {
   uint16_t word;
   struct {
     uint8_t a,b;
   };
} uint16_t_u;

#define H8(w)  (((uint16_t_u)w).a)
#define L8(w)  (((uint16_t_u)w).b)

uint8_t DoTest(uint16_t x) {

    return(H8(x) ^ L8(x));
}
erzeugt bei mir
43:       void glcdSelectFont(void *data) {
+00000051:   01FC        MOVW    R30,R24          Copy register pair
46:         glcd.FontData = (glcdFontData_t)(data);
+00000052:   93900105    STS     0x0105,R25       Store direct to data space
+00000054:   93800104    STS     0x0104,R24       Store direct to data space
47:         d = pgm_read_dword(glcd.FontData);
+00000056:   9185        LPM     R24,Z+           Load program memory and postincrement
+00000057:   9195        LPM     R25,Z+           Load program memory and postincrement
+00000058:   91A5        LPM     R26,Z+           Load program memory and postincrement
+00000059:   91B4        LPM     R27,Z            Load program memory
49:         glcd.FontWidth = HH8(d);
+0000005A:   93800106    STS     0x0106,R24       Store direct to data space
50:         glcd.FontHeight = HL8(d);
+0000005C:   93900107    STS     0x0107,R25       Store direct to data space
51:         glcd.FontBitsPixel = LH8(d);
+0000005E:   93A00108    STS     0x0108,R26       Store direct to data space
52:         glcd.FontFirstChar = LL8(d);
+00000060:   93B00109    STS     0x0109,R27       Store direct to data space
+00000062:   9508        RET                      Subroutine return
bzw.
66:       uint8_t DoTest(uint16_t x) {
+00000063:   2789        EOR     R24,R25          Exclusive OR
+00000064:   2799        CLR     R25              Clear Register
+00000065:   9508        RET                      Subroutine return

CU Frank

Autor: FBI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... und auch noch einer :)
diesmal auch noch ohne defines
typedef union {
   uint32_t dword;
   struct {
     uint8_t a,b,c,d;
   };
} uint32_t_u;

void glcdSelectFont(void *data) {
  glcd.FontData = (glcdFontData_t)(data);
  uint32_t_u d = (uint32_t_u)pgm_read_dword(glcd.FontData);
  glcd.FontWidth = d.a;
  glcd.FontHeight = d.b;
  glcd.FontBitsPixel = d.c;
  glcd.FontFirstChar = d.d;
}
typedef union {
   uint16_t word;
   struct {
     uint8_t a,b;
   };
} uint16_t_u;

uint8_t DoTest(uint16_t x) {
    return(((uint16_t_u)x).a ^ ((uint16_t_u)x).b);
}

CU

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.