C xc8 rozkald double na byty
Miroslav Draxal
evik na volny.cz
Středa Květen 17 10:51:22 CEST 2017
Ještě výtah z *.lst
168 psect eeprom_data
169 F00000 5A 61 76 6C 61 68 61 30 db
90,97,118,108,97,104,97,48 ;#
170 F00008 66 69 72 6D 77 30 2E 30 db
102,105,114,109,119,48,46,48 ;#
171 F00010 00 00 00 00 00 00 00 00 db 0,0,0,0,0,0,0,0 ;#
172 F00018 00 00 00 00 00 00 00 00 db 0,0,0,0,0,0,0,0 ;#
173 F00020 07 0A 00 05 03 0A 00 00 db 7,10,0,5,3,10,0,0
;#
174 F00028 01 32 05 0A 14 01 FF FE db
1,50,5,10,20,1,255,254 ;#
175 F00030 01 FF FE 01 FF FE 01 FF db
1,255,254,1,255,254,1,255 ;#
176 F00038 FE 01 FF FE 01 FF FE 01 db
254,1,255,254,1,255,254,1 ;#
177 F00040 FF FE 00 00 00 00 00 00 db 255,254,0,0,0,0,0,0
;#
178 F00048 03 23 02 05 04 0E 0C 00 db 3,35,2,5,4,14,12,0
;#
179 F00050 09 05 00 00 00 00 00 00 db 9,5,0,0,0,0,0,0 ;#
180 F00058 00 00 00 00 00 90 18 44 db 0,0,0,0,0,144,24,68
;# // TADY JE ULOŽENO 610.25
181 F00060 07 08 05 00 01 00 02 14 db 7,8,5,0,1,0,2,20
;#
182 F00068 14 0F 00 05 06 06 0F 00 db 20,15,0,5,6,6,15,0
;#
183 F00070 03 0A 0A 0F 00 07 0F 0F db 3,10,10,15,0,7,15,15
;#
184 F00078 0F 00 01 14 14 0F 00 04 db 15,0,1,20,20,15,0,4
;#
185 F00080 09 09 0F 00 06 0F 0F 0F db 9,9,15,0,6,15,15,15
;#
186 F00088 00 08 0A 0A 0F 00 02 0A db 0,8,10,10,15,0,2,10
;#
187 F00090 0A 0F 00 01 0A 0A 00 00 db 10,15,0,1,10,10,0,0
;#
-----Original Message-----
From: Hw-list [mailto:hw-list-bounces na list.hw.cz] On Behalf Of Miroslav
Draxal
Sent: Wednesday, May 17, 2017 10:42 AM
To: 'HW-news'
Subject: RE: C xc8 rozkald double na byty
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