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