Pupsomat schrieb:
> Ok, das funktioniert. Vergrößert aber das Programm um 200 Bytes...
__memx verwendet 24-Bit Zeuger anstatt der sonst üblichen 16 Bits.
Zudem muß bei jedem Zugriff zur Laufzeit getestet werden, ob dieser
vom Flash oder aus dem RAM lesen soll.
Evtl. ist man dann händisch besser dran:
1 | int get_int (const int *p, bool from_flash)
|
2 | {
|
3 | if (from_flash)
|
4 | return *(const __flash int*) p;
|
5 | else
|
6 | return *p;
|
7 | }
|
Das testet zwar auch zur Laufzeit, aber vielleicht wird der Code so
kleiner. Falls die Funktion nicht allzu groß ist und der Aufrufer weiß,
von wo er lesen will, kann es lohnen zu inlinen:
1 | static inline int
|
2 | get_int (const int *p, bool from_flash)
|
3 | {
|
4 | if (from_flash)
|
5 | return *(const __flash int*) p;
|
6 | else
|
7 | return *p;
|
8 | }
|
9 |
|
10 | extern int a, b, val_b;
|
11 | extern const __flash int val_a;
|
12 |
|
13 | void set_ab (void)
|
14 | {
|
15 | a = get_int (&val_a, true);
|
16 | b = get_int (&val_b, false);
|
17 | }
|
gibt:
1 | set_ab:
|
2 | ldi r30,lo8(val_a)
|
3 | ldi r31,hi8(val_a)
|
4 | lpm r24,Z+
|
5 | lpm r25,Z+
|
6 | sts a+1,r25
|
7 | sts a,r24
|
8 | lds r24,val_b
|
9 | lds r25,val_b+1
|
10 | sts b+1,r25
|
11 | sts b,r24
|
12 | ret
|
Versucht man das gleiche mit __memx:
1 | static inline int
|
2 | get_int (const __memx int *p)
|
3 | {
|
4 | return *p;
|
5 | }
|
6 |
|
7 | void set_ab (void)
|
8 | {
|
9 | a = get_int (&val_a);
|
10 | b = get_int (&val_b);
|
11 | }
|
dann ist der Code größer; ohne die Bibliotheksfunktion __xload2:
1 | set_ab:
|
2 | ldi r24,lo8(val_a)
|
3 | ldi r25,hi8(val_a)
|
4 | ldi r26,0
|
5 | movw r30,r24
|
6 | mov r21,r26
|
7 | call __xload_2
|
8 | sts a+1,r23
|
9 | sts a,r22
|
10 | ldi r24,lo8(val_b)
|
11 | ldi r25,hi8(val_b)
|
12 | ldi r26,lo8(-128)
|
13 | movw r30,r24
|
14 | mov r21,r26
|
15 | call __xload_2
|
16 | sts b+1,r23
|
17 | sts b,r22
|
18 | ret
|
Die Möglichkeiten für avr-gcc das zu optimieren sind beschränkt. Grund
sind Situationen wie diese:
1 | #include <avr/pgmspace.h>
|
2 |
|
3 | extern void foo_P (const __memx char *);
|
4 |
|
5 | void hallo (void)
|
6 | {
|
7 | foo_P (PSTR ("Hallo"));
|
8 | }
|
Der Zeiger, den PSTR zurückliefert, liegt formal im Generic Address
Space (RAM), enthält aber eine Flash-Adresse. Für dieses Beispiel
erzeugt der Compiler Code wie erwartet, d.h. übergibt an foo_P einen
24-Bit Zeiger aufs Flash.
Dummerweise ist das, was PSTR macht, nicht auf Embedded-C abbildbar.