
*===================================================================
*  The timings are given without any warranty. It's hard to figure
*  out all possible situations...
*
*  The difference between minimum and maximum timings is due to the
*  branch cache and superscalar capabilities.
*  Maximum timing assumes no superscalar dispatches and wrong branch
*  predictions.
*  Minimum timing assumes superscalar dispatches and correctly
*  predicted branches.
*===================================================================

        CNOP 0,8

Patch_Start

* a (32) × b (32) = c (64) unsigned)
* d0       d1       d0:d1
*
* timings :
*   a×b=0  : 13 (min) -> 29 (max) cycles.
*   a×b<>0 : 36 (min) -> 55 (max) cycles.
*
* NOTE: Shift/rotate instructions may be dispatched, while
*       swap will only execute in pOEP.

UMult64 ;        movem.l d4/d5,-(sp)     ; 2
                move.l  d5,-(sp)
                move.l  d4,-(sp)

                move.l  d1,d5           ; 1
                beq.s   .return0        ; Result = 0

                move.l  d0,d4           ; 1/8
                beq.s   .return0        ; Result = 0
                
;                movem.l d2/d3,-(sp)     ; 3/10
                move.l  d3,-(sp)
                move.l  d2,-(sp)
                moveq   #16,d2          ; 1
                move.l  d0,d3           ; 0/1
                ror.l   d2,d5           ; 1   (=swap)
                ror.l   d2,d3           ; 0/1 (=swap)
                                        ; 9 (min) => 25 (max)

                ; d0.w = Factor1_l = d4.w       * [(a<<16)+b] × [(c<<16)+d] = 
                ; d3.w = Factor1_h              * ac<<32 + (ad+bc)<<16 + bd
                ; d1.w = Factor2_l
                ; d5.w = Factor2_h

                mulu.w  d1,d0           ; 2   Factor2_l × Factor1_l = bd
                mulu.w  d3,d1           ; 2   Factor1_h × Factor2_l = ad
                mulu.w  d5,d4           ; 2   Factor2_h × Factor1_l = bc
                mulu.w  d5,d3           ; 2   Factor2_h × Factor1_h = ac

                ror.l   d2,d0           ; 1   (=swap)
                clr.l   d5              ; 0/1
                add.w   d1,d0           ; 1   Add ad to bd's most significant word
                addx.l  d5,d3           ; 1   Add the potential carry to ac
                add.w   d4,d0           ; 1   Add bc to bd's most significant word
                addx.l  d5,d3           ; 1   Add the potential carry to ac

                lsr.l   d2,d1           ; 1   (~swap)
                lsr.l   d2,d4           ; 0/1 (~swap)
                add.l   d3,d1           ; 1
                ror.l   d2,d0           ; 0/1 (=swap) Reorder bd
                add.l   d4,d1           ; 1   = Most significant longword.

;                movem.l (sp)+,d2-d5     ; 4
                move.l (sp)+,d2
                move.l (sp)+,d3
                move.l (sp)+,d4
                move.l (sp)+,d5
                rts                     ; 7
                                        ; 27 (min) => 30 (max)
                                        ; -----
                                        ; TOTAL : 36 => 55 cycles.

        CNOP 0,8

.return0        clr.l   d0              ; 1/8
                clr.l   d1              ; 0/1
;                movem.l (sp)+,d4/d5     ; 2
                move.l (sp)+,d4
                move.l (sp)+,d5
                rts                     ; 7
                                        ; 10 -> 18


*==============================================================================
* a (32) × b (32) = c (64) unsigned)
* d0       d1       d0:d1
*
* timings :
*      a×b=0 : 13 (min) -> 29 (max)
*   a>0, b>0 : 41 (min) -> 82 (max)
*   a>0, b<0 : 45 (min) -> 88 (max)
*   a<0, b>0 : 45 (min) -> 88 (max)
*   a<0, b<0 : 46 (min) -> 90 (max)

        CNOP 0,8

SMult64 ;        movem.l d5/d6,-(sp)     ; 2
                move.l  d6,-(sp)
                move.l  d5,-(sp)

                move.l  d0,d6           ; 1
                beq.s   .return0

                tst.l   d1              ; 1/8
                beq.s   .return0

;                movem.l d2-d4,-(sp)     ; 4/11
                move.l  d4,-(sp)
                move.l  d3,-(sp)
                move.l  d2,-(sp)
                eor.l   d1,d6           ; 1    Get result's sign
                move.l  d0,d2           ; 0/1
                bpl.s   .pos0           ; ---
                                        ; 9 (min) => 24 (max)

                neg.l   d2              ; 1/8
                neg.l   d0              ; 1

.pos0           move.l  d1,d4           ; 0/1  (or 1/8 when branch was taken)
                bpl.s   .pos1           ; ---
                                        ; b>0 : 1 (min) => 8 (max)
                                        ; b<0 : 2 (min) => 10 (max)

                neg.l   d4              ; 1/8
                neg.l   d1              ; 1

.pos1           moveq   #16,d5          ; 0/1  (or 1/8 when branch was taken)
                move.l  d0,d3           ; 1
                ror.l   d5,d4           ; 0/1
                ror.l   d5,d3           ; 1
                                        ; ---
                                        ; a>0 : 3 (min) => 11 (max)
                                        ; a<0 : 4 (min) => 13 (max)

                ; d0.w = Factor1_l = d2.w       * [(a<<16)+b] × [(c<<16)+d] = 
                ; d3.w = Factor1_h              * ac<<32 + (ad+bc)<<16 + bd
                ; d1.w = Factor2_l
                ; d4.w = Factor2_h

                mulu.w  d1,d0           ; 2   Factor2_l × Factor1_l = bd
                mulu.w  d3,d1           ; 2   Factor1_h × Factor2_l = ad
                mulu.w  d4,d2           ; 2   Factor2_h × Factor1_l = bc
                mulu.w  d4,d3           ; 2   Factor2_h × Factor1_h = ac

                ror.l   d5,d0           ; 1
                clr.l   d4              ; 0/1
                add.w   d1,d0           ; 1   Add ad to bd's most significant word
                addx.l  d4,d3           ; 1   Add the potential carry to ac
                add.w   d2,d0           ; 1   Add bc to bd's most significant word
                addx.l  d4,d3           ; 1   Add the potential carry to ac

                lsr.l   d5,d1           ; 1   (~swap)
                lsr.l   d5,d2           ; 0/1 (~swap)
                add.l   d3,d1           ; 1
                ror.l   d5,d0           ; 0/1 (=swap) Reorder bd
                add.l   d2,d1           ; 1   = Most significant longword.
                                        ; ----
                                        ; 16 (min) => 19 (max)

                tst.l   d6              ; 0/1
                bpl.s   .exit           ; ----
                                        ; 0 (min) => 1 (max)

                not.l   d0              ; 1/8
                not.l   d1              ; 1
                addq.l  #1,d0           ; 0/1
                addx.l  d4,d1           ; 1
                                        ; ----
                                        ; 3 (min) => 11 (max)

.exit ;          movem.l (sp)+,d2-d6     ; 5 (or 5/12 if bpl was taken)
                move.l (sp)+,d2
                move.l (sp)+,d3
                move.l (sp)+,d4
                move.l (sp)+,d5
                move.l (sp)+,d6

                rts                     ; 7
                                        ; ----
                                        ; a×b<0 : 12 (min) => 12 (max)
                                        ; a×b>0 : 12 (min) => 19 (max)

        CNOP 0,8

.return0        clr.l   d0              ; 1/8
                clr.l   d1              ; 0/1
;                movem.l (sp)+,d5/d6     ; 2
                move.l (sp)+,d5
                move.l (sp)+,d6
                rts                     ; 7
                                        ; ----
                                        ; 10 (min) => 18 (max)


        ; Name of the MsgPort we check to see if we have
        ; already patched these functions.

PortName:       dc.b    "PatchMult64_checkport",0

        CNOP 0,4                        ; Ensure that the code's length is an
Patch_End:                              ; even multiple of 4.
