Muluwuw
Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Multiplikation von 2 16-bit-Zahlen
Wenn wir schriftlich zwei Zahlen multiplizieren, kommen immer größere Zahlen heraus, als jeder der beiden Faktoren.
Beispiel: 999 * 99999 = 99899001
Weil hier eine dreistellige Zahl mit einer fünfstelligen Zahl multipliziert wurde, kann das Ergebnis achtstellig sein.
Das ist bei Binärzahlen genauso:
Wenn eine 8-Bit-Zahl mit einer 8-Bit-Zahl multipliziert wird, wird ein 16-bit-Ergebnis herauskommen.
Der Programmcode 16 bit mal 16 bit ergibt 32 bit
// This routine multiplies two 16 bit integers,
// The return value is a 32 bit integer
//
#include <heport.h>
#include <heimath.h> // definition of mul_uw_uw
#ifdef AVR
#include <avr/io.h>
#endif
#ifndef AVR
// Other processors do not need speed up
FUNCT uint32_t mul_uw_uw( uint16_t x , uint16_t y )
{
uint32_t res ;
res = (uint32_t)x * (uint32_t)y ;
return res ;
}
#else
#if !defined(__AVR_HAVE_MUL__) /* Software- Multiply */
// input:
// r23_r22 = x.h_x.l
// r25_r24 = y.h_y.l
// may destroy r18 r19 r20 r21 r22 r23 r24* r25* r26* r27*
// may not destroy r14 r15 r16 r17 r28=YL r29=YH
// return r25_r24_r23_r22
FUNCT uint32_t dummy_mul_uw_uw( uint16_t x , uint16_t y )
{
// asm(" .text " "\n");
asm(" ; " "\n");
asm(" .global mul_uw_uw" "\n");
asm(" ; See as well mul_uc_uc : 8 bit by 8 bit, result 16 bits " "\n");
asm(" ; " "\n");
asm(" ; Function mul_uw_uw " "\n");
asm(" ; multiply unsigned 16 bit by 16 bit " "\n");
asm(" ; " "\n");
asm(" ; Input: " "\n");
asm(" ; r23:r22 : The factor x " "\n");
asm(" ; r25:r24 : The factor y " "\n");
asm(" ; Results " "\n");
asm(" ; r25:r24:r23:r22 : result " "\n");
asm(" ; Destroyed registers " "\n");
asm(" ; none " "\n");
asm(" ; This program is verified by qqarith.asm " "\n");
asm(" ; " "\n");
//asm(" _Z9mul_uw_uwtt: " "\n");
asm("mul_uw_uw: " "\n");
asm(" push r16 ; " "\n");
asm(" push r18 ; " "\n");
asm(" push r19 ; " "\n");
asm(" push r20 ; " "\n");
asm(" push r21 ; " "\n");
asm(" push r26 ; " "\n");
asm(" push r27 ; " "\n");
asm(" ; Clear start values " "\n");
#ifdef __AVR_HAVE_MOVW__
asm(" movw r26,r22 ; factor x to interim storage " "\n");
asm(" movw r18,r24 ; factor y to interim storage , extend" "\n");
#else
asm(" mov r26,r22 ; factor x to interim storage " "\n");
asm(" mov r27,r23 " "\n");
asm(" mov r18,r24 ; factor y to interim storage , extend" "\n");
asm(" mov r19,r25 " "\n");
#endif
asm(" clr r20 " "\n");
asm(" clr r21 " "\n");
asm(" ; Clear result r25:r24;r23;r22 " "\n");
asm(" clr r22 " "\n");
asm(" clr r23 " "\n");
asm(" clr r24 " "\n");
asm(" clr r25 " "\n");
asm(" ; " "\n");
asm(" mul_uw_uw_3: " "\n");
asm(" lsr r27 ; shift x" "\n");
asm(" ror r26 ; next binary digit of right factor to carry " "\n");
asm(" brcc mul_uw_uw_4 " "\n");
asm(" ; Add the (shifted) left factor into result " "\n");
asm(" add r22,r18 " "\n");
asm(" adc r23,r19 " "\n");
asm(" adc r24,r20 ; add 0" "\n");
asm(" adc r25,r21 ; add 0" "\n");
asm(" mul_uw_uw_4: " "\n");
asm(" ; shift the factor y by 1 bit to left" "\n");
asm(" add r18,r18 " "\n");
asm(" adc r19,r19 " "\n");
asm(" adc r20,r20 " "\n");
asm(" adc r21,r21 " "\n");
asm(" mov r16,r26 ; no more of right factor left " "\n");
asm(" or r16,r27 " "\n");
asm(" brne mul_uw_uw_3 " "\n");
asm(" ; result is 32 bits in r25:r24:r23:r22 " "\n");
asm(" pop r27 " "\n");
asm(" pop r26 " "\n");
asm(" pop r21 " "\n");
asm(" pop r20 " "\n");
asm(" pop r19 " "\n");
asm(" pop r18 " "\n");
asm(" pop r16 " "\n");
// asm(" ret " "\n");
// The warning here is intentionally expected. a dummy return would waste 8 words
// return 0 ;
}
#else
// Hardware multiply MUL
// input:
// r23_r22 = x.h_x.l
// r25_r24 = y.h_y.l
// may destroy r18 r19 r20 r21 r22 r23 r24* r25* r26* r27*
// may not destroy r14 r15 r16 r17 r28=YL r29=YH
// return r25_r24_r23_r22
FUNCT int32_t dummy_mul_uw_uw( int16_t x , int16_t y )
{
//asm(" .text " "\n");
asm(" .global mul_uw_uw" "\n");
asm(" ; See as well mul_uc_uc : 8 bit by 8 bit, result 16 bits " "\n");
asm(" ; " "\n");
asm(" ; Function mul_uw_uw " "\n");
asm(" ; multiply unsigned 16 bit by 16 bit " "\n");
asm(" ; " "\n");
asm(" ; Input: " "\n");
asm(" ; r23:r22 : The factor " "\n");
asm(" ; r25:r24 : The factor " "\n");
asm(" ; Results " "\n");
asm(" ; r25:r24:r23:r22 : result" "\n");
asm(" ; r1 = 0 (as it is GCC standard)" "\n" );
asm(" ; Destroyed registers " "\n");
asm(" ; ro (as allows GCC standard) " "\n");
asm(" ; This program is verified by qqarith.asm " "\n");
asm(" ; " "\n");
//asm(" _Z9mul_uw_uwtt: " "\n");
asm("mul_uw_uw: " "\n");
asm(" push r18 ; " "\n");
asm(" push r19 ; " "\n");
asm(" push r20 ; " "\n");
asm(" push r21 ; " "\n");
#ifdef __AVR_HAVE_MOVW__
asm(" movw r20,r22 ; factor x to interim storage " "\n");
asm(" movw r18,r24 ; factor y to interim storage " "\n");
#else
asm(" mov r20,r22 ; factor x to interim storage " "\n");
asm(" mov r21,r23 " "\n");
asm(" mov r18,r24 ; factor y to interim storage " "\n");
asm(" mov r19,r25 " "\n");
#endif
asm(" mul r20,r18 ; low byte * low byte" "\n" );
#ifdef __AVR_HAVE_MOVW__
asm(" movw r22,r0 ; low result word" "\n" );
#else
asm(" mov r22,r0 ; low result word" "\n" );
asm(" mov r23,r1 ; low result word" "\n" );
#endif
asm(" mul r21,r19 ; high byte * high byte" "\n" );
#ifdef __AVR_HAVE_MOVW__
asm(" movw r24,r0 ; high result word" "\n" );
#else
asm(" mov r24,r0 ; high result word" "\n" );
asm(" mov r25,r1 ; high result word" "\n" );
#endif
asm(" mul r20,r19 ; low byte * high byte" "\n" );
asm(" add r23,r0 ; medium result word" "\n" );
asm(" adc r24,r1 ; medium result word" "\n" );
asm(" clr r1 ; does not modify Carry flag" "\n" );
asm(" adc r25,r1 ; carry to highest byte" "\n" );
asm(" mul r21,r18 ; low byte * high byte" "\n" );
asm(" add r23,r0 ; medium result word" "\n" );
asm(" adc r24,r1 ; medium result word" "\n" );
asm(" clr r1 ; does not modify Carry flag" "\n" );
asm(" adc r25,r1 ; carry to highest byte" "\n" );
asm(" ; result is 32 bits in r25:r24:r23:r22 " "\n");
asm(" pop r21 " "\n");
asm(" pop r20 " "\n");
asm(" pop r19 " "\n");
asm(" pop r18 " "\n");
// asm(" ret " "\n");
// The warning here is intentionally expected. a dummy return would waste 8 words
// return 0 ;
}
#endif
#endif
Der Aufruf aus C erfolgt z.B. so:
uint32_t erg ;
uint16_t f1 ;
uint16_t f2 ;
erg = mul_uw_uw(f1,f2);