Forum: Compiler & IDEs SDCC Inline Assembler zur Laufzeitoptimierung


von Tobias K. (tobias-k)


Lesenswert?

Hallo,

ich arbeite gerade an einem kleinem Projekt für eine Bus-Schnittstelle. 
Dabei will ich, um die Code Laufzeit zu erhöhen Inline Assembly 
verwenden. Leider habe ich das bisher noch nie verwendet und habe 
desshalb so meine Startschwierigkeiten.
Mir sind beim betrachten des ASM Codes einige Stellen aufgefallen, die 
sich optimieren lassen, jedoch weis ich nicht genau, wie ich das im C 
Code einfügen kann.

Bsp 1:
unverändert
1
;  CANish_controller.c: 125: switch (ui16_msg_sendBuff & 0x1F00) {    //Wenn nötig Stopfbit einfügen
2
  mov  a, _ui16_msg_sendBuff+1
3
  mov  p, a
4
  mov  a, _ui16_msg_sendBuff+0
5
  clear  _send_msg_sloc0_1_0+0
6
  mov  a, p
7
  and  a, #0x1f
8
  mov  _send_msg_sloc0_1_0+1, a
9
  mov  a, _send_msg_sloc0_1_0+0
10
  ceqsn  a, #0x00
11
  goto  00177$
12
  mov  a, _send_msg_sloc0_1_0+1
13
  cneqsn  a, #0x00
14
  goto  00103$
15
00177$:
16
  mov  a, _send_msg_sloc0_1_0+0
17
  ceqsn  a, #0x00
18
  goto  00104$
19
  mov  a, _send_msg_sloc0_1_0+1
20
  ceqsn  a, #0x1f
21
  goto  00104$

optimiert
1
;  CANish_controller.c: 125: switch (ui16_msg_sendBuff & 0x1F00) {    //Wenn nötig Stopfbit einfügen
2
  mov  a, _ui16_msg_sendBuff+1
3
  and  a, #0x1f
4
  cneqsn  a, #0x00
5
  goto  00103$
6
00177$:
7
  ceqsn  a, #0x1f   (Compare ACC with immediate data and skip next instruction if both are equal.)
8
  goto  00104$

Wie in Bsp 1 sollten sich einige sachen vereinfach lassen, jedoch ist 
mir rätselhalft wie ich das fließend in den C Code einbinde, ohne den 
completten ASM abschnitt zu kopieren und und anzupassen. Ich würde gerne 
immer nur bestimmte abschnitte optimieren, damit vom C so viel wie 
möglich erhalten bleibt, da das Programm noch nicht fertig ist und es 
noch anpassungen geben wird. Ich hoffe, dass ihr mir weiterhelfen könnt.


Gesamter Code:
C Code
1
switch (ui16_msg_sendBuff & 0x1F00) {    //Wenn nötig Stopfbit einfügen
2
                case 0x1F00:  //Die letzten 5 Bits waren eine 1, also 0 senden
3
                  ui16_msg_sendBuff = ui16_msg_sendBuff & 0xFEFF;    //Das letzte gesendete Bit wird auf 0 gesetzt
4
                  SEND_DATA_DOMINANT;
5
                
6
                break;
7
                  
8
                case 0x0000:  //Die letzten 5 Bits waren eine 0, also 1 senden
9
                  ui16_msg_sendBuff = ui16_msg_sendBuff | 0x0100;    //Das letzte gesendete Bit wird auf 1 gesetzt                  
10
                  SEND_DATA_RECESSIVE;
11
                
12
                break;
13
                
14
                default:
15
                  switch (0x0080 & ui16_msg_sendBuff) {
16
                    case 0:
17
                      SEND_DATA_DOMINANT;
18
                    break;
19
                    
20
                    default:
21
                      SEND_DATA_RECESSIVE;
22
                    break;
23
                  }
24
                  
25
                  ui16_msg_sendBuff = ui16_msg_sendBuff << 1;
26
                  ui8_sendBits++;
27
                  //ui8_counter_send_sameBit++;
28
                
29
                break;
30
              }    
31
              
32
              
33
              switch (ui8_sendBits & 0x07) {
34
                case 0:
35
                  ui16_msg_sendBuff = (ui16_msg_sendBuff & 0xFF00) | ui8Arr_msg[ui8_sendBits >> 3];
36
                  break;
37
              }

Vom Compiler generierter ASM Code:
1
;  CANish_controller.c: 125: switch (ui16_msg_sendBuff & 0x1F00) {    //Wenn nötig Stopfbit einfügen
2
  mov  a, _ui16_msg_sendBuff+1
3
  mov  p, a
4
  mov  a, _ui16_msg_sendBuff+0
5
  clear  _send_msg_sloc0_1_0+0
6
  mov  a, p
7
  and  a, #0x1f
8
  mov  _send_msg_sloc0_1_0+1, a
9
  mov  a, _send_msg_sloc0_1_0+0
10
  ceqsn  a, #0x00
11
  goto  00177$
12
  mov  a, _send_msg_sloc0_1_0+1
13
  cneqsn  a, #0x00
14
  goto  00103$
15
00177$:
16
  mov  a, _send_msg_sloc0_1_0+0
17
  ceqsn  a, #0x00
18
  goto  00104$
19
  mov  a, _send_msg_sloc0_1_0+1
20
  ceqsn  a, #0x1f
21
  goto  00104$
22
;  CANish_controller.c: 127: ui16_msg_sendBuff = ui16_msg_sendBuff & 0xFEFF;    //Das letzte gesendete Bit wird auf 0 gesetzt
23
  mov  a, _ui16_msg_sendBuff+1
24
  mov  p, a
25
  mov  a, _ui16_msg_sendBuff+0
26
  mov  _send_msg_sloc1_1_0+0, a
27
  mov  a, p
28
  and  a, #0xfe
29
  mov  _send_msg_sloc1_1_0+1, a
30
  mov  a, _send_msg_sloc1_1_0+0
31
  mov  _ui16_msg_sendBuff+0, a
32
  mov  a, _send_msg_sloc1_1_0+1
33
  mov  _ui16_msg_sendBuff+1, a
34
;  CANish_controller.c: 128: SEND_DATA_DOMINANT;
35
  mov  a, #0xd1
36
  mov  __pac, a
37
;  CANish_controller.c: 130: break;
38
  goto  00108$
39
;  CANish_controller.c: 132: case 0x0000:  //Die letzten 5 Bits waren eine 0, also 1 senden
40
00103$:
41
;  CANish_controller.c: 133: ui16_msg_sendBuff = ui16_msg_sendBuff | 0x0100;    //Das letzte gesendete Bit wird auf 1 gesetzt                  
42
  mov  a, _ui16_msg_sendBuff+1
43
  mov  p, a
44
  mov  a, _ui16_msg_sendBuff+0
45
  mov  _send_msg_sloc2_1_0+0, a
46
  mov  a, p
47
  or  a, #0x01
48
  mov  _send_msg_sloc2_1_0+1, a
49
  mov  a, _send_msg_sloc2_1_0+0
50
  mov  _ui16_msg_sendBuff+0, a
51
  mov  a, _send_msg_sloc2_1_0+1
52
  mov  _ui16_msg_sendBuff+1, a
53
;  CANish_controller.c: 134: SEND_DATA_RECESSIVE;
54
  mov  a, #0x11
55
  mov  __pac, a
56
;  CANish_controller.c: 136: break;
57
  goto  00108$
58
;  CANish_controller.c: 138: default:
59
00104$:
60
;  CANish_controller.c: 139: switch (0x0080 & ui16_msg_sendBuff) {
61
  mov  a, _ui16_msg_sendBuff+1
62
  mov  p, a
63
  mov  a, _ui16_msg_sendBuff+0
64
  and  a, #0x80
65
  mov  _send_msg_sloc3_1_0+0, a
66
  clear  _send_msg_sloc3_1_0+1
67
  mov  a, _send_msg_sloc3_1_0+0
68
  ceqsn  a, #0x00
69
  goto  00106$
70
  mov  a, _send_msg_sloc3_1_0+1
71
  ceqsn  a, #0x00
72
  goto  00106$
73
;  CANish_controller.c: 141: SEND_DATA_DOMINANT;
74
  mov  a, #0xd1
75
  mov  __pac, a
76
;  CANish_controller.c: 142: break;
77
  goto  00107$
78
;  CANish_controller.c: 144: default:
79
00106$:
80
;  CANish_controller.c: 145: SEND_DATA_RECESSIVE;
81
  mov  a, #0x11
82
  mov  __pac, a
83
;  CANish_controller.c: 147: }
84
00107$:
85
;  CANish_controller.c: 149: ui16_msg_sendBuff = ui16_msg_sendBuff << 1;
86
  sl  _ui16_msg_sendBuff+0
87
  slc  _ui16_msg_sendBuff+1
88
;  CANish_controller.c: 150: ui8_sendBits++;
89
  mov  a, _ui8_sendBits+0
90
  add  a, #0x01
91
  mov  _ui8_sendBits+0, a
92
;  CANish_controller.c: 154: }    
93
00108$:
94
;  CANish_controller.c: 157: switch (ui8_sendBits & 0x07) {
95
  clear  p
96
  mov  a, _ui8_sendBits+0
97
  and  a, #0x07
98
  mov  _send_msg_sloc4_1_0+0, a
99
  clear  _send_msg_sloc4_1_0+1
100
  mov  a, _send_msg_sloc4_1_0+0
101
  ceqsn  a, #0x00
102
  goto  00120$
103
  mov  a, _send_msg_sloc4_1_0+1
104
  ceqsn  a, #0x00
105
  goto  00120$
106
;  CANish_controller.c: 159: ui16_msg_sendBuff = (ui16_msg_sendBuff & 0xFF00) | ui8Arr_msg[ui8_sendBits >> 3];
107
  mov  a, _ui16_msg_sendBuff+1
108
  mov  p, a
109
  mov  a, _ui16_msg_sendBuff+0
110
  clear  _send_msg_sloc5_1_0+0
111
  mov  a, p
112
  mov  _send_msg_sloc5_1_0+1, a
113
  mov  a, _ui8_sendBits+0
114
  sr  a
115
  sr  a
116
  sr  a
117
  add  a, #(_ui8Arr_msg + 0)
118
  mov  p, a
119
  idxm  a, p
120
  mov  p, a
121
  mov  a, _send_msg_sloc5_1_0+0
122
  or  p, a
123
  mov  a, _send_msg_sloc5_1_0+1
124
  mov  _ui16_msg_sendBuff+1, a
125
  mov  a, p
126
  mov  _ui16_msg_sendBuff+0, a

von Falk B. (falk)


Lesenswert?

Tobias K. schrieb:
> ich arbeite gerade an einem kleinem Projekt für eine Bus-Schnittstelle.
> Dabei will ich, um die Code Laufzeit zu erhöhen Inline Assembly
> verwenden.

Wirklich? Es soll langsamer laufen? Das geht auch einfach in C ;-)

von PittyJ (Gast)


Lesenswert?

Statt der 'switch'es hätte ich normale 'if's genommen. Damit arbeiten 
die Compiler meist besser, wenn es nur 2 oder 3 Fälle gibt.

Vielleicht kann man bei deinem Compiler auch eine Optimierung 
einschalten?? Selbst mein gcc liefert meist besseren Code.

von Tobias K. (tobias-k)


Lesenswert?

Falk B. schrieb:
> Tobias K. schrieb:
>> ich arbeite gerade an einem kleinem Projekt für eine Bus-Schnittstelle.
>> Dabei will ich, um die Code Laufzeit zu erhöhen Inline Assembly
>> verwenden.
>
> Wirklich? Es soll langsamer laufen? Das geht auch einfach in C ;-)

Oh, natürlich meine ich schneller laufen.



Meiner Erfahrung nach ist ein switch für gewöhnlich schneller als eine 
if Bedingung

von Falk B. (falk)


Lesenswert?

Tobias K. schrieb:
> Oh, natürlich meine ich schneller laufen.

Dann pack die gesamte Funktion in eine separate ASM-Datei. Das ist 
deutlich einfacher und übersichtlicher als mit Inline-ASM.

> Meiner Erfahrung nach ist ein switch für gewöhnlich schneller als eine
> if Bedingung

Ist auch so, so doof sind die Compiler schon lange nicht mehr, als daß 
sie das nicht flott umsetzen können.

von Tobias K. (tobias-k)


Lesenswert?

Falk B. schrieb:
> Dann pack die gesamte Funktion in eine separate ASM-Datei. Das ist
> deutlich einfacher und übersichtlicher als mit Inline-ASM.

Das Problem dabei ist, dass ich die restlichen Abschnitte in normalem C 
verfassen möchte, also C Abschnitte die nur aufgerufen werden, wenn die 
ASM Abschnitte ein gewisses Ergebnis liefern. Das Programm ist nämlich 
noch lange nicht fertig und Anpassungen in C sind für mich sehr viel 
leichter als welche in Assebler.

von Nop (Gast)


Lesenswert?

Tobias K. schrieb:
> Das Programm ist nämlich
> noch lange nicht fertig und Anpassungen in C sind für mich sehr viel
> leichter als welche in Assebler.

Das ist der im allgemeinen verkehrte Ansatz. Das macht man in dieser 
Reihenfolge:

1) Richtiges Design. Hier gehören u.a. sinnvolle Wahl von Algorithmen 
und Datenstrukturen rein.
2) Bring es zum Laufen und halte es dabei vor allem übersichtlich.
3) Code profiling. Finde die Flaschenhälse - und zwar die wirklichen und 
nicht die, die Du Dir vorstellst.
4) Optimiere die Flaschenhälse gezielt.

Du bist irgendwo zwischen 1) und 2), und da ist Assembler jedenfalls für 
Optimierungszwecke noch gar nicht angebracht.

von Falk B. (falk)


Lesenswert?

Tobias K. schrieb:
> Das Problem dabei ist, dass ich die restlichen Abschnitte in normalem C
> verfassen möchte, also C Abschnitte die nur aufgerufen werden, wenn die
> ASM Abschnitte ein gewisses Ergebnis liefern. Das Programm ist nämlich
> noch lange nicht fertig und Anpassungen in C sind für mich sehr viel
> leichter als welche in Assebler.

Sicher, aber das löst das Problem nicht. So wie ich es sehe, willst du, 
warum auch immer, einen CAN-Controller in Software nachbilden. Dafür 
braucht man ziemlich genaues, hier wohl taktgenaues Timing. Das macht 
man sinnvollerweise in ASM. Als bau dir eine Funktion in ASM, welche das 
erledigt. Die zeitunkritischen Sachen macht man dann in C.

Hier mal als Beispiel für die WS2812. Die Datenausgabe erfolgt in ASM, 
der Aufruf und die Datenvorbereitung in C. So ähnlich kannst bzw. 
solltest du das auch angehen.

Beitrag "Re: Frage zu IR-Remote+LED-Strips an AVR"

von Tobias K. (tobias-k)


Lesenswert?

Ja, genau, es soll eine Art Can Controller auf basus eines Padauk uC 
werden.
Gut, dann versuche ich es am besten so mit einer externen asm Funktion.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.