16x16 signed Multiplikation

Gast #520897
Lesenswert?

int16 FIX_MPY(int16 a, int16 b)
{
  // shift right one less bit
  int32 c = ((int32)a * (int32)b) >> 14;
  // last bit shifted out = rounding-bit
  b = c & 0x01;
  // last shift + rounding bit
  a = (c >> 1) + b;
  return a;
}

Gibts da Optimierungspotential? Die Routine wird sehr oft (16384 mal pro 
Berechnung) aufgerufen, wenn man da noch was machen könnte, ich bin in 
Zeitnot :-)
Ist für einen M16, und auf die Rundung kann ich nicht verzichten.
Ich sehe nichts mehr.
Gast #520942
Lesenswert?

Hallo,

du könntest die Multiplikation vom HW-Multiplizierer ausführen lassen. 
Normalerweise sollte sich unter den intrinsics was finden lassen.

Dann würde ich wahrscheinlich zwei mal nach links schieben und das 
Hiword nehmen. Mir ist z.B. beim IAR Compiler mal aufgefallen, dass der 
Compiler wirklich 14 mal schiebt in solchen Fällen (hängt wahrscheinlich 
von der Optimierungsstufe ab). Zwei mal schieben und dann ein mov.w ist 
da schon etwas schneller.
Kannst Du die Funktion evtl. als inline Funktion verwenden?

Viele Grüße,
Ralf
Gast #520994
Lesenswert?

;## #  FUNCTION FIX_MPY
;## #  FRAME  AUTO  ( __PAD11)  size  1,  offset -1
;## #  REGISTER ARG    (       a)   size   2,   REGISTER R1
;## #  REGISTER ARG    (       b)   size   2,   REGISTER R2
;## #  ARG Size(0)  Auto Size(1)  Context Size(5)

  ._type  307,'x',269,2
  ._type  307,'m','a',0,269
  ._type  307,'m','b',0,269
  ._func  'FIX_MPY','G',1,307,$FIX_MPY,0
  ._inspect  'F', 's', "FIX_MPY", "$FIX_MPY", 'G', 6
  .align
  ._line  303
;## # C_SRC :  {
  .glb  $FIX_MPY
$FIX_MPY:
  enter  #01H
  ._block
  ._var  'a','A',269,0
  ._var  'b','A',269,0
  ._var  'c','A',292,0
  ._line  305
;## # C_SRC :    int32 c = ((int32)a * (int32)b) >> 14;
  ._block
  ._var  'a','R',269,6
  ._var  'b','R',269,7
  mul.w  R2,R1  ;  b
  ._eblock
  sha.l  #-8H,R3R1
  sha.l  #-6,R3R1
  ._line  307
;## # C_SRC :    b = c & 0x01;
  mov.w  R1,R0
  and.w  #0001H,R0  ;  b
  ._block
  ._var  'b','R',269,5
  ._line  309
;## # C_SRC :    a = (c >> 1) + b;
  sha.l  #-1,R3R1
  add.w  R1,R0  ;  a
  ._eblock
  ._block
  ._var  'a','R',269,5
  ._line  312
;## # C_SRC :    return a;
  ._eblock
  exitd

das der Auszug aus dem listing. Scheint genauso gemacht, wie du 
vorgeschlagen hast, schade.
Trotzdem vielen Dank.
#521001
Lesenswert?

What is the exact purpose of your code? Knowing that can help to 
optimise.

By shifting right by 14 places, you are throwing away a lot of 
information. Maybe you can find a way to figure out how to not calculate 
those bits in the first place. As far as I understand, even many 
hardware multipliers have a variable execution time that increases with 
the number of non-zero bits.

The following code is a little simpler and should be equivalent to 
yours:
int16 FIX_MPY(int16 a, int16 b)
{
  // shift right one less bit
  int32 c = ((int32)a * (int32)b) >> 14;
  // round it
  return ((c + 1) >> 1);
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren