                ORG     $0
                DC.L    $8000           stack pointer value after a reset
                DC.L    START           program counter value after a reset

START:          MOVE.L  #1,-(SP)        put 1 into arg. frame for F
                MOVE.L  #2,-(SP)        put 2 into arg. frame for F
                MOVE.L  #20,-(SP)       put 20 into arg. frame for F
                LEA.L   $0,A6           initialize frame pointer
                                        * (there is no higher arg. frame yet)
                JSR     F               call F( 1, 2, 20)
                MOVE.L  (SP)+,D0        put result into D0
                BREAK


********************************************************************************
*
* function: (SP1) F( (SP1), (SP2), (SP3))
*
* description:
*   Expects an argument frame with three arguments on the stack.
*   The register A6 should contain the frame pointer of the actual environment.
*
* registers affected: none
*
                                                                                
F:              LINK    A6,#0           store pointer to arg. frame in A6
                MOVEM.L D0-D2,-(SP)     save registers
                MOVE.L  16(A6),D0       fetch u from actual arg. frame
                MOVE.L  12(A6),D1       fetch v from actual arg. frame
                MOVE.L  8(A6),D2        fetch n from actual arg. frame

                SUBI.L  #1,D2           n = n - 1
                MOVE.L  D1,-(SP)        put v into arg. frame for G
                MOVE.L  D0,-(SP)        put u into arg. frame for G
                MOVE.L  D2,-(SP)        put n into arg. frame for G
                                        * no frame pointer adjustment needed
                JSR     G               call G( v, u, n)
                MOVE.L  (SP)+,D0        put result into D0
                MOVE.L  D0,16(A6)       write result into arg. frame (1st entry)

                MOVEM.L (SP)+,D0-D2     restore registers
                UNLK    A6              restore A6
                MOVE.L  (SP),8(SP)      kill last two entries of arg. frame:
                ADDQ.L  #8,SP             move return address, adjust SP
                RTS


********************************************************************************
*
* function: (SP1) G( (SP1), (SP2), (SP3))
*
* description:
*   Expects an argument frame with three arguments on the stack.
*   The register A6 should contain the frame pointer of the actual environment.
*
* registers affected: none
*
                                                                                
G:              LINK    A6,#0           store pointer to arg. frame in A6
                MOVEM.L D0-D4,-(SP)     save registers
                MOVE.L  16(A6),D0       fetch w from actual arg. frame
                MOVE.L  12(A6),D1       fetch z from actual arg. frame
                MOVE.L  8(A6),D2        fetch n from actual arg. frame
                MOVEA.L (A6),A0         fetch pointer to arg. frame of F
                MOVE.L  16(A0),D3       fetch u from arg. frame of F
                MOVE.L  12(A0),D4       fetch v from arg. frame of F

                CMPI.L  #0,D2           (n == 0) ?
                BLE     G_TAIL
                SUBI.L  #1,D2           n = n - 1
                CMP.L   D3,D0           (w > u) ?
                BGT     G_G

G_F:            ADDI.L  #1,D0           w = w + 1
                MOVE.L  A6,-(SP)        save A6
                MOVE.L  D4,-(SP)        put v into arg. frame for F
                MOVE.L  D0,-(SP)        put w into arg. frame for F
                MOVE.L  D2,-(SP)        put n into arg. frame for F
                MOVEA.L (A6),A6         adjust frame pointer for F
                MOVEA.L (A6),A6         adjust frame pointer for F
                JSR     F               call F( v, w, n)
                MOVE.L  (SP)+,D0        res = F( ...)
                MOVE.L  (SP)+,A6        restore A6
                JMP     G_END

G_G:            SUBI.L  #1,D3           u = u - 1
                MOVE.L  A6,-(SP)        save A6
                MOVE.L  D3,-(SP)        put u into arg. frame for G
                MOVE.L  D1,-(SP)        put z into arg. frame for G
                MOVE.L  D2,-(SP)        put n into arg. frame for G
                MOVEA.L (A6),A6         adjust frame pointer for G
                JSR     G               call G( u, z, n)
                MOVE.L  (SP)+,D0        res = G( ...)
                MOVE.L  (SP)+,A6        restore A6
                JMP     G_END

G_TAIL:         ADD.L   D1,D0           res = w + z

G_END:          MOVE.L  D0,16(A6)       write result into arg. frame (1st entry)
                MOVEM.L (SP)+,D0-D4     restore registers
                UNLK    A6              restore A6
                MOVE.L  (SP),8(SP)      kill last two entries of arg. frame:
                ADDQ.L  #8,SP             move return address, adjust SP
                RTS


********************************************************************************


END
