Dieser Code erzeugt eine wahnsinnig lange ASM-Funktion:
1
000000e2 <transmitData>:
2
e2: cf 93 push r28
3
e4: df 93 push r29
4
e6: ec 01 movw r28, r24
5
e8: 86 2f mov r24, r22
6
ea: 0e 94 60 00 call 0xc0 ; 0xc0 <spi_transmit>
7
ee: e9 81 ldd r30, Y+1 ; 0x01
8
f0: fa 81 ldd r31, Y+2 ; 0x02
9
f2: 90 81 ld r25, Z
10
f4: 21 e0 ldi r18, 0x01 ; 1
11
f6: 30 e0 ldi r19, 0x00 ; 0
12
f8: 08 80 ld r0, Y
13
fa: 02 c0 rjmp .+4 ; 0x100 <transmitData+0x1e>
14
fc: 22 0f add r18, r18
15
fe: 33 1f adc r19, r19
16
100: 0a 94 dec r0
17
102: e2 f7 brpl .-8 ; 0xfc <transmitData+0x1a>
18
104: 92 2b or r25, r18
19
106: 90 83 st Z, r25
20
108: df 91 pop r29
21
10a: cf 91 pop r28
22
10c: 08 95 ret
Man beachte dass der Teil zum löschen des Pins auskommentiert ist, sonst
wäre die gesamte Sequenz hinter dem call spi_transmit noch einma davor.
Nun meine Frage:
Kann ich den Compiler irgendwie dazu bewegen meinen Code mit dem Umweg
über die "Konstante" genauso zu übersetzen wie wenn ich eine direkte
Portzuweisung machen würde?
mfg
nga
Wenn du die Funktion "static" machst, dann kann er sie inline
ersetzen. Ansonsten kann der Compiler natürlich innerhalb von
transmitData() nicht ahnen, mit welchen Parametern sie irgendwann
konkret gerufen wird. Wäre höchstens, dass die linker relaxations
das noch rausreißen können, aber das kann ich mir angesichts der
Komplexität der notwendigen Optimierung schwer vorstellen.
Tatsache, das mit dem static hilft schon einmal.
Danke schon mal.
Würde evtl ein C++ Compiler besseren Code erzeugen (wegen echten
Konstanten)? Evtl auch mit templates?
eigentlich sollte es ein C-Programm werden...
Oder gibt es andere Vorschläge?
nga schrieb:> Würde evtl ein C++ Compiler besseren Code erzeugen (wegen echten> Konstanten)?
Auch nur unter vergleichbaren Umständen: wenn die Adressen der
jeweiligen Ports und Portbits zur Compilezeit nicht bekannt sind, dann
kann der Compiler natürlich keine IN/OUT-Befehle generieren (für die
die Port- und Bitnummer ja im Opcode stehen), sondern nur LDS/STS.
Wie wird es wenn du alles in ein Array packst und über den Index
auswählst? Das hat noch den entscheidenden Vorteil, dass der Aufrufer
nix mit den slave_t zu tun haben muss.
Ausserdem kann das Bit-shiften in der Configuration stattfinden.
nga schrieb:> Dieser Code erzeugt eine wahnsinnig lange ASM-Funktion:
Nicht nur das.
Du erzeugst 3 Structs a 6 Byte, die müssen befüllt, übergeben und wieder
auseinander gefummelt werden.
Das kostet natürlich.
Du mußt schon dem Compiler etwas entgegenkommen und möglichts oft
Konstanten benutzen.
Es reicht außerdem völlig, wenn man unterschiedliche Select-Pins hat.
Und da bietet es sich an, alle auf den selben Port zu legen und nur die
Maske zu übergeben:
kurzes Update:
Peter Dannegger schrieb:> Du mußt schon dem Compiler etwas entgegenkommen und möglichts oft> Konstanten benutzen.
Das ist natürlich klar. Ich habe es ja versucht mittels const den
Compiler die Variable als Konstante zu sehen, leider ist C da nicht so
klar...
Peter Dannegger schrieb:> Es reicht außerdem völlig, wenn man unterschiedliche Select-Pins hat.> Und da bietet es sich an, alle auf den selben Port zu legen und nur die> Maske zu übergeben
Ich stimme dir voll zu. Aber in dem struct werden auch noch die Daten
gespeichert, deswegen wollte ich die 'Konstanten' dort speichern.
Bleibt abschließend zu sagen, dass
Eric B. schrieb:> Zur Run-Time Optimierung könnte man dann noch switch/casen über den> index:
das hier genau wie gewollt funktioniert hat:
es werden sbi und cbi Instruktionen erzeugt!
Danke an alle
nga schrieb:> Ich stimme dir voll zu. Aber in dem struct werden auch noch die Daten> gespeichert, deswegen wollte ich die 'Konstanten' dort speichern.
Da liegt dann der grundsätzliche Fehler: Konfiguration (konstant -> kann
ins ROM/Flash) und Nutzdaten (variabel -> muss ins RAM) soll man nicht
mischen.