Assembler cracks anwesend?

22/12/2010 - 23:42 von Olaf Kaluza | Report spam
Ich habe mal eine kleine Aufgabe fuer diejenigen die noch Bits
persoenlich atmen. :)

Ich habe hier auf meinem SH7262, also SH2A die libmad installiert um
damit mp3s abzuspielen. Mittlerweile funktioniert das auch ganz gut,
koennte aber noch etwas schneller sein. Dafuer kennt die Libarie fuer
verschiedene Prozessoren spezielle Assembleroptimierungen, aber leider
nicht fuer meinen sh2a.

Defaultmaessig macht die Libary soetwas:

#define mad_f_mul(x, y) (((x) >> 12) * ((y) >> 16))

Das funktioniert, ist langsam und hat einen gewissen Verlust an
Genauigkeit zur Folge. Alle Variablen sind 32Bit signed longs.

Besser waer natuerlich soetwas: (x*y)>>28. Das ist aber natuerlich
wegen den notwendigen Registerbreiten auf den meisten Prozessoren
inakzeptabel. Ein ARM oder auch mein SH2A sollten das aber koennen.

Jetzt mal zu meinen Loesungsansaetzen:

#define mad_f_mul(x, y) ({ signed long __dummy; signed long __result;\
asm ( \
"dmuls.l %2, %3\t" \
"sts mach, %1\t" \
"sts macl, %0\t" \
\
"shlr16 %0\t" 28Bit logisch nach rechts \
"shlr8 %0\t" \
"shlr2 %0\t" \
"shlr2 %0\t" \
\
"shll2 %1\t" \
"shll2 %1\t" \
\
"add %0,%1\t" \
\
: "=&r" (__dummy), "=r" (__result) \
: "%r" (x), "r" (y) \
: "cc" \
); \
__result; \
})

Obiger Code funktioniert. Allerdings ueberrascht es mich das er
funktioniert. Und zwar wegen den shlr Befehlen. Da die Libmad mit
signed longs arbeitet sollten das IMHO shar, also arithmetisches Shift
sein. Das kann die CPU aber leider nur Bitweise und nicht fuer mehrere
Bits in einem einzigen Befehl. BTW: Jeder der obigen Befehle benotigt
1Takt, nur die 32x32dBit Multiplikation benoetigt 2Takte.

Mein naechstes Versuch sah so aus:

#define mad_f_mul(x, y) ({ signed long __dummy; signed long
__result;\
asm ( \
"dmuls.l %2, %3\t" 32x32dBit \
"sts macl, %0\t" Low32Bit \
"sts mach, %1\t" High32Bit \
\
"shad %4,%0\t" 28Bit arith nach rechts\
\
"shll2 %1\t" 2Bit nach links \
"shll2 %1\t" nochmal \
"add %0,%1\t" alles zusammenbastln\
\
: "=&r" (__dummy), "=r" (__result) \
: "%r" (x), "r" (y), "r" (0xffffffe4L) \
: "cc" \
); \
__result; \
})

Hier benutze ich den Barrelshifter in dem Microcontroller. Er kann
damit in einem Takt 28Bits arithmetisch nach rechts
shiften. Allerdings wird das reinladen der Konstante (0xffffffe4L -28) einen Extratakt kosten.
Problem ist nur das dieser Code nicht funktioniert. Genauer gesagt
verwurstet er mir jedes MP3 zu weissem Rauschen. Und ich verstehe
leider nicht warum. Wenn ich die Funktion mit ein paar Testdaten
aufrufe und mit meinem Taschenrechner gegenrechne sieht alles gut aus!

Das shiften um genau 28Bits ist notwendig weil die gesamte Libarie
darauf aufbaut. Hat vielleicht jemand eine bessere Idee wie man
soetwas loesen kann? Tricks welchen den Divisionsbefehl verwenden sind
leider nichts zielfuehrend weil der lahme 34Takte braucht.

Das Problem ist das mir die Multiplikation ihr 64Bit Ergebniss in zwei
getrennten Registern liefert. Ich benoetige davon zwar nur 32Bit aber
muss die Bits muehsam zusammenbasteln.

Jeder einzelne Takt der eingespart werden kann ist wichtig. Diese
Funktion wird bei der MP3 Decodierung wirklich reichlich verwendet und
ich kann sofort sehen wie die Ausfuehrungszeiten nach oben gehen wenn
diese Funktion laenger wird. Allerdings koennte eine Loesung die
1-2Befehle laenger ist eventuelle akzeptabel sein wenn ich die
Befehle geschickt verschachteln kann weil der Controller ja zwei
Befehle gleichzeitig ausfuehren kann, auch wenn ich noch nicht
begriffen habe nach welchen Kriterien das ablaeuft.

Olaf
 

Lesen sie die antworten

#1 Jan Kandziora
23/12/2010 - 00:31 | Warnen spam
Olaf Kaluza schrieb:
\
"shad %4,%0\t" 28Bit arith nach rechts\
\



Prüfe mal mit einem Disassembler, was er tatsàchlich assembliert. Evtl. ist
einfach der Zugriff auf %4 problematisch.

Mit freundlichem Gruß

Jan

Ähnliche fragen