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\n\t" \ "sts mach, %1\n\t" \ "sts macl, %0\n\t" \ \ "shlr16 %0\n\t" 28Bit logisch nach rechts \ "shlr8 %0\n\t" \ "shlr2 %0\n\t" \ "shlr2 %0\n\t" \ \ "shll2 %1\n\t" \ "shll2 %1\n\t" \ \ "add %0,%1\n\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 32x32=64Bit 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\n\t" 32x32=64Bit \ "sts macl, %0\n\t" Low32Bit \ "sts mach, %1\n\t" High32Bit \ \ "shad %4,%0\n\t" 28Bit arith nach rechts\ \ "shll2 %1\n\t" 2Bit nach links \ "shll2 %1\n\t" nochmal \ "add %0,%1\n\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