- Labornetzteil AliExpress         
Seite 2 von 4 ErsteErste 1234 LetzteLetzte
Ergebnis 11 bis 20 von 31

Thema: Festpunktarithmetik

  1. #11
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Anzeige

    Powerstation Test
    Nochwas zu Codegröße/Laufzeit:

    IMHO wird eine Version mit normalen Funktionen (F-Version) keinen merklichen Vorteil an Flashverbrauch haben gegen eine Inline-Version (I-Version).

    Grund: Es muss nicht nur Code für die Aufrufe erzeugt werden, sondern auch Code, um die callclobbered Register um einen Aufruf zu sichern und die Argumente/RetValue in die von der ABI dafür vorgesehenen Übergaberegister zu kopieren.

    Ein Vergleich der beiden Versionen wäre dennoch interessant. Alle Implementierungen in den Header zu klatschen ist aber keine gute Idee, weil die Implementierungen in der F-Version dann mehrfach vorliegen, wenn die Fix-Arith in verschiedenen Modulen gebraucht wird.

    Man könnte den Header so aufbauen:
    Code:
    #ifndef _FIX_ARITH_H_
    ...blabla
    
    #ifdef SOME_SYMBOL
    #    define FIX_MEM_CLASS static inline // oder always_inline
    #else
    #    define FIX_MEM_CLASS extern
    #endif // SOME_SYMBOL
    
    // prototypes
    FIX_MEM_CLASS uint8_t foo (...);
    ...
    
    #ifndef SOME_SYMBOL
    #include "fix-arith.c"
    #endif // !SOME_SYMBOL
    
    ...
    fix-arith.c implementiert wie gewohnt und nur in der F-Version wird gegen fix-arith.o gelinkt. (Noch besser wäre ne feingranulierte Lib).
    Disclaimer: none. Sue me.

  2. #12
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    58
    Beiträge
    1.195
    Hier jetzt ein update. Nachdem ich zwei Versionen durcheinander gewürfelt hatte (Zeit für Subversion) ist jetzt hoffentlich alles im Lot
    Angehängte Dateien Angehängte Dateien

  3. #13
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Kontrollier das nochmal. Da gibt's einige Regressionen, zb

    (a == b == c)
    Disclaimer: none. Sue me.

  4. #14
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    58
    Beiträge
    1.195
    Vermaledeites Hin- und herkopieren Als nächstes kümmere ich mich um einen subversion server.

  5. #15
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    58
    Beiträge
    1.195
    So, auf ein Neues.

    Grund: Es muss nicht nur Code für die Aufrufe erzeugt werden, sondern auch Code, um die callclobbered Register um einen Aufruf zu sichern und die Argumente/RetValue in die von der ABI dafür vorgesehenen Übergaberegister zu kopieren.
    Ich dachte, dass man zumindest das Retten/Restaurieren der Register durch die Option -mcall-prologues reduziert. Aber "Versuch macht kluch".

    Hier jetzt die korrigierte Version.
    Angehängte Dateien Angehängte Dateien

  6. #16
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    :75: "=d", "=d" → "=d", "=0"
    :129: "=a" → "=&d"
    :149: %A0 = ?
    :236: "=&w" → "=&d"
    :257: %1 ist kein IN-op
    :266: "=w", "=w" → "=&d", "=0"
    :281: %1 ist kein IN-op
    :290: "=w", "=w" → "=&d", "=0"
    :313: "=&a" → "=&r"
    :344: "=&w" → "=&d"
    Disclaimer: none. Sue me.

  7. #17
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    58
    Beiträge
    1.195
    Hi,

    vielen Dank. An ein paar Stellen habe ich Probleme/Fragen:

    75, 266, 290
    ../fixedPointArithmetics.c:283: error: matching constraint not valid in output operand

    236, 266, 344: erfordert m.E. "=w" wegen adiw bzw. sbiw Operation.

  8. #18
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Stimmt, da war was mit "=0"... hab grad keinen Compiler hier.

    Dito mit "=w" bzw. "=&w"

    Was mit nicht gefällt sind Konstrukte wie
    Code:
    		: "=w" (result), "=w" (op1)
    		: "0" (op1), ...
    Hier wüde ich lieber destruktiv auf op1 arbeiten, was ja auch dem Inhalt das asm entspricht.

    Wenn man das so hinschreibt wie bisher, hat man zwar ne schönere C-Quelle, aber Magendrücken macht das schon.

    Ausserdem belegt das unnötig eines der wertvollen w-Regs, von denen man nur 4 hat. Für deine Anwendung bleiben dann nur noch 2 Regs, Y wird vermutlich für den Frame verbraucht, so daß nur eines überbleibt.

    zu -mcall-prologues:

    Aus gcc-Sicht teilen sich die Register in (mindestens) 3 Gruppen:

    -- fixed (wird nicht allokiert, zB r0, r1)
    -- call saved (wird durch f() nicht zerstört, zB Y)
    -- call clobbered (aka call used, f() hinterlässt nen Schweinestall, zB X, Z)

    Falls eine Funktion ein call used Register verwendet, so muss sie dieses im Prolog sichern (push) und im Epilog wieder herstellen (pop).

    Wenn das bei recht vielen Funktionen recht viele Register sind, dann kann man mit -mcall-prologues Platz sparen, weil Epilog und Prolog in eigene Funktionen ausgelagert werden. Diese Sicher-/Herstellfunktionen dauern aber recht lange, weil sie den Rundumschlag machen (müssen) und alle call clobbered register sichern und nicht nur die, welche die Funktion tatsächlich benutzt. -mcall-prologues wirkt also auf callees (aufgerufene) Funktionen.

    Aus Sicht des Callers (Aufrufer) sieht das etwas anders aus. Hier bringt die Option nichts (ausser wenn die Funktion selber nen großen Prolog/Epilog hat und wir sie als callee betrachten).
    Wenn der Caller eine Variable verwendet, die über einen Funktionsaufruf hinweg lebt, dann muss diese notwendigerweise call saved sein, trägt also u.U. zur Größe des Prolog/Epilog bei oder muss ständig zwischen call saved oder gar Frame (da lebt das Reg) und call used (parameter/ret-val) hin- und herkopiert werden.

    Falls die Hardregs (GPRs) der Maschine nicht ausreichen, dann wird für die Funktion ein Frame angelegt und die überschüssigen Variablen leben im Frame. Von der Laufzeit her ist das übel, weil für jeden Zugriff ein Speicherzugriff notwendig ist. Zudem muss ein Framepointer (Y-Reg) angelegt werden, um in den Frame greifen zu können.

    Man tut also gut daran, nicht allzu viele lokale Variablen zu haben. Wenn man zB ein lokales Array braucht, dann sollte man das als local static anlegen und nicht als local auto!

    Ausserdem ist es günstig, möglichst viele leaf-Functions (Blätter) zu haben, also Funktionen, die keine andere Funktion aufrufen (nur callee sind, aber kein caller). Das kann dadurch gegeben sein, daß die Funktion keine Funktionen aufruft oder aller aufgerufenen Funktionen geinlinet werden oder dead Code sind, etc.
    Disclaimer: none. Sue me.

  9. #19
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    58
    Beiträge
    1.195
    Was mit nicht gefällt sind Konstrukte wie
    Ich schau mal, was ich hinbekomme.

    Bei den call-prologues muss ich halt einen Tod sterben. Derzeit ist Geschwindigkeit aber eher nicht mein Problem (zumindest nicht durch Funktionsaufrufe) da algorithmenbedingt in den Funktionen recht viel Zeit verbraucht wird. Sofern die Aufrufe auf fmacX zeitkritisch werden, pack' ich das in ein Macro.

  10. #20
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Für Codegröße lohnt es sich, die Saturierung auszulagern. Zumindest dann, wenn das öfter gebraucht wird, was ja wohl der Fall ist:

    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    #define inline __attribute__((always_inline))
    
    #define MAX_FIX_VALUE 0x8001
    #define MIN_FIX_VALUE 0x7fff
    
    static inline uint8_t foo (uint8_t op1, uint8_t op2);
    void __attribute__((naked)) saturate16 (void);
    
    void saturate16 (void)
    {
        asm volatile ("; r27:r26 = sat(r1:r0), r1=0  " "\n\t"
            "movw    r26, r0"                          "\n\t"
            "brvc    0f"                               "\n\t"
            "ldi     r26, lo8(%[max])"                 "\n\t"
            "ldi     r27, hi8(%[max])"                 "\n\t"
            "brcc    0f"                               "\n\t"
            "ldi     r26, lo8(%[min])"                 "\n\t"
            "ldi     r27, hi8(%[min])"                 "\n"
            "0:\tclr     __zero_reg__"                 "\n\t"
            "ret"
            :: [max] "i" (MAX_FIX_VALUE),  [min] "i" (MIN_FIX_VALUE) );
    }
    
    uint8_t foo (uint8_t op1, uint8_t op2)
    {
        uint16_t result;
        
        asm volatile (
            "muls    %[op1], %[op2] "                "\n\t"
            "%~call   saturate16 ; r27:r26 = sat(r1:r0), r1=0  "
            : [result] "=x" (result)
            : [op1] "a" (op1), [op2] "a" (op2)
            );
    
        return result;
    }
    
    
    uint8_t mul5 (uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e)
    {
        uint8_t x = foo (a, b);
    
        x = foo (x, c);
        x = foo (foo (x, d), e);
    
        return x;
    }
    
    SIGNAL (SIG_INTERRUPT0)
    {
        // all used GPRs are saved as desired :-)
        foo (1, 2);
    }
    ergibt:

    Code:
    	.file	"fix.c"
    	.arch atmega8
    __SREG__ = 0x3f
    __SP_H__ = 0x3e
    __SP_L__ = 0x3d
    __tmp_reg__ = 0
    __zero_reg__ = 1
    	.global __do_copy_data
    	.global __do_clear_bss
     ;  GNU C version 3.4.6 (avr)
     ; 	compiled by GNU C version 3.3 20030226 (prerelease) (SuSE Linux).
     ;  GGC heuristics: --param ggc-min-expand=99 --param ggc-min-heapsize=129491
     ;  options passed:  -fpreprocessed -mmcu=atmega8 -auxbase -Os
     ;  -fverbose-asm
     ;  options enabled:  -feliminate-unused-debug-types -fdefer-pop
     ;  -fomit-frame-pointer -foptimize-sibling-calls -funit-at-a-time
     ;  -fcse-follow-jumps -fcse-skip-blocks -fexpensive-optimizations
     ;  -fthread-jumps -fstrength-reduce -fpeephole -fforce-mem -ffunction-cse
     ;  -fkeep-static-consts -fcaller-saves -freg-struct-return -fgcse
     ;  -fgcse-lm -fgcse-sm -fgcse-las -floop-optimize -fcrossjumping
     ;  -fif-conversion -fif-conversion2 -frerun-cse-after-loop
     ;  -frerun-loop-opt -fdelete-null-pointer-checks -fsched-interblock
     ;  -fsched-spec -fsched-stalled-insns -fsched-stalled-insns-dep
     ;  -fbranch-count-reg -freorder-functions -fcprop-registers -fcommon
     ;  -fverbose-asm -fregmove -foptimize-register-move -fargument-alias
     ;  -fstrict-aliasing -fmerge-constants -fzero-initialized-in-bss -fident
     ;  -fpeephole2 -fguess-branch-probability -fmath-errno -ftrapping-math
     ;  -minit-stack=__stack -mmcu=atmega8
    
    	.text
    .global	saturate16
    	.type	saturate16, @function
    saturate16:
    /* prologue: frame size=0 */
    /* prologue: naked */
    /* prologue end (size=0) */
    /* #APP */
    	; r27:r26 = sat(r1:r0), r1=0  
    	movw    r26, r0
    	brvc    0f
    	ldi     r26, lo8(-32767)	 ; 
    	ldi     r27, hi8(-32767)	 ; 
    	brcc    0f
    	ldi     r26, lo8(32767)	 ; 
    	ldi     r27, hi8(32767)	 ; 
    0:	clr     __zero_reg__
    	ret
    /* #NOAPP */
    /* epilogue: frame size=0 */
    /* epilogue: naked */
    /* epilogue end (size=0) */
    /* function saturate16 size 20 (20) */
    	.size	saturate16, .-saturate16
    .global	mul5
    	.type	mul5, @function
    mul5:
    /* prologue: frame size=0 */
    	push r16
    /* prologue end (size=1) */
    	mov r19,r22	 ;  b, b
    	mov r21,r18	 ;  d, d
    	mov r23,r24	 ; , a
    /* #APP */
    	muls    r23, r19 	 ; , b
    	rcall   saturate16 ; r27:r26 = sat(r1:r0), r1=0  
    /* #NOAPP */
    	movw r18,r26	 ;  result,
    /* #APP */
    	muls    r18, r20 	 ;  result, c
    	rcall   saturate16 ; r27:r26 = sat(r1:r0), r1=0  
    /* #NOAPP */
    	movw r18,r26	 ;  result,
    /* #APP */
    	muls    r18, r21 	 ;  result, d
    	rcall   saturate16 ; r27:r26 = sat(r1:r0), r1=0  
    /* #NOAPP */
    	movw r18,r26	 ;  result,
    /* #APP */
    	muls    r18, r16 	 ;  result, e
    	rcall   saturate16 ; r27:r26 = sat(r1:r0), r1=0  
    /* #NOAPP */
    	mov r24,r26	 ;  result, result
    	clr r25	 ;  <result>
    /* epilogue: frame size=0 */
    	pop r16
    	ret
    /* epilogue end (size=2) */
    /* function mul5 size 27 (24) */
    	.size	mul5, .-mul5
    .global	__vector_1
    	.type	__vector_1, @function
    __vector_1:
    /* prologue: frame size=0 */
    	push __zero_reg__
    	push __tmp_reg__
    	in __tmp_reg__,__SREG__
    	push __tmp_reg__
    	clr __zero_reg__
    	push r18
    	push r19
    	push r26
    	push r27
    /* prologue end (size=9) */
    	ldi r18,lo8(1)	 ;  op1,
    	ldi r19,lo8(2)	 ;  op2,
    /* #APP */
    	muls    r18, r19 	 ;  op1, op2
    	rcall   saturate16 ; r27:r26 = sat(r1:r0), r1=0  
    /* #NOAPP */
    /* epilogue: frame size=0 */
    	pop r27
    	pop r26
    	pop r19
    	pop r18
    	pop __tmp_reg__
    	out __SREG__,__tmp_reg__
    	pop __tmp_reg__
    	pop __zero_reg__
    	reti
    /* epilogue end (size=9) */
    /* function __vector_1 size 24 (6) */
    	.size	__vector_1, .-__vector_1
    /* File "fix.c": code   71 = 0x0047 (  50), prologues  10, epilogues  11 */
    Sieht doch ganz gut aus.

    Ich hoffe, ich verwirre dich nicht zu sehr :P
    Disclaimer: none. Sue me.

Seite 2 von 4 ErsteErste 1234 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests