Hi
ich hab schon im Forum gesucht, aber nicht das richtig gefunden.
Ich hab in der main() eine Schleife in der eine Switch-Anweisung steht.
Der avr-gcc (GCC) 4.1.3 20070724 generiert daraus 2 Jumptables.
Das ganze wird für nen Atmega8 kompiliert
Hier 3 Ausschnitte
1
uint16_tt=...;
2
switch(t){
3
case0x01:set_act_date();
4
break;
5
case0x02:get_act_date();
6
break;
7
case0x03:get_alarm_info();
8
break;
9
case0x04:set_alarm_info();
10
break;
11
case0x05:write_alarm_with_index();
12
break;
13
case0x06:get_alarm_with_index();
14
break;
15
case0x07:add_alarm();
16
break;
17
case0x08:delete_alarm_with_index();
18
break;
19
case0x09:get_clock_config();
20
break;
21
case...
22
23
}
in r31:r30 ist t abgelegt
mit dem ijmp springt er in den zweiten ASM-Ausschnitt zu Zeile 26+Index
und von da aus dann wieder zurück zur Zeile 65c
1
64e: 31 97 sbiw r30, 0x01 ; 1
2
650: e9 30 cpi r30, 0x09 ; 9
3
652: f1 05 cpc r31, r1
4
654: 88 f7 brcc .-30 ; 0x638 <main+0x8>
5
656: ed 5e subi r30, 0xED ; 237
6
658: ff 4f sbci r31, 0xFF ; 255
7
65a: 09 94 ijmp
8
65c: 5b df rcall .-330 ; 0x514 <set_act_date>
9
65e: ec cf rjmp .-40 ; 0x638 <main+0x8>
10
660: ad df rcall .-166 ; 0x5bc <get_act_date>
11
662: ea cf rjmp .-44 ; 0x638 <main+0x8>
12
664: 7b df rcall .-266 ; 0x55c <get_alarm_info>
13
666: e8 cf rjmp .-48 ; 0x638 <main+0x8>
14
668: 20 de rcall .-960 ; 0x2aa <set_alarm_info>
15
66a: e6 cf rjmp .-52 ; 0x638 <main+0x8>
16
66c: 79 de rcall .-782 ; 0x360 <write_alarm_with_index>
17
66e: e4 cf rjmp .-56 ; 0x638 <main+0x8>
18
670: 16 de rcall .-980 ; 0x29e <get_alarm_with_index>
19
672: e2 cf rjmp .-60 ; 0x638 <main+0x8>
20
674: 33 de rcall .-922 ; 0x2dc <add_alarm>
21
676: e0 cf rjmp .-64 ; 0x638 <main+0x8>
22
678: 2b df rcall .-426 ; 0x4d0 <get_clock_config>
23
67a: de cf rjmp .-68 ; 0x638 <main+0x8>
die rjmp zu main+0x8 gehen zur Anfang der Hauptschleife
1
0: 1c c0 rjmp .+56 ; 0x3a <__ctors_end>
2
2: 2b c1 rjmp .+598 ; 0x25a <__vector_1>
3
4: 34 c0 rjmp .+104 ; 0x6e <__bad_interrupt>
4
6: 33 c0 rjmp .+102 ; 0x6e <__bad_interrupt>
5
8: 32 c0 rjmp .+100 ; 0x6e <__bad_interrupt>
6
a: 31 c0 rjmp .+98 ; 0x6e <__bad_interrupt>
7
c: 30 c0 rjmp .+96 ; 0x6e <__bad_interrupt>
8
e: 2f c0 rjmp .+94 ; 0x6e <__bad_interrupt>
9
10: 2e c0 rjmp .+92 ; 0x6e <__bad_interrupt>
10
12: 2d c0 rjmp .+90 ; 0x6e <__bad_interrupt>
11
14: 2c c0 rjmp .+88 ; 0x6e <__bad_interrupt>
12
16: 32 c3 rjmp .+1636 ; 0x67c <__vector_11>
13
18: 2a c0 rjmp .+84 ; 0x6e <__bad_interrupt>
14
1a: 29 c0 rjmp .+82 ; 0x6e <__bad_interrupt>
15
1c: 28 c0 rjmp .+80 ; 0x6e <__bad_interrupt>
16
1e: 27 c0 rjmp .+78 ; 0x6e <__bad_interrupt>
17
20: 26 c0 rjmp .+76 ; 0x6e <__bad_interrupt>
18
22: 25 c0 rjmp .+74 ; 0x6e <__bad_interrupt>
19
24: 24 c0 rjmp .+72 ; 0x6e <__bad_interrupt>
20
26: 1a c3 rjmp .+1588 ; 0x65c <main+0x2c>
21
28: 1b c3 rjmp .+1590 ; 0x660 <main+0x30>
22
2a: 1c c3 rjmp .+1592 ; 0x664 <main+0x34>
23
2c: 1d c3 rjmp .+1594 ; 0x668 <main+0x38>
24
2e: 1e c3 rjmp .+1596 ; 0x66c <main+0x3c>
25
30: 1f c3 rjmp .+1598 ; 0x670 <main+0x40>
26
32: 20 c3 rjmp .+1600 ; 0x674 <main+0x44>
27
34: 01 c3 rjmp .+1538 ; 0x638 <main+0x8>
28
36: 20 c3 rjmp .+1600 ; 0x678 <main+0x48>
Wie kann ich den GCC dazu bringen, dass er direkt zur Zeile 65c springt
und nicht erst den Umweg über den erweiterten Interrupt Vektor
lg
Benimmt er sich falsch oder vermutest du nur anhand des etwas
irreführenden Listings dass er es täte?
Denn bei
676: e0 cf rjmp .-64 ; 0x638 <main+0x8>
springt er natürlich nicht nach main+0x08, sondern nach 0x638
(0x676+2-64).
Warum im Kommentar main+0x08 drinsteht weiss ich nicht. Aber nicht der
Kommentar wird ausgeführt, sondern der Code.
ich weiß, aber 676+2-64 ist main+0x8 :)
daher der kommentar
main fängt bei 630 an
das ergebnis ist so wie gewollt, aber ich möchte einfach nur das, der µC
nicht erst 2x springen muss bevor er dann die richtige funktion aufruft
Dennis B. wrote:
> ich weiß, aber 676+2-64 ist main+0x8 :)
Mag sein. Aber drunter schreibst du was von der Interrupt-Tabelle. Und
die hat ja nun rein garnichts mit der Sache zu tun. Denn wie du selber
schreibst, geht der Sprung nach main+0x8=0x638 und nicht zur
Interrupt-Tabelle.
Und da der wichtigste Teil des Codes fehlt, sowohl in Quelle wie im
Listing, kann man auf die Frage schlecht eine Antwort gegen.
hmm dachte das ist verständlich
weil mehr Quellcode posten bringt nix, weil der unwichtig ist.
Denn im ersten ASM Ausschnitt steht ein IJMP, und im Z Register steht
26 + (t-1) (aus der switch anweisung)
und zeile 26 steht im 2 ASM Code.
PS: aber wenn du möchtest, hänge ich gerne ca 1400 Zeilen Code an (400
in C und 1000 in ASM)
Ok, sorry, ich hatte das verkehrt gelesen.
Der Code hat nur eine einzige Sprungtabelle, nämlich die an 0x26. Das
Zeug ab 0x65C ist schlicht der Code der einzelnen Komponenten vom
Switch-Statement. Dass die alle ähnlich aussehen liegt an deinem ebenso
ähnlichen Quellcode, nicht am Compiler.
Wenn du erreichen willst, dass in der Tabelle die Funktion direkt
aufgerufen werden, dann solltest du hier kein switch() verwenden,
sondern eine Funktionstabelle:
>Wie kann ich den GCC dazu bringen, dass er direkt zur Zeile 65c springt>und nicht erst den Umweg über den erweiterten Interrupt Vektor
Aus akademischem Interesse ja ganz interessant, aber gibt es bei deiner
Anwendung auch einen praktischen Grund?
Oliver
Der GCC hat für berechnete Switch-Anweisungen ein festes Code-Muster,
das einen IJMP in eine Serie von RJMPs vorsieht. Das ist für den Fall,
das in den einzelnen Cases unterschiedlich lange Anweisungen stehen,
auch optimal. In deinem Fall steht aber in jedem Case nur ein
einzelner RCALL, der natürlich mit dem RJMP aus der Tabelle zu einem
einzelnen Befehl vereint werden könnte.
Das wäre eine zusätzliche Optimierungregel, die aber offensichtlich
nicht implementiert ist. Vielleicht haben die Entwickler auch deswegen
darauf verzichtet, weil solche Konstrukte sowieso meist mit einem
Array aus Funktionspointern realisiert werden, wie du es jetzt ja
schließlich ebenfalls getan hast.
Die Funktionspointerlösung hat den den Vorteil, dass der Sourcecode
kürzer wird, und die Ausführungszeit ist auch dann unabhängig von der
Anzahl der unterschiedlichen Werte von t, wenn der Compiler bei
Switches keine Optimierung durch berechnete Sprünge kann.