Eigentlich sollte das schon gut auf C-Ebene gehen (wenn auch nicht so Effizient wie per asm).
z.B. eine fix-Mul, die 2 Werte (interpretiert als unsigned mit 8 Bit Vor- und Nachkomma) multipliziert:
Code:
/*static inline*/ uint16_t fmul (uint16_t a, uint16_t b)
{
return (uint16_t) ((uint32_t) a*b >> 16);
}
Code:
.global fmul
.type fmul, @function
fmul:
/* prologue: frame size=0 */
/* prologue end (size=0) */
movw r18,r22 ; 4 *movhi/1 [length = 1]
clr r26 ; 12 zero_extendhisi2/1 [length = 2]
clr r27
clr r20 ; 13 zero_extendhisi2/1 [length = 2]
clr r21
movw r22,r24 ; 14 *movsi/1 [length = 2]
movw r24,r26
rcall __mulsi3 ; 16 *mulsi3_call [length = 1]
movw r26,r24 ; 17 *movsi/1 [length = 2]
movw r24,r22
movw r24,r26 ; 35 *lshrsi3_const/2 [length = 3]
clr r26
clr r27
/* epilogue: frame size=0 */
ret
/* epilogue end (size=1) */
/* function fmul size 14 (13) */
.size fmul, .-fmul
00000094 <__mulsi3>:
94: 62 9f mul r22, r18
96: d0 01 movw r26, r0
98: 73 9f mul r23, r19
9a: f0 01 movw r30, r0
9c: 82 9f mul r24, r18
9e: e0 0d add r30, r0
a0: f1 1d adc r31, r1
a2: 64 9f mul r22, r20
a4: e0 0d add r30, r0
a6: f1 1d adc r31, r1
a8: 92 9f mul r25, r18
aa: f0 0d add r31, r0
ac: 83 9f mul r24, r19
ae: f0 0d add r31, r0
b0: 74 9f mul r23, r20
b2: f0 0d add r31, r0
b4: 65 9f mul r22, r21
b6: f0 0d add r31, r0
b8: 99 27 eor r25, r25
ba: 72 9f mul r23, r18
bc: b0 0d add r27, r0
be: e1 1d adc r30, r1
c0: f9 1f adc r31, r25
c2: 63 9f mul r22, r19
c4: b0 0d add r27, r0
c6: e1 1d adc r30, r1
c8: f9 1f adc r31, r25
ca: bd 01 movw r22, r26
cc: cf 01 movw r24, r30
ce: 11 24 eor r1, r1
d0: 08 95 ret
Das ist schon mal deutlich effizienter als float (aber natürlich auch was anderes
)
Zum weiteren Optimieren kann man ja von dem Code ausgehen und weitere Kenntnise ausnutzen (z.B. welche Register in mulsi3 Anfangs 0 sind, das spart das Löschen, und man kann z.B. statt dessen __zero_reg__ draufaddieren.
Lesezeichen