Compiler erzeugt falschen Code - wie überlisten?



  • Gast++ schrieb:

    if (value & 128) 
        //sda = 0;		// SDA release
        sda &= 0;
    else 
        //sda = 1;
        sda |= 1;
    

    ???

    Sonst wär inline Assembler ja auch noch 'ne Möglichkeit.

    Grüsse

    *this

    Das tut auch wieder nur für den ersten Fall, sda &= 0, der else- Pfad kriegt keinen Code erzeugt. 😞
    Kann es sein, daß das Gift in dem If- Argument liegt 😕



  • Bashar schrieb:

    Versteh ich das Problem richtig: sda ist ein einzelnes Bit, das man auf dieser Architektur separat ansprechen kann (welche Architektur ist das? welcher Compiler?). Du möchtest sda allein schreiben, aber der Compiler erzeugt einen Befehl, der erst das ganze Byte einliest, das entsprechende Bit verändert, und das ganze Byte wieder rausschreibt?

    Der Reihe nach:
    Compiler ist der NC30 für Renesas M16C-CPUs, Bitfields sind Standard- ANSI.
    sda ist als Bit eines Registers definiert, das wiederum mit #pragma adress angelegt war, was standardweise als volatile interpretiert wird.
    Das Problem liegt nicht im registerweisen Lesen, sondern daß bei read-modify-write immer eine Identität erzeugt wird (sda ist eigentlich nur das direction bit).
    Die Frage ist nun, wie man den Compiler daran hindern kann, read-modify-write- Prozessorbefehle zu erzeugen ...



  • pointercrash() schrieb:

    Compiler ist der NC30 für Renesas M16C-CPUs, Bitfields sind Standard- ANSI.

    ... aber man kann sie nicht einzeln ansprechen, die kleinste separat adressierbare Einheit in ANSI-C ist das Byte. Bit-Variablen kenn ich z.B. vom 8051, mit über ANSI hinausgehenden Compilererweiterungen.

    sda ist als Bit eines Registers definiert, das wiederum mit #pragma adress angelegt war, was standardweise als volatile interpretiert wird.
    Das Problem liegt nicht im registerweisen Lesen, sondern daß bei read-modify-write immer eine Identität erzeugt wird (sda ist eigentlich nur das direction bit).

    Das versteh ich nicht. Was meinst du mit Identität?



  • Bashar schrieb:

    .. aber man kann sie nicht einzeln ansprechen, die kleinste separat adressierbare Einheit in ANSI-C ist das Byte. Bit-Variablen kenn ich z.B. vom 8051, mit über ANSI hinausgehenden Compilererweiterungen.

    Ist nicht Standard? 😕

    /********************************************************
    *	declare SFR bit					*
    ********************************************************/
    struct bit_def {
    		char	b0:1;
    		char	b1:1;
    		char	b2:1;
    		char	b3:1;
    		char	b4:1;
    		char	b5:1;
    		char	b6:1;
    		char	b7:1;
    };
    union byte_def{
    	struct bit_def bit;
    	char	byte;
    };
    
    #pragma ADDRESS		p7_addr		03e0H		
    /*------------------------------------------------------
    	Port P7 direction register  bit
    ------------------------------------------------------*/
    union byte_def pd7_addr;
    #define		pd7		pd7_addr.byte
    
    #define		pd7_0		pd7_addr.bit.b0		/* P7 direction register  bit0 */
    #define		pd7_1		pd7_addr.bit.b1		/* P7 direction register  bit1 */
    #define		pd7_2		pd7_addr.bit.b2		/* P7 direction register  bit2 */
    #define		pd7_3		pd7_addr.bit.b3		/* P7 direction register  bit3 */
    #define		pd7_4		pd7_addr.bit.b4		/* P7 direction register  bit4 */
    #define		pd7_5		pd7_addr.bit.b5		/* P7 direction register  bit5 */
    #define		pd7_6		pd7_addr.bit.b6		/* P7 direction register  bit6 */
    #define		pd7_7		pd7_addr.bit.b7		/* P7 direction register  bit7 */
    
    #define	sda					pd7_0
    

    Bashar schrieb:

    Das versteh ich nicht. Was meinst du mit Identität?

    Verstehe ich momentan selbst nimmer 😞 , sitze aber auch schon seit heute, nein, gestern in aller Früh' dran. Jedenfalls hängt der Pin auf Hi fest, was man nur durch den generierten Assemblercode erklären kann.
    Ich glaube, eine Mütze Schlaf könnte jetzt nicht schaden ... 😉



  • hi,
    kennst du das: http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf ?
    read-modify-write auf 'nem datenrichtungsregister sollte eigentlich kein problem sein. es wird trotzdem nur der port geändert, den du willst und dass dein compiler mist baut, ist sehr unwahrscheinlich (wenn er nicht GCC heisst oder von imagecraft kommt 😉 )
    folgendes solltest du ausserdem überprüfen:
    - ziehst du den bus (mit dem datenregister) fest auf null?
    - sind pullups angeschlossen?
    wenn das alles stimmt: oszilloskop dranhalten (2-kanal reicht, sda und scl anschauen), damit siehste sofort wo's zickt...
    - stimmen die pegel?
    - sind es saubere signale?
    - ist das timing innerhalb der toleranzen?
    - etc...
    🙂
    btw: haben die renesas-teile kein i2c peripheral eingebaut (ich glaub' das haben sie), oder wieso machst du das mit bit-getoggle?



  • pointercrash() schrieb:

    Bashar schrieb:

    .. aber man kann sie nicht einzeln ansprechen, die kleinste separat adressierbare Einheit in ANSI-C ist das Byte. Bit-Variablen kenn ich z.B. vom 8051, mit über ANSI hinausgehenden Compilererweiterungen.

    Ist nicht Standard? 😕
    [snip]

    Doch, Bitfelder schon. Aber es gibt keine Garantie, dass tatsächlich nur die Bits angesprochen werden, die du manipulierst. Das müsstest du dem Compiler irgendwie klar machen. Da ich deinen Compiler nicht kenne, kann ich dir auch nicht sagen wie.
    BTW fehlt da nicht irgendwo ein volatile?



  • pale dog schrieb:

    hi,
    read-modify-write auf 'nem datenrichtungsregister sollte eigentlich kein problem sein. es wird trotzdem nur der port geändert, den du willst

    Stimmt, auf dem RICHTUNGSregister nicht, aber da war ich wohl gestern zu lange drangesessen, um noch auf den anderen Punkt zu kommen: Bei Input/Output- Registern muß man aber sehr wohl aufpassen ⚠, woher der Wert kommt ⚠ und wohin er geschrieben wird ⚠
    Ich habe die Routinen aus einem Programm für einen MELPS77 entnommen, da hat es funktioniert. Unterschied also nur die defines für die Pins, Compiler und Prozessor. Um es kurz zu machen: Der MELPS77 hat doppelt schattierte Portregister, der M16C nur ein einzelnes Schattenregister. Also, wenn ich beim MELPS einen Pin einlese, landet das in einem separaten Latch, beim M16C wird damit der Bitwert für die Ausgangsfunktion überladen.
    Bei der Abfrage des Ack liest man eine "0" ein, was ja dem vorgeladenen Ausgangswert entspricht. Nur nach Transfers ohne Ack liest man ein Hi ein und der Pin kann fortan durch Umschalten der Direction den Pegel nicht mehr auf Lo ziehen. Da die meisten Transfers einen Ack enthalten, erschien das zunächst irgendwie unsystematisch 😕

    pale dog schrieb:

    und dass dein compiler mist baut, ist sehr unwahrscheinlich (wenn er nicht GCC heisst oder von imagecraft kommt 😉 )

    Oder von Keil ... 👎 . Nein, ich hatte den Compiler nicht direkt im Verdacht, sondern wollte ihm lediglich das r-m-w auf dem Register abgewöhnen, was nutzlos gewesen wäre, wie wir nun wissen ... 😃

    Btw, ich habe keine GCC- Erfahrungen und müßte demnächst einen fetteren Prozessor einsetzen. Für M32 und H8 gibt es adaptierte GCC- Compiler. Ist das so, daß man bei "mission critical" grundsätzlich von GCC die Finger lassen soll? Mit gekauften Compilern bin ich auch schonmal schwer eingefahren.
    Es gibt halt hier ziemlich viel Gemotze über den GCC für X'86, fragt sich, ob man das verallgemeinern kann.

    pale dog schrieb:

    wenn das alles stimmt: oszilloskop dranhalten (2-kanal reicht, sda und scl anschauen), damit siehste sofort wo's zickt...

    Jo, oder Singlestep und ein einzelner Logic- Pen tun's auch, i2c kann ja statisch betrieben werden. Wenn's bei Speed nicht klappt, können nur die Pullups zu groß sein.

    pale dog schrieb:

    btw: haben die renesas-teile kein i2c peripheral eingebaut (ich glaub' das haben sie), oder wieso machst du das mit bit-getoggle?

    Haben Sie, haarsträubed implementiert, schlecht dokumentiert und die Beispiele aus den Appnotes funktionieren nicht mit echter Hardware 🤡 . Ein AppIng bei der Glyn meinte, er würde sich drum kümmern und das zum Laufen bringen, nach zwei Wochen habe ich aufgegeben, ihn zu fragen, ob's denn jetzt geht und mich an die ollen Scrips für die MELPS erinnert.

    Bashar schrieb:

    Aber es gibt keine Garantie, dass tatsächlich nur die Bits angesprochen werden, die du manipulierst. Das müsstest du dem Compiler irgendwie klar machen. Da ich deinen Compiler nicht kenne, kann ich dir auch nicht sagen wie.

    Doch, macht er, ist ein globaler switch. Einzeln kann man das aber nicht beeinflussen.

    Bashar schrieb:

    BTW fehlt da nicht irgendwo ein volatile?

    Njet, über #pragma adress angelegte Symbole kriegen den Stempel "volatile" aufgedrückt, ebenso wie alle davon abgeleiteten Symbole. Es gibt noch ein Pragma, mit dem das für einzelne Symbole verhindert werden kann, sowie einen globalen switch, mit dem man das volatile wieder abstellen kann. Wozu der gut sein soll, weiß ich aber nicht, denn dann läuft ja erwartungsgemäß gar nix mehr richtig 🤡

    Jedenfalls Danke, durch eure Bemerkungen angeregt, habe ich Forschung in der richtigen Richtung betrieben! 😃



  • pointercrash() schrieb:

    pale dog schrieb:

    und dass dein compiler mist baut, ist sehr unwahrscheinlich (wenn er nicht GCC heisst oder von imagecraft kommt 😉 )

    Btw, ich habe keine GCC- Erfahrungen und müßte demnächst einen fetteren Prozessor einsetzen. Für M32 und H8 gibt es adaptierte GCC- Compiler. Ist das so, daß man bei "mission critical" grundsätzlich von GCC die Finger lassen soll?

    GCC's erzeugen im verhältnis zu kommerziellen compilern grossen und langsamen code. wenn man viel programmspeicher hat und speed egal ist, dann kann man ihn nehmen, sonst eher nicht.

    pointercrash() schrieb:

    pale dog schrieb:

    btw: haben die renesas-teile kein i2c peripheral eingebaut (ich glaub' das haben sie), oder wieso machst du das mit bit-getoggle?

    Haben Sie, haarsträubed implementiert, schlecht dokumentiert und die Beispiele aus den Appnotes funktionieren nicht mit echter Hardware 🤡 . Ein AppIng bei der Glyn meinte, er würde sich drum kümmern und das zum Laufen bringen, nach zwei Wochen habe ich aufgegeben, ihn zu fragen, ob's denn jetzt geht und mich an die ollen Scrips für die MELPS erinnert.

    den M16C gibt's doch schon seit 5 jahren oder noch länger. ich glaube kaum, dass das i2c nicht funktioniert. mit bit-banging verbrät man nur wertvolle prozessorzeit. die hardware macht das besser und schneller...



  • Hi Pale dog,

    gut, beit speed also eher nicht der gcc, dann muß ich schauen, ob ich mit der Trial bis 64 kB Objektgröße durchkomme oder in den sauren Apfel beißen und für die VV löhnen.

    pale dog schrieb:

    ich glaube kaum, dass das i2c nicht funktioniert. mit bit-banging verbrät man nur wertvolle prozessorzeit. die hardware macht das besser und schneller...

    Nicht wirklich. Für Massentransfer ist der i2c eh nicht gedacht, es geht meist nur um ein paar Bytes. Da das Protokoll bei Single Master komplett statisch ist, ist es jederzeit unterbrechbar (z.B. durch Interrupts). Wenn ich die eingebauten Automaten anschmeiße, polle ich sowieso nur die Flags, wann die Hardware ihre Arbeit getan haben, da kann's die CPU genausogut auch selber per Software tun. Die meisten Appnotes zum M16C bilden die i2c sowieso über Software, ich hab's nur selber geschrieben, weil sie entweder nicht funktionierten oder unhandlich waren, weil so Sachen wie Multimasterbetrieb einbezogen wurden.
    Es gibt eine neuere Appnote, die alles in eine Interruptsteuerung zieht, aber das ist der Overkill- Popanz, den ich nicht brauche. Hab' auch keine Lust auf Herumtesten ... :p
    300 selbstgeschriebene Zeilen und ich kann's an beliebige Pins hängen, gefällt mir besser. 😉



  • pointercrash() schrieb:

    Wenn ich die eingebauten Automaten anschmeiße, polle ich sowieso nur die Flags, wann die Hardware ihre Arbeit getan haben, da kann's die CPU genausogut auch selber per Software tun.

    ne, der trick ist ja, zuerst pollen ob der vorherige transfer beendet wurde, manche machen es falsch (zuerst senden und sofort pollen ob das byte weg ist).
    so kannst du nach dem transfer und bis zum nächsten aufruf der sendefunktion anderen code ausführen, was die polling-zeit verkürzt (u.u. ist das byte schon längst wech)

    pointercrash() schrieb:

    Es gibt eine neuere Appnote, die alles in eine Interruptsteuerung zieht, aber das ist der Overkill- Popanz, den ich nicht brauche.

    ja, die technik ist bekannt, für jeden event (tx-, rx-ready, fehler, usw.) einen interrupt abzuhandeln ist natürlich mies in einem single-cpu system...
    sowas geht fein auf einem S12X, bei dem man den interrupt an einen kleinen RISC core weitergeben kann, der dann das peripheral bedient usw...

    pointercrash() schrieb:

    ...und ich kann's an beliebige Pins hängen, gefällt mir besser. 😉

    das spricht natürlich für deine variante 😉


Anmelden zum Antworten