                ORG     $0
                DC.L    $8000           Stack pointer value after a reset
                DC.L    START           Program counter value after a reset

START:          MOVE.L  #$ffffffff,D0
                MOVE.L  #$ffffffff,D1
                JSR     MULU_L          call MULU_L( ...)
                BREAK
                MOVE.L  #6,D0
                JSR     FAC_L           call FAC_L( 6)
                BREAK
                MOVE.L  #9,D0
                JSR     FAC_L           call FAC_L( 9)
                BREAK
                MOVE.L  #12,D0
                JSR     FAC_L           call FAC_L( 12)
                BREAK
                MOVE.L  #13,D0
                JSR     FAC_L           call FAC_L( 13)
                BREAK


********************************************************************************
*
* function:   D0 FAC_L( D0)
*
* description:
*   computes the factorial of the number given in D0 and returns
*   the result in D0 as well. Returns 0, iff an overflow (wrt. to long format)
*   is detected.
*
* registers affected: D0-D5
*

FAC_L:          MOVE.L  #1,D1           initialize the accumulator D1
                CMPI    #0,D0           if ( n eq 0)
                BEQ     DONE_L          return( D1)
LOOP_L:         JSR     MULU_L          D2,D3 = MULU_L( D0, D1)
                CMPI.L  #0,D2           result still in long format?
                BNE     OVERFLOW
                MOVE.L  D3,D1           if so, move result into accu
                SUBI    #1,D0           decrement n
                BNE     LOOP_L          until ( n eq 0)
                
DONE_L:         MOVE.L  D1,D0           return the accu in D0
                RTS


********************************************************************************
*
* function:   D2,D3 MULU_L( D0, D1)
*
* description:
*   multiplies two unsigned long formats given in D0,D1. The result is returned
*   in D2,D3, which hold the higher and the lower long format of the result,
*   respectively.
*
* registers affected: D2-D5
*

*
* For reasons of convenience, the following notation will be used to denote
* the individual parts of the resulting double-long:
*
*                   |----||----||----||----|
*                   |    D2    ||    D3    |
*                   | r0 || r1 || r2 || r3 |
*    

MULU_L:         MOVE.L  D0,D4
                SWAP    D4              D4 = HW( D0)
                MOVE.L  D1,D5
                SWAP    D5              D5 = HW( D1)
                MOVE.L  D4,D2
                MULU    D5,D2           D2 = HW( D0) * HW( D1) => affects r0 r1
                MOVE.L  D1,D3
                MULU    D0,D3           D3 = LW( D0) * LW( D1) => affects r2 r3

                MULU    D1,D4           D4 = HW( D0) * LW( D1) => affects r1 r2
                MULU    D0,D5           D5 = LW( D0) * HW( D1) => affects r1 r2
                ADD.L   D5,D4
                BCC     NO_INC_HW       do we have a carry affecting r0?
                ADD.L   #$10000,D2      increment r0
NO_INC_HW:      SWAP    D4
                MOVE.L  D4,D5
                ANDI.L  #$FFFF,D4       D4 = $0000     HW(D4+D5) => r1
                ANDI.L  #$FFFF0000,D5   D5 = LW(D4+D5) $0000     => r2
                ADD.L   D5,D3           compute     r2 r3
                ADDX.L  D4,D2           compute     r0 r1
                RTS
