PIC16 Anweisungen wegoptimiert

OP #2908807
Lesenswert?

Hallo

ich lese hier schon seit längerem mit und habe auch schon so manches 
Problem lösen können durch die Beiträge anderer User. Heute hab ich auch 
mal ein Problem was ich noch nicht lösen konnte.

Ich nutze folgende Funktion um die Parität eines Zeichens zu berechnen 
und übergebe dann die 9 Bit an die Hardware-UART. Bei der Compoilierung 
werden die beiden Zeilen, die um 1 bzw. 2 Bit shiften einfach 
wegoptimiert, alle anderen bleiben bestehen.

Wie kann das sein? Wie kann ich das verhindern?

Silvio
1
//
2
/*  Zeichen per UART senden*/
3
void zeichen_senden(unsigned char zeichen)
4
{
5
  bit9 = (bit9 ^ (zeichen & 0b00000001));                    //  \
6
  bit9 = (bit9 ^ ((zeichen >> 1) & 0b00000001));                //   \
7
  bit9 = (bit9 ^ ((zeichen >> 2) & 0b00000001));                //    \Paritätsberechnung
8
  bit9 = (bit9 ^ ((zeichen >> 3) & 0b00000001));                //    /
9
  bit9 = (bit9 ^ ((zeichen >> 4) & 0b00000001));                //   /
10
  bit9 = (bit9 ^ ((zeichen >> 5) & 0b00000001));                //  /
11
  bit9 = (bit9 ^ ((zeichen >> 6) & 0b00000001));                // /
12
  bit9 = (bit9 ^ ((zeichen >> 7) & 0b00000001));
13
  TX2STAbits.TX9D = bit9;                            //9. Bit zuweisen
14
  TX2REG = zeichen;                              //Daten ins Ausgaberegister schieben, Übertragung beginnt
15
}
#2908846
Lesenswert?

Kein Name schrieb:
> Der Backslash maskiert das Newline?


Oh, ja. Der Programmier-Fehler ist wirklich fies.

INteressant ist, dass auch die Forensoftware das hinkriegt, dass die 
beiden Zeilen auskommentiert sind, weil sie mit dem \ alle zu einer 
Zeile zusammengezogen wurden und daher alles nach dem \\ in der ersten 
Zeile als Kommentar gewertet wird. Hätte ich jetzt nicht gedacht, dass 
die das schafft.
#2908850
Lesenswert?

abgesehen davon
1
void zeichen_senden(unsigned char zeichen)
2
{
3
  bit9 = (bit9 ^ (zeichen & 0b00000001));                    //  \

bist du dir sicher, dass die Paritätsberechnung mit einem nicht näher 
bekannten Wert von bit9 beginnen soll?

Alles in allem ist deine Paritätsberechnung mit den vielen 
Schiebeoperationen alles andere als µC-schonend implementiert. Hoffen 
wir mal, dass der Optimizer des Compilers erkennt, dass er das jeweilige 
Ergebnis der Stufe davor weiterverwenden kann.
OP #2908894
Lesenswert?

Hallo

auf diese Idee mit dem fortsetzen der Zeile bin ich noch gar nicht 
gekommen. Ich dachte imme nach // ist alles Kommentar bis zum Zeilenende 
also auch ein \. Habe aber jetzt im Disassambly Listing gesehen daß auch 
an anderen Stellen was als Kommentar angesehen wurde was eigentlich Code 
sein sollte. Hat aber bisher keine Auswirkungen gehabt weil in der 
Initialisierung und nur bei Werten die ich auch so setze wie sie nach 
einem Reset automatisch sind.

Mit dem Startwert für bit9 ist geändert. Die Berechnung in Assambler 
erfolgt folgendermaßen:

bit9 testen
Ergebnis in temporäre Speicherstelle
Zeichen laden
Zeichen shiften
Zeichen Bit 0 testen
Ergebnis in Arbeitsregister
XOR von Arbeitsregister und temporärer Speicherstelle
Ergebnis in Arbeitsregister
Arbeitsregister Bit 0 testen
Ergebnis in Bit9 speichern

Ist für alle 8 Bit gleich bis auf die Anzahl der Stellen beim Shift. 
Sollte also passen. Für die Berechnung werden etwa 200 Assambler-Befehle 
gebraucht.

Vielen dank für die Hilfe, ohne euch hätte ich den Fehler garantiert 
nicht gefunden.

Silvio
Gast #2908907
Lesenswert?

Es gibt auch einen Denkfehler.
{
  bit9 = (bit9 ^ (zeichen & 0b00000001));

sollte eigentlich sein:
{
  bit9 = (zeichen & 0b00000001);


Wechsle das aus und poste auch den ASM Code, welcher der Compiler 
generiert.

Ansonten, eventuell eine ASM Funktion:

 swapf zeichen,W
 xorwf zeichen,W
 andlw 0xf0
 movwf tmp

 rlf   tmp,w
 rlf   tmp
 btfsc tmp,7
 incf  tmp
 btfsc tmp,6
 incf  tmp
 btfsc tmp,
 incf  tmp

 bcf   TX2STAbits,TX9D
 btfsc tmp,0
 bsf   TX2STAbits,TX9D
OP #2908931
Lesenswert?

Hallo

ich habe jetzt vor der Berechnung bit9 auf 0 gesetzt. Damit kann der 
Code so bleiben.

Die ASM-Variante ist zwar schön kurz und auch schnell, aber da ich weder 
mit dem Platz (8k Befehle, 4k genutzt) noch der Ausführungszeit (ca. 
40µs) Probleme habe werde ich das erstmal so lassen.

Der ASM-Code der erzeugt wird ist im Anhang.

Silvio
Angehängte Dateien:
Gast #2908937
Lesenswert?

sa geht doch wohl auch mit C schneller
1
uint8_t bit9 = 0;
2
uint8_t tmp = zeichen;
3
for( uint8_t bit = 0; bit < 7; ++bit ) {
4
   bit9 = bit9 ^ (zeichen & 1);
5
   zeichen = zeichen >> 1;
6
}
7
TX2STAbits.TX9D = bit9;   
8
TX2REG = zeichen;
#2908941
Lesenswert?

Silvio G. schrieb:

> Die ASM-Variante ist zwar schön kurz und auch schnell

Sorry. Das würde ich weder kurz noch schnell nennen.

Probier mal diese Variante, ob die schneller geht bzw. weniger Code 
produziert
1
unsigned char Parity( unsigned char i )
2
{
3
  static const unsigned char nibbleParity[] =    // die Parität für jeweils 4 Bit
4
  {
5
    0, 1, 1, 0,     // 0000, 0001, 0010, 0011
6
    1, 0, 0, 1,     // 0100, 0101, 0110, 0111
7
    1, 0, 0, 1,     // 1000, 1001, 1010, 1011
8
    0, 1, 1, 0      // 1100, 1101, 1110, 1111
9
  };
10

11
  return nibbleParity[i&0x0F] ^ nibbleParity[i>>4];
12
}
#2908992
Lesenswert?

Karl Heinz Buchegger schrieb:
> Silvio G. schrieb:
>
>
>> Die Funtion Parity ergibt 74 Befehle mit ca. 130 Befehlszyklen (ASM im
>> Anhang).
>
>
> Autsch.
> Wenn der Compiler ein static Array so einbaut, dass er es jedesmal beim
> Betreten der Funktion wieder neu erzeugt, würde ich ganz schnell den
> Compiler wechseln.

Edit:
Was treibt der Compiler da? Da ist noch mehr in der Funktion als nur die 
Tabelle.

Hast du den Optimizer eingeschaltet?
Oder die Generierung von Debug-Information aktiviert?
#2908996
Lesenswert?

A. K. schrieb:
> Karl Heinz Buchegger schrieb:
>> Wenn der Compiler ein static Array so einbaut, dass er es jedesmal beim
>> Betreten der Funktion wieder neu erzeugt, würde ich ganz schnell den
>> Compiler wechseln.
>
> Wie kommst du darauf?

OK. Ich bin nicht 100% sicher. Aber das hier
1
653:               unsigned char Parity( unsigned char i )
2
654:               {
3
655:                 static const unsigned char nibbleParity[] =    // die Parität für jeweils 4 Bit
4
  0263    3400     RETLW 0
5
  0264    3401     RETLW 0x1
6
  0265    3401     RETLW 0x1
7
  0266    3400     RETLW 0
8
  0267    3401     RETLW 0x1
9
  0268    3400     RETLW 0
10
  0269    3400     RETLW 0
11
  026A    3401     RETLW 0x1
12
  026B    3401     RETLW 0x1
13
  026C    3400     RETLW 0
14
  026D    3400     RETLW 0
15
  026E    3401     RETLW 0x1
16
  026F    3400     RETLW 0
17
  0270    3401     RETLW 0x1
18
  0271    3401     RETLW 0x1
19
  0272    3400     RETLW 0
20
  0273    3420     RETLW 0x20
21
  0274    3450     RETLW 0x50
22
  0275    3461     RETLW 0x61
23
  0276    3472     RETLW 0x72
24
  0277    3469     RETLW 0x69
25
  0278    3474     RETLW 0x74
26
  0279    3461     RETLW 0x61
27
  027A    3465     RETLW 0x65
28
  027B    3474     RETLW 0x74
29
  027C    3420     RETLW 0x20
30
  027D    3400     RETLW 0
31
  027E    3430     RETLW 0x30
32
  027F    3431     RETLW 0x31
33
  0280    3432     RETLW 0x32
34
  0281    3433     RETLW 0x33
35
  0282    3434     RETLW 0x34
36
  0283    3435     RETLW 0x35
37
  0284    3436     RETLW 0x36
38
  0285    3437     RETLW 0x37
39
  0286    3438     RETLW 0x38
40
  0287    3439     RETLW 0x39
41
  0288    3400     RETLW 0
42
  0289    3420     RETLW 0x20
43
  028A    3457     RETLW 0x57
44
  028B    3465     RETLW 0x65
45
  028C    3472     RETLW 0x72
46
  028D    3474     RETLW 0x74
47
  028E    3420     RETLW 0x20
48
  028F    3400     RETLW 0
49
  0290    344E     RETLW 0x4e
50
  0291    3472     RETLW 0x72
51
  0292    342E     RETLW 0x2e
52
  0293    3420     RETLW 0x20
53
  0294    3400     RETLW 0
54
  0295    3430     RETLW 0x30
55
  0296    3431     RETLW 0x31
56
  0297    3400     RETLW 0
57
656:                 {
58
657:                   0, 1, 1, 0,     // 0000, 0001, 0010, 0011
59
658:                   1, 0, 0, 1,     // 0100, 0101, 0110, 0111
60
659:                   1, 0, 0, 1,     // 1000, 1001, 1010, 1011
61
660:                   0, 1, 1, 0      // 1100, 1101, 1110, 1111
62
661:                 };
63
662:               
64
663:                 return nibbleParity[i&0x0F] ^ nibbleParity[i>>4];
65
  02C8    00F3     MOVWF 0x73

sieht für mich danach aus. Die RETLW rese.....


Vergiss es. Da hab ich mich vertan.
Das hat er schon gut gemacht.
#2909013
Lesenswert?

A. K. schrieb:
> Karl Heinz Buchegger schrieb:
>> Oder die Generierung von Debug-Information aktiviert?
>
> Da sind beim Disassembleren irgendwelche Strings mit zugerordnet worden,
> die nicht zu diesem Teil des Codes zählen aber keine Symbole haben.

Sieht wohl so aus. Mal rückübersetzen
1
  0273    3420     RETLW 0x20    ' '
2
  0274    3450     RETLW 0x50    'P'
3
  0275    3461     RETLW 0x61    'a'
4
  0276    3472     RETLW 0x72    'r'
5
  0277    3469     RETLW 0x69    'i'
6
  0278    3474     RETLW 0x74    't'
7
  0279    3461     RETLW 0x61    'a'
8
  027A    3465     RETLW 0x65    'e'
9
  027B    3474     RETLW 0x74    't'
10
  027C    3420     RETLW 0x20    ' '
11
  027D    3400     RETLW 0
12
  027E    3430     RETLW 0x30    '0'
13
  027F    3431     RETLW 0x31    '1'
14
  0280    3432     RETLW 0x32    '2'
15
  0281    3433     RETLW 0x33    '3'
16
  0282    3434     RETLW 0x34    '4'
17
  0283    3435     RETLW 0x35    '5'
18
  0284    3436     RETLW 0x36    '6'
19
  0285    3437     RETLW 0x37    '7'
20
  0286    3438     RETLW 0x38    '8'
21
  0287    3439     RETLW 0x39    '9'
22
  0288    3400     RETLW 0
23
  0289    3420     RETLW 0x20    ' '
24
  028A    3457     RETLW 0x57    'W'
25
  028B    3465     RETLW 0x65    'e'
26
  028C    3472     RETLW 0x72    'r'
27
  028D    3474     RETLW 0x74    't'
28
  028E    3420     RETLW 0x20    ' '
29
  028F    3400     RETLW 0
30
  0290    344E     RETLW 0x4e    'N'
31
  0291    3472     RETLW 0x72    'r'
32
  0292    342E     RETLW 0x2e    '.'
33
  0293    3420     RETLW 0x20    ' '
34
  0294    3400     RETLW 0
35
  0295    3430     RETLW 0x30    '0'
36
  0296    3431     RETLW 0x31    '1'
37
  0297    3400     RETLW 0


Jep. Das sind wohl Strings von woanders aus dem Programm, die nur 
zufällig hier beim Disassemblieren mitgekommen sind. Die eigentliche 
Funktion ist das hier
1
 02C8    00F3     MOVWF 0x73
2
  02C9    0873     MOVF 0x73, W
3
  02CA    00F1     MOVWF 0x71
4
  02CB    3004     MOVLW 0x4
5
  02CC    36F1     LSRF 0x71, F
6
  02CD    0B89     DECFSZ 0x9, F
7
  02CE    2ACC     GOTO 0x2cc
8
  02CF    0871     MOVF 0x71, W
9
  02D0    3E63     ADDLW 0x63
10
  02D1    3182     MOVLP 0x2
11
  02D2    000A     CALLW
12
  02D3    3182     MOVLP 0x2
13
  02D4    00F2     MOVWF 0x72
14
  02D5    0873     MOVF 0x73, W
15
  02D6    390F     ANDLW 0xf
16
  02D7    3E63     ADDLW 0x63
17
  02D8    3182     MOVLP 0x2
18
  02D9    000A     CALLW
19
  02DA    3182     MOVLP 0x2
20
  02DB    0672     XORWF 0x72, W
21
  02DC    2ADD     GOTO 0x2dd
22
664:               }
23
  02DD    0008     RETURN

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren