Multiply2ULONGs

Purpose: Multiply two UNSIGNED LONG INTEGER value by another one.
Assumes:   The caller will handle any overflow issue(s).
Passed: R25:R24:R23:R22 ULONG ulValue1 the multiplicand; the first of the two values to be multiplied
R21:R20:R19:R18 ULONG lValue2 the multiplier
Returns: R25:R24:R23:R22   ULONG   ulProduct   the 32-BIT result of the multiplication
Alters: R0, R18 through R21, R26, R27, R30, R31, and the FLAGs (SREG)
 

MultiplyULONGbyBYTE

Purpose: Multiply an UNSIGNED LONG value by a BYTE value.
Assumes:   Nothing.
Passed: R25:R24:R23:R22 ULONG ulValue1 the multiplicand
R20 BYTE bValue2 the multiplier
Returns: R25:R24:R23:R22 ULONG ulProduct 32-BIT result of the multiplication
R18 BYTE bOVStatus   overflow indicator; 0 if no overflow; nonzero if it overflowed
Alters: R0, R18, and the FLAGs (SREG)

Example:  
.ORG   0x1000                       ; Address 0x1000 = 4096 (decimal)
   ADIW    R26, 0                   ; If no parameter was passed in the command
   BREQ    ALocal_Ret               ;   line tail, just exit immediately
   MOVW    R24, R26                 ; Point to the buffer and parse any value
   CALL    AParseValue              ;  string which it contains; none illegal
   ADIW    R26, 0                   ; If no parameter was passed in the command
   BREQ    ALocal_Ret
   MOVW    R30, R24                 ; Copy R25:R24:R23:R22 to R31:R30:R27:R26
   PUSH    R23
   PUSH    R22
   MOVW    R24, R26                 ; Point to the buffer and parse any value
   CALL    AParseValue              ;  string which it contains; accept all
   MOVW    R20, R24
   MOVW    R18, R22                 ; Move the multiplier to R21:R20:R19:R18
   OR      R25, R24
   OR      R25, R23                 ; Determine if all 3 MSBytes of multipler
   IN      R26, SREG                ;  are 0 and store the result in R26
   POP     R22
   POP     R23                      ; R25:R24:R23:R22 now has the first ULONG
   MOVW    R24, R30                 ;  value parsed, the multiplicand

DecideWhichToUse:
   SBRC    R26, SREG_Z              ; If the ZERO flag was set, move R18 into
   MOV     R20, R18                 ;  R20 for the MultiplyULONGbyBYTE() call
   SBRC    R26, SREG_Z              ; R26 is only modified by Multiply2ULONGs
   CALL    AMultiplyULONGbyBYTE     ;  so if R25:R24:R23 were all zero call
   SBRS    R26, SREG_Z              ;  MultiplyULONGbyBYTE(), otherwise call
   CALL    AMultiply2ULONGs         ;  Multiply2ULONGs()

BITSET = (1 << BIT_FMT_PRE_0x) | (1 << BIT_FMT_PRINT) | (1 << BIT_FMT_COMMAS)

DisplayResults:
   LDI     R21, 0                   ; Set R21:R20 to a NULL pointer (no copy)
   LDI     R20, 0                   ; FormatULONGHex ignores BIT_FMT_COMMAS
   LDI     R18, BITSET              ; FormatULONG    ignores BIT_FMT_PRE_0x
   CALL    AFormatULONGHex          ; Output the value in hexadecimal format
   MOVW    R30, R24
   MOVW    R26, R22
   LDI     R25, 0x3A                ; ACSZ_SpaceEqualSpace is found at FLASH
   LDI     R24, 0xD2                ;  address 0x3AD2, which is " = "
   CALL    APrintFLASHASCIIz        ; Print the " = " string, which uses R20,
   MOVW    R24, R30                 ;  R22, R24, and R25
   MOVW    R22, R26
   LDI     R21, 0                   ; Set R21:R20 to a NULL pointer (no copy)
   LDI     R20, 0                   ; FormatULONGHex ignores BIT_FMT_COMMAS
   CALL    AFormatULONG             ; Output the same value in decimal format
   CALL    APrintNewLine            ;  and finish each set with CR, LF

Local_Ret:
   RET
Test it:
m>@ 4096  100 100
0x2710 = 10,000
m>@ 4096 200 200
0x9C40 = 40,000
m>@ 4096 300 300
0x15F90 = 90,000
m>@ 4096 300 10
0xBB8 = 3,000
m>@ 4096 1760 3
0x14A0 = 5,280
m>@ 4096 8000 3000
0x16E3600 = 24,000,000
m>
m>; To verify which is being called, replace one of the "CALL AMultiply..."
m>;  lines with these 2 lines: "RET" and "NOP", (since we're replacing a
m>;  4-BYTE FAR CALL opcode with two 2-BYTE opcodes), for example:
m>@ 4096  257 255      ; With the original code, both work correctly
0xFFFF = 65,535
m>@ 4096  255 257
0xFFFF = 65,535
m>
m>DFH+ 0x1030 16      ; First print the original code in iHex:
FLASH (program memory) contents:
:101030000E946A30A1FF0E94693050E040E02BE03E
:00000001FF
m>; That is the original code; remove the AMultiplyULONGbyBYTE() call:
m>:1010300008950000A1FF0E94693050E040E02BE0DD
m>:00000001FF
m>@ 4096  257 255     ; MultiplyULONGbyBYTE() is not called
m>@ 4096  255 257     ; Multiply2ULONGs() is called
0xFFFF = 65,535
m>
m>; Restore the original code (not really needed, but for comparison):
m>:101030000E946A30A1FF0E94693050E040E02BE03E
m>; Remove the AMultiply2ULONGs() call:
m>:101030000E946A30A1FF0895000050E040E02BE0DC
m>:00000001FF
m>@ 4096  257 255     ; MultiplyULONGbyBYTE() is called
0xFFFF = 65,535
m>@ 4096  255 257     ; Multiply2ULONGs() is not called
m>
m>; Restore the original code:
m>:101030000E946A30A1FF0E94693050E040E02BE03E
m>:00000001FF
m>@ 4096  257 255     ; MultiplyULONGbyBYTE() is called again
0xFFFF = 65,535
m>@ 4096  255 257     ; and Multiply2ULONGs() is called again
0xFFFF = 65,535
m>                                                                                         
Notes:       Many times, some value needs to be multiplied by a only BYTE (i.e., a value less than 256.) When that it the case, a little time can be saved by using the MultiplyULONGbyBYTE version. Prefer its use while coding, when that choice is appropriate.
Overflow means means greater than 0xFFFFFFFF.
Dropin: 
(setup
code)
;   Setup for the Multiply2ULONGs() call:
; Passed:  R25:R24:R23:R22 ulValue1  the multiplicand
;          R21:R20:R19:R18 ulValue2  the multiplier
; Returns: R25:R24:R23:R22 ulProduct the result of the multiplication
; Alters:  R0, R18 through R21, R26, R27, R30, R31, and the FLAGs

;   Setup for the MultiplyULONGsbyBYTE() call:
; Passed:  R25:R24:R23:R22 ulValue1  the multiplicand
;                      R20 bValue2   the multiplier
; Returns: R25:R24:R23:R22 ulProduct the result of the multiplication
;                      R18 bOVStatus nonzero if an overflow occurred
; Alters:  R0, R18, and the FLAGs
Also see:The Divide System Function pair.