Step 7 Was erzeugt diesen AWL Code ?

Draco Malfoy

Level-1
Beiträge
1.168
Reaktionspunkte
82
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi

Welcher Quellcode erzeugt folgende Sequenz ?

Code:
      L     LB    49; 
      UD    DW#16#FF; 
      L     LB    48; 
      UD    DW#16#FF; 
      TAK   ; 
      T     LW    72; 
      TAK   ; 
      L     8; 
      TAK   ; 
      LAR1  ; 
      TAK   ; 
      L     DW#16#10; 
      >=I   ; 
      SPB   I007; 
      TAK   ; 
      TAR1  ; 
      SLW   ; 
      SPA   I008; 
I007: L     DW#16#0; 
I008: UD    DW#16#FFFF; 
      L     LW    72; 
      OW    ;

LB 48 und LB 49 sind Sichten auf lokale Variable (ANY-Pointer) und an der LW72 liegt nichts, diese Addresse wird nur vom Compiler temporär belegt. Es ist mir schon klar, daß hier am Ende so etwas wie:

Code:
tmp_offset  :=  SHL ( IN := p_ext_any.BZ[1], N := 8 );

stehen wird, aber ich raffe nicht, wie man den Compiler dazu bringt diesen Byte-Swap ohne zwischenvariablen zu machen. Thx
 
Meinst Du die "TAK"? Das sind "Tausche AKKU1 mit AKKU2"-Anweisungen.
Das ist eine "Macke" des SCL-Compilers, der ziemlich ungeplant (ohne Optimierung) vorgeht beim Halten von Werten in "Prozessor-Registern" und temporären Speichern von Zwischenergebnissen. Der Compiler versucht so lange wie möglich Werte in AKKU1 und AKKU2 zu halten, und wenn das nicht geht, dann will er dann doch im letzten Moment den Inhalt von AKKU2 sichern (dafür werden die TAK benötigt), bevor die nächste Operation den Inhalt aus AKKU2 wegschiebt (z.B. vor dem "L 8"). Manchmal benutzt der Compiler auch kurzerhand das AR1 als allgemeines Register zum temporären Sichern eines AKKU-Inhaltes.

Auch die "UD DW#16#FF;" nach Laden von Bytes sind so eine überflüssige Macke, die man dem Compiler ganz schlecht abgewöhnen kann.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi Harald.

Also - nein, ich meine nicht TAK und ich meine nicht die Maske. Ich habe schon Paar km Code aus verschiedenen Bausteinen revers compiliert, und sehe diesen Krempel zum ersten Mal. Oder stehe gerade auf dem Schlauch.

Wie bringe ich den Compiler dazu, ein Wort in die Addresse LW72 zu laden, mit vertauschter Byte-Reihenfolge, ohne daß LW72 deklariert ist ?

Es ist ja so:

tmp_offset := SHL ( IN := p_ext_any.BZ[1], N := 8 );

Das ist jetzt einfach ohne Byte-Swap. Also müsste der Ursprünglicher Code etwa so ausgesehen haben:

tmp_offset := SHL ( IN := BYTESWAP (p_ext_any.BZ[1]), N := 8 );

Ich komme nur nicht drauf, was das sein könnte.
 
Wie bringe ich den Compiler dazu, ein Wort in die Addresse LW72 zu laden, mit vertauschter Byte-Reihenfolge, ohne daß LW72 deklariert ist ?
Gar nicht, das Schreiben in nicht deklarierten TEMP-Speicher unterhalb des letzten deklarierten bzw. vom Quelltext benutzten TEMP-Speicher macht der Compiler selber, wenn er temporär Zwischenergebnis-Speicher braucht.

Dein AWL-Code bastelt aus zwei Bytes ein Word zusammen und der ursprüngliche SCL-Code könnte so ausgesehen haben:
Code:
  tmp_Word : WORD;
  tmp_W AT tmp_Word : STRUCT
    H : BYTE;
    L : BYTE;
  END_STRUCT;
  tmp_offset : WORD;
END_VAR

tmp_offset := BYTE_TO_WORD(tmp_W.L) OR SHL(IN := BYTE_TO_WORD(tmp_W.H), N := 8);

//könnte man auch einfach so schreiben:  tmp_offset := tmp_Word;
allerdings scheint mir das irgendwie sinnfrei, weil da die Bytes gar nicht getauscht werden, falls sie bereits aus einem Word stammen. Ein "tmp_offset := tmp_Word;" hätte das selbe bewirkt.
Oder die beiden Bytes stammen gar nicht von einer AT-Überlagerung eines Word sondern sind zwei unabhängige nacheinander deklarierte Byte-Variablen?
Oder ist ein Fehler in Deinem AWL-Code (LB48 und LB49 vertauscht?) oder stammt der AWL-Code von einer SPS mit Little-Endian (Intel-Format)?

Harald
 
Sinnfrei scheint mir das richtige Wort zu sein, Harald.
Der Code kann doch schlicht durch die Anweisung L LW48 ersetzt werden.

Edit, Umformulierung wegen Haralds Einwand: Der Code macht nichts anderes als die Anweisung L LW48.

Und das unabhängig davon, wer wann LB48 und LB49 mit was auch immer gefüllt hat!
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
LB 48 und LB 49 sind Sichten auf lokale Variable (ANY-Pointer)
Vielleicht zeigst Du uns mal die Deklarationen, dann verstehen wir vielleicht, wie jemand auf so umständlichen Code kommen konnte.
Kann es sein, daß der "Byte-Swap" eine Fehlinterpretation des Codes von Dir ist, daß es überhaupt nicht um Byte-Swap, sondern einfach nur um zusammenbasteln eines Word aus zwei Bytes geht?

@Heinileini
Der Ursprungscode war ein SCL-Quellcode, da kann man nicht einfach "L LW48" schreiben.

Harald
 
PS: der SCL-Compiler übersetzt SHL meistens so uneffizient. Für effizienteren Code macht man das zusammenbasteln von zwei Bytes zu einem Word besser so:
Code:
wResult := INT_TO_WORD(BYTE_TO_INT(Byte_H)*256) OR BYTE_TO_WORD(Byte_L);

//oder über AT-Struct:
tmp_W.H := Byte_H;
tmp_W.L := Byte_L;
wResult := tmp_Word;

Harald
 
OK Danke für die Rückmeldungen,

habe es inzwischen selber rausgefunden (Guter Whisky hilft !). Es war diese sagenhafte Programmierweise, die mich an die Grenzen gebracht hat:

Code:
                tmp_offset  :=  SHR ( IN := BYTE_TO_WORD(p_ext_any.BZ[3]) OR (SHL ( IN := BYTE_TO_WORD(p_ext_any.BZ[2]), N := 8 )), N := 3)
                
                                OR 
                                
                                SHL ( IN := BYTE_TO_WORD(p_ext_any.BZ[1]), N := 13 ) ;

Unübersichtlicher gehts eigentlich nicht mehr. V.A. das Ergebnis der letzten Schiebeoperation ist ja per Definitionem immer Null, wie man im Compilat unschwer erkennen kann.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Unübersichtlicher gehts eigentlich nicht mehr.
Fällt Dir eine bessere/übersichtlichere Formulierung ein? (meinetwegen auch mit Whisky)

das Ergebnis der letzten Schiebeoperation ist ja per Definitionem immer Null, wie man im Compilat unschwer erkennen kann.
Meinst Du diese: "SHL ( IN := BYTE_TO_WORD(p_ext_any.BZ[1]), N := 13 ) ;"? Das Ergebnis ist nicht immer 0, und dieses SHL ist auch nicht in dem von Dir gezeigten Compilat. Das "L DW#16#0;" in dem Compilat hat mit diesem SHL nichts zu tun.

Harald
 
OK ich poste mal den gesamten Abschnitt

Code:
      L     LB    49; 
      UD    DW#16#FF; 
      L     LB    48; 
      UD    DW#16#FF; 
      TAK   ; 
      T     LW    72; 
      TAK   ; 
      L     8; 
      TAK   ; 
      LAR1  ; 
      TAK   ; 
      L     DW#16#10; 
      >=I   ; 
      SPB   I007; 
      TAK   ; 
      TAR1  ; 
      SLW   ; 
      SPA   I008; 
I007: L     DW#16#0; 
I008: UD    DW#16#FFFF; 
      L     LW    72; 
      OW    ; 
      L     3; 
      TAK   ; 
      LAR1  ; 
      TAK   ; 
      L     DW#16#10; 
      >=I   ; 
      SPB   I009; 
      TAK   ; 
      TAR1  ; 
      SRW   ; 
      SPA   I00a; 
I009: L     DW#16#0; 
I00a: L     LB    47; 
      UD    DW#16#FF; 
      TAK   ; 
      T     LW    72; 
      TAK   ; 
      L     13; 
      TAK   ; 
      LAR1  ; 
      TAK   ; 
      L     DW#16#10; 
      >=I   ; 
      SPB   I00b; 
      TAK   ; 
      TAR1  ; 
      SLW   ; 
      SPA   I00c; 
I00b: L     DW#16#0; 
I00c: UD    DW#16#FFFF; 
      L     LW    72; 
      OW    ; 
      UD    DW#16#FFFF; 
      T     #tmp_offset; 
      L     #tmp_offset; 
      L     #cmd_sel_counter; 
      TAK   ; 
      T     LD    72; 
      TAK   ; 
      L     1; 
      -I    ; 
      L     90; 
      *I    ; 
      ITD   ; 
      L     LD    72; 
      +D    ; 
      T     #tmp_offset; 
      L     #tmp_offset; 
      SRD   13; 
      UD    DW#16#FF; 
      T     LB    47; 
      L     #tmp_offset; 
      SRD   5; 
      UD    DW#16#FF; 
      T     LB    48; 
      L     LB    49; 
      L     B#16#7; 
      UW    ; 
      T     LB    49; 
      L     #tmp_offset; 
      SLD   3; 
      UD    DW#16#FF; 
      L     LB    49; 
      OW    ; 
      T     LB    49;

was im Quellcode folgenden Geistesflügen (ich entschuldige mich, sinnvoll programmierten Sequenzen) entspricht:

Code:
                tmp_offset  :=  SHR ( IN := BYTE_TO_WORD(p_ext_any.BZ[3]) OR (SHL ( IN := BYTE_TO_WORD(p_ext_any.BZ[2]), N := 8 )), N := 3)
                
                                OR 
                                
                                SHL ( IN := BYTE_TO_WORD(p_ext_any.BZ[1]), N := 13 ) ; 
                                
                
                tmp_offset  :=  DINT_TO_DWORD(DWORD_TO_DINT(tmp_offset)  +  (cmd_sel_counter - 1) * INT#90);
                
                p_ext_any.BZ[1] := DWORD_TO_BYTE(SHR (IN := tmp_offset, N := 13));
                p_ext_any.BZ[2] := DWORD_TO_BYTE(SHR (IN := tmp_offset, N := 5));
                p_ext_any.BZ[3] := p_ext_any.BZ[3] AND B#16#7;
                p_ext_any.BZ[3] := p_ext_any.BZ[3] OR DWORD_TO_BYTE(SHL (IN := tmp_offset, N := 3));

Es geht hier um die Berechnung von Zeigern. Ja, ich bin der Meinung, das man das durchaus besser fassen kann. Und ja, das Ergebis wird immer Null sein, weil 13 größer als 10 ist und somit die Beschränkung über I00b greift.
 
Und ja, das Ergebis wird immer Null sein, weil 13 größer als 10 ist und somit die Beschränkung über I00b greift.
13 ist aber nicht größer als 16#10

Der SCL-Compiler erzeugt diese hier unnötige Prüfung der Größe der Schiebezahl, auch wenn die Schiebezahl als Zahl/Konstante im Quelltext steht.

Harald
 
Noch ein weiteres Problem:

Original Code:

Code:
      L     #bufoffset; 
      ITD   ; 
      L     L#0; 
      +D    ; 
      L     L#8; 
      *D    ; 
      L     L#336; 
      +D    ; 
      L     DIW [AR2,P#18.0]; 
      T     LW    74; 
      TAK   ; 
      AUF   DB [LW 74]; 
      L     DID [AR2,P#20.0]; 
      TAK   ; 
      T     LD    74; 
      TAK   ; 
      +D    ; 
      LAR1  ; 
      L     B [AR1,P#0.0]; 
      L     DW#16#10020001; 
      T     LD    78; 
      L     DIW [AR2,P#18.0]; 
      T     LW    82; 
      L     DID [AR2,P#20.0]; 
      L     LD    74; 
      +D    ; 
      T     LD    84; 
      L     LD    78; 
      T     LD    30; 
      L     LD    82; 
      T     LD    34; 
      L     LW    86; 
      T     LW    38;

Das, was ich bisher durch try & error zustande gebracht habe:

Code:
      L     #bufoffset; 
      ITD   ; 
      L     L#8; 
      *D    ; 
      L     L#336; 
      +D    ; 
      L     DW#16#10020001; 
      T     LD    74; 
      TAK   ; 
      T     LD    84; 
      TAK   ; 
      L     DIW [AR2,P#18.0]; 
      T     LW    78; 
      L     DID [AR2,P#20.0]; 
      L     LD    84; 
      +D    ; 
      T     LD    80; 
      L     LD    74; 
      T     LD    30; 
      L     LD    78; 
      T     LD    34; 
      L     LW    82; 
      T     LW    38;

Es wird ein Any-Zeiger auf einen Zielblock im INOUT-Bereich geladen, wobei der Zielblock ein Array ist.
Wie kommt diese seltasame Stelle mit L B [AR1,P#0.0] zustande ? Ich konnte es bisher nicht reproduzieren.

Thx
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
[...]
      L     L#336; 
      +D    ; 
[COLOR="#00A000"]      L     DIW [AR2,P#18.0]; 
      T     LW    74; 
      TAK   ; 
      AUF   DB [LW 74]; 
      L     DID [AR2,P#20.0]; 
      TAK   ; [/COLOR]
      T     LD    74; 
[COLOR="#00A000"]      TAK   ; 
      +D    ; 
      LAR1  ; 
      L     B [AR1,P#0.0]; [/COLOR]
      L     DW#16#10020001; 
      T     LD    78; 
[...]
Code:
FUNCTION_BLOCK FBxx
...
VAR_IN_OUT
  IOS : STRUCT   // DIB18 .. 23: POINTER auf Aktualparameter
    res : ARRAY[0..41] OF BYTE ;     //irgendwas 42 Byte lang
    Buffer : ARRAY[0..xx] OF BYTE ;
    ...
  END_STRUCT;
END_VAR
VAR_TEMP
  L0_friss_Byte : ARRAY[0..29] OF BYTE ;   //irgendwas bis LB29
  tmpANY : ANY;
  bufoffset : INT;
  L42_friss_Byte : ARRAY[42..71] OF BYTE ; //irgendwas bis LB71
END_VAR
...
tmpANY := IOS.Buffer[bufoffset];
"L B [AR1,P#0.0]" (und die grünen Anweisungen) ist vom Compiler zusätzlich eingefügter Code, vermutlich ein Test, ob die zur Laufzeit berechnete Adresse IOS.Buffer[bufoffset] existiert (ggf. Zugriffsfehler vor der Stelle wo der ANY erzeugt wird).

PS: Es würde das Helfen/Nachdenken für Dich sehr erleichtern, wenn Du bei Deiner Frage auch die Bausteinschnittstelle hier zeigen würdest.

Harald
 
Hi Harald,

danke Dir. Es war spät am Abend und ich habe wieder nicht dran gedacht. Sehe ich das richtig, daß ich die Compiler-Option "Array-Grenzen prüfen" einschalten muss, damit mir dieser seltsame Krempel zusätzlich generiert wird ?

@ Es wird leider nicht besser von!

Hier die Schnittstelle:

Code:
VAR_IN_OUT 
      HW_CONNECT : "IID_HW_CONNECT";   // channel sync-variable
END_VAR
   VAR_TEMP 
      raised_EXECUTE : BOOL;   // flag for rising edge of execute
      raised_Init : BOOL;   // flag for rising edge of init
      raised_SRESET : BOOL;   // flag for rising edge of sreset
      int_error : BOOL;   // helper: internal error
      adress : DINT;   // helper: i/o address
      b : BYTE;   // helper: error flag in acknowledge
      li : DINT;   // helper: length
      bufoffset : INT;   // helper: buffer offset
      tmp_w : WORD;   // helper: interpret single bytes of telegram
      i : INT;   // helper: offset
      finished : BOOL;   // helper: command is finished
      tmp : INT;   // helper: loop variable
      tmp_max : INT;   // helper: pdu size
      tmp_status : WORD;   // helper: mask status
      return_val : INT;   // return value of timestamp
      j : INT;   // helper: loop
      
        local_any : ANY ;    //helper: local any-pointer
END_VAR

Mein Code:

Code:
local_any   :=  HW_CONNECT.Static.buf[bufoffset];

Mein Compiler generiert diesen seltsamen Müll nicht !
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Ok, das wars.... Danke Dir!
Relativ unüblich, daß in solchen Librarys noch irgend eine Debug Info rumgeistert, deswegen bin ich nicht drauf gekommen.

Übrigens kann man das auch aus der Quelle steuern:

Code:
{
Scl_ResetOptions                        ;
Scl_OverwriteBlocks         :=      'y' ;
Scl_GenerateReferenceData   :=      'y' ;
Scl_S7ServerActive          :=      'y' ;
Scl_CreateObjectCode        :=      'y' ;
Scl_OptimizeObjectCode      :=      'y' ;   
Scl_MonitorArrayLimits      :=      'n' ;
Scl_CreateDebugInfo         :=      'y' ;
Scl_SetOKFlag               :=      'n' ;
Scl_SetMaximumStringLength  :=      '254'
}
 
Ich vermute unterschiedliche Klammer-Setzung, vielleicht eine überflüssige Angst-Klammer im linken Beispiel mit L64.3, etwa so:
Code:
IF NOT #tPORT1_CONNECT AND [COLOR="#FF0000"]([/COLOR]#PORT1_CONNECT = 1 AND LB42 = 2[COLOR="#FF0000"])[/COLOR] THEN
  DIX[AR2,P#111.0] := TRUE; [COLOR="#008000"]//eine Bool-Variable an DBX111.0 in der Instanz (multiinstanzfähig)[/COLOR]
Code:
IF NOT #tPORT1_CONNECT AND #PORT1_CONNECT = 1 AND LB42 = 2 THEN
  DIX[AR2,P#111.0] := TRUE; [COLOR="#008000"]//eine Bool-Variable an DBX111.0 in der Instanz (multiinstanzfähig)[/COLOR]
oder so?
Code:
IF (NOT #tPORT1_CONNECT) AND (#PORT1_CONNECT = 1) AND (LB42 = 2) THEN
  DIX[AR2,P#111.0] := TRUE; [COLOR="#008000"]//eine Bool-Variable an DBX111.0 in der Instanz (multiinstanzfähig)[/COLOR]

Harald
 
Zurück
Oben