C xc8 rozkald double na byty

Jaromir Sukuba jarin.hw na gmail.com
Středa Květen 17 11:03:50 CEST 2017


v pic.h (includovany z xc.h) je makro

#if    EEPROM_SIZE > 0
#define __EEPROM_DATA(a, b, c, d, e, f, g, h) \
             asm("\tpsect eeprom_data,class=EEDATA,delta=2,space=3,noexec"); \
             asm("\tdb\t" ___mkstr(a) "," ___mkstr(b) "," ___mkstr(c)
"," ___mkstr(d) "," \
                      ___mkstr(e) "," ___mkstr(f) "," ___mkstr(g) ","
___mkstr(h))
#endif

mkstr je

#define    ___mkstr1(x)    #x
#define    ___mkstr(x)    ___mkstr1(x)


teda rozvinie sa to do pseudoinstrukcii assembleru, ktore su nim spracovane.
To makro je pomerne jednoducho urobene, daju sa urobit aj makra ktore
definuju odkial a kam maju siahat data v EEPROM, napriklad.


Dňa 17. mája 2017, 10:42, Miroslav Draxal <evik na volny.cz> napísal/a:
> Preprocesor to v xc8 rozvine takto (v editoru MPLABX klik myš
> pravé=>navigate>View Macro Expansion)
>
> #define CelkovyVykon_kWh_rokDb_EEPROM 610.250
>
> __EEPROM_DATA(0, // byt0 CelkovyVykon_kWh_denDb
>               0, // byt1
>               0, // byt3
>               0, // byt4 CelkovyVykon_kWh_denDb - pokud je double 4bytová
> přesnost
>               CelkovyVykon_kWh_rokDb_EEPROM & 0xff, // byt0
> CelkovyVykon_kWh_rokDb
>               (CelkovyVykon_kWh_rokDb_EEPROM >> 8) &0xff, // byt2
>               (CelkovyVykon_kWh_rokDb_EEPROM >> 16) &0xff, // byt3
>               (CelkovyVykon_kWh_rokDb_EEPROM >> 24) &0xff); // byt4
> CelkovyVykon_kWh_rokDb - pokud je double 4bytová přesnost
>
>
>
> asm("\tpsect eeprom_data,class=EEDATA,noexec");
> asm("\tdb\t" "0" "," "0" "," "0" "," "0" "," "610.250&0xff" ","
> "(610.250>>8)&0xff" "," "(610.250>>16)&0xff" "," "(610.250>>24)&0xff" ); //
> byt4 CelkovyVykon_kWh_rokDb - pokud je double 4bytová přesnost
>
> Asi to budu psát zbytečně, ale : Zde se nic nepřekládá do asm, ale rovnou se
> hodnoty zapíší do bloku eeprom, který je součástí *.hex, který se rovnou
> ukládá do mikrokontroleru spolu s obsahem Flash, konfig byty a User ID (vše
> součást *.hex).
> Míra
>
>
> -----Original Message-----
> From: Hw-list [mailto:hw-list-bounces na list.hw.cz] On Behalf Of Jan Waclawek
> Sent: Tuesday, May 16, 2017 11:20 PM
> To: HW-news
> Subject: Re: C xc8 rozkald double na byty
>
>>Skusit nieco mozem, ale neviem presne co mam skusit, daj mi prosim
>>blizsi popis, stracam sa v tom.
>
> Tak som prisiel na to, ze neviem. Skusim to zhrnut.
>
> Ulohou je s pouzitim prekladaca (podla moznosti nativneho pre danu
> platformu, aby sa vylucili medziplatformove nekompatibility binarnej
> reprezentacie typov) vygenerovat binarny inicializator pre float (alebo
> akukolvek inu viac-nez-jednobytovu premennu) s pouzitim makra
> __EEPROM_DATA(), ktore akceptuje jednotlive byty.
>
>
> 0. Navod od Jana Zuffu
> http://list.hw.cz/pipermail/hw-list/2017-May/499344.html, ktory v tom XC8
> funguje, vklada vyraz typu
>
> (123.4 >> 8) & FF
>
> do makra __EEPROM_DATA(). Kedze ten vyraz je nelegalny v C (operator >>
> vyzaduje aby oba operandy boli celociselne), toto funguje len vdaka tomu, ze
> __EEPROM_DATA() je makro ktore vedie na inline assembler, v ktorom je
> uvedeny vyraz uz legalny (k tomu, aby bolo jasne, co v tom asembleri je
> alebo nie je legalne treba nastudovat spomenutu kapitolu 6 z manualu XC8).
> Toto teda nie je ani v naznaku prenositelne.
>
> Bolo by super vidiet, ako presne vyzera to makro __EEPROM_DATA() (ak je to
> vobec makro a nie intrinzicka funkcia prekladaca); a ako ju kompilator
> prelozi do asembleru.
>
>
>
> Pre dalsie pokusy, ktore som dufal, ze budu prenositelne, som si pre avr-gcc
> vyrobil moje makro __EEPROM_DATA() ktore vlozene byty pouzije ako
> inicializator pola bytov.
>
> 1. Type punning skrz pretypovanie smernikov, podla panov kolegov Hamouza
> http://list.hw.cz/pipermail/hw-list/2017-May/499341.html a Stengla
> http://list.hw.cz/pipermail/hw-list/2017-May/499449.html - vid makro BB3() a
> "attempt 2" dole.
>
> Toto si vyzaduje definovat inicializovanu float premennu ff; napriek tomu ze
> je oznacena ako const, tie jednotlive "rozobrate byty" (ktorych hodnotu by
> teda mohol poznat v case kompilacie) v inicializatore prekladac nepoklada za
> konstantne a tym padom nedovoli pouzit ako inicializator globalnej ci
> statickej premennej. Na ukazku je to teda pouzite ako inicializovana lokalna
> premenna, ktoru prekladac samozrejme drzi na stacku a nema pre nu
> inicializator, ale pri vstupe do funkcie ho nakopiruje z povodnej premennej
> ff:
>
>   61 003c 8091 0000             lds r24,ff
>   62 0040 9091 0000             lds r25,ff+1
>   63 0044 2091 0000             lds r18,ff+2
>   64 0048 3091 0000             lds r19,ff+3
>   65 004c 8987                  std Y+9,r24
>   66 004e 9A87                  std Y+10,r25
>   67 0050 2B87                  std Y+11,r18
>   68 0052 3C87                  std Y+12,r19
>
> Tadialto cesta teda nevedie.
>
>
> 2a. Type punning skrze union, podla pana kolegu Mraza
> http://list.hw.cz/pipermail/hw-list/2017-May/499350.html - makro BB2() v
> "attempt 1".
>
> Vysledok je - nie prilis prekvapujuco - presne ten isty.
>
>   53 0024 8091 0000             lds r24,rb
>   54 0028 9091 0000             lds r25,rb+1
>   55 002c 2091 0000             lds r18,rb+2
>   56 0030 3091 0000             lds r19,rb+3
>   57 0034 8D83                  std Y+5,r24
>   58 0036 9E83                  std Y+6,r25
>   59 0038 2F83                  std Y+7,r18
>   60 003a 3887                  std Y+8,r19
>
>
> 2b. Type punning skrze union s pouzitim compound literal podla C99 6.5.2.5
> (makro BB1()) - ten XC8 je len ciastocne C99-kompatibilny (je proklamovany
> ako C89, a compound literals su novinka v C99), takze ani toto vlastne nie
> je riesenie povodneho problemu, ale vkladal som do neho velke nadeje, lebo
> je tu vyluceny medzikrok cez pomocnu premennu.
>
> A nic... gcc ani toto nepoklada za konstantny inicializator, takze znova len
> na ukazku ako lokalna premenna, aj ked ju gcc - celkom pochopitelne -
> inicializuje konstantami (ale nie z inicializacneho segmentu):
>
>   45 0014 8DEC                  ldi r24,lo8(-51)
>   46 0016 8983                  std Y+1,r24
>   47 0018 8CEC                  ldi r24,lo8(-52)
>   48 001a 8A83                  std Y+2,r24
>   49 001c 86EF                  ldi r24,lo8(-10)
>   50 001e 8B83                  std Y+3,r24
>   51 0020 82E4                  ldi r24,lo8(66)
>   52 0022 8C83                  std Y+4,r24
>
>
>
>
> Este si dovolim poznamky ku generovaniu inicializatora inak nez pouzitim
> __EEPROM_DATA() (t.j. tiez nie odpoved na povodnu otazku):
>
> 3. Dovolil som si inline asm v tom avr-gcc. Toto funguje a je pochopitelne
> dokonale neprenositelne, mozno ani medzi roznymi inkarnaciami (targetmi)
> gcc, ba dokonca ani medzi roznymi verziami avr-gcc (skusil som 4.2 a 4.8 a v
> oboch to fungovalo, ale ten inline asm pochopitelne nie je standardizovany
> takze to v novsej verzii moze zacat nefungovat). Kedze, ako som uz bol
> pisal, avr-as "nezozerie" floating-point konstanty, tuna som si vypomohol
> podvodom, ked kompilator pri preklade z inline asembleru pouzije constraint
> "i" (co je predpis ze "vyrob z daneho parametra integer konstantu"), a
> asembler ho nasledne rozbije na byty. Ako parameter namiesto (FF) ani tu
> nemozem pouzit (FF >> 8) lebo to je C vyraz vyhodnocovany kompilatorom, t.j.
> pre neho plati ta podmienka ze operandy
>>> musia byt celociselne.
>
> Takto to prelozi kompilator:
>   18                            .section .eeprom
>   19 0000 CD                    .byte 0x42f6cccd & 0xFF
>   20 0001 CC                    .byte 0x42f6cccd >> 8 & 0xFF
>   21 0002 F6                    .byte 0x42f6cccd >> 16 & 0xFF
>   22 0003 42                    .byte 0x42f6cccd >> 24 & 0xFF
>   23                            .text
> a s tymto si uz asembler hravo poradi.
>
>
>
> 4. Jeden pomerne dobry sposob, nie prenositelny v detailoch ale ako
> myslienka mozno uplatnitelny u mnohych prekladacov, je vygenerovanie
> inicializatora pre nativne inicializovane premenne (ci uz RAM alebo FLASH) a
> potom ho nejakym sposobom vyextrahovat z vysledneho binaru. Ta extrakcia je
> pochopitelne zavisla od toolchainu, ale castokrat su tie inicializatory
> pomerne dobre oddelitelne vdaka umiestneniu v osobitnych sekciach. Toto moze
> nezafungovat u prechytralych prekladacov (ktorym je aj ten XC8 mimochodom, a
> do urcitej miery aj SDCC), ktore bud inicializuju kodom a nie kopirovanim
> bloku, alebo ktore maju tendenciu brutalne vyoptimalizovat nepouzivane alebo
> malo pouzivane premenne az do ich uplnej eliminacie spomedzi
> inicializovanych premennych.
>
>
> wek
>
>
>
>
>
>
>
> #include <stdint.h>
> #define SUPERGLUE(a, b) a##b
> #define GLUE(a, b) SUPERGLUE(a, b)
> #define __EEPROM_DATA(a, b, c, d) const volatile uint8_t GLUE(aa,
> __LINE__)[] = {a, b, c, d};
>
>
> #define FF 123.4f  // 0x42f6cccd
>
> // ---------- attempt 1 - type punning through union //
> http://list.hw.cz/pipermail/hw-list/2017-May/499350.html
> #define REAL float
> #define BYTE uint8_t
> typedef union rb_u {
>   const REAL r;
>   const BYTE b[sizeof (REAL)];
> } rbu_t;
> const rbu_t rb = {.r=FF};
> #define BB1(f, byte) ((const rbu_t){.r = (f)}).b[(byte)] #define BB2(f,
> byte) rb.b[byte]
>
>
> // ---------- attempt 2 - type punning through pointer cast //
> http://list.hw.cz/pipermail/hw-list/2017-May/499341.html
> // http://list.hw.cz/pipermail/hw-list/2017-May/499449.html
> #define BB3(f, byte)  (((uint8_t *)&(f))[(byte)]) const REAL ff = FF;
>
>
> // ---------- attempt 3 - gcc-specific inline asm void dummy(void)
> __attribute__((naked)); void dummy(void) {
>   __asm(
>     "\n\t" ".section .eeprom"
>     "\n\t" ".byte %0 & 0xFF"
>     "\n\t" ".byte %0 >> 8 & 0xFF"
>     "\n\t" ".byte %0 >> 16 & 0xFF"
>     "\n\t" ".byte %0 >> 24 & 0xFF"
>     "\n\t" ".text"
>     :
>     : "i" (FF)
>   );
> };
>
> int main(void) {
>   __EEPROM_DATA(BB1(FF, 0), BB1(FF, 1), BB1(FF, 2), BB1(FF, 3));
>   __EEPROM_DATA(BB2(FF, 0), BB2(FF, 1), BB2(FF, 2), BB2(FF, 3));
>   __EEPROM_DATA(BB3(ff, 0), BB3(ff, 1), BB3(ff, 2), BB3(ff, 3)); }
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.cz Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list


Další informace o konferenci Hw-list