****************************************************************************
*
*    $RCSfile: OberonSysDIVMOD.asm $
* Description: Runtime support for the Oberon-A compiler
*
*  Created by: fjc (Frank Copeland)
*   $Revision: 1.2 $
*     $Author: fjc $
*       $Date: 1994/05/12 20:31:15 $
*
* Copyright © 1994, Frank Copeland.
* This file is part of the Oberon-A Library.
* See Oberon-A.doc for conditions of use and distribution.
*
* Log entries are at the end of the file.
*
****************************************************************************
*
* This file contains the MC68000 source code for part of the runtime
* support library of the Oberon-A compiler.  It contains the code to
* perform division and modulus operations on 32-bit signed integers
* (LONGINTs).
*
* Other parts of the runtime system may be found in the other files in
* this directory.  The object files resulting from assembling these
* files are concatenated to create OberonSys.lib.
*
* This code is by definition *not* re-entrant and is not suitable for
* creating shared-code libraries.
*
* Acknowledgements
* ----------------
*
* The 32-bit multiply and divide procedures are from the runtime
* library of Patrick Quaid's PCQ freeware Pascal compiler, which in
* turn came from the runtime library of Sozobon C.
*
**********************************************************************

;---------------------------------------------------------------------
;    Program unit hunk name

     TTL OberonSys

;---------------------------------------------------------------------
;    Imports

     INCLUDE   "OberonSys.i"

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

**********
* lmath.s
**********
* Copyright (c) 1988 by Sozobon, Limited.  Author: Johann Ruegg
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
*    of using this software, even if they result from defects in it.
*

*       For PCQ Pascal:
*            These are the 32-bit math functions from Sozobon-C,
*       as noted above.  I changed the names of the routines to
*       be more similar to the rest of my library, and handle the
*       divide by zero condition differently.  Other than that I
*       haven't changed the code a bit.

*       For Oberon-A:
*            I have changed the names (again) and modified the
*       routines to accept parameters passed in registers instead of
*       on the stack, in keeping with the conventions I use in the
*       rest of the compiler.

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

     ;----------------------------------------------------------------
     ; PROCEDURE OberonSys_DIV
     ;   l1 {D0} : LONGINT;
     ;   l2 {D1} : LONGINT)
     ; : LONGINT;
     ;
     ; Calculates l1 DIV l2, returning the result in D0.
     ;----------------------------------------------------------------

     SECTION OberonSys,CODE

     XDEF      OberonSys_DIV

OberonSys_DIV:

        movem.l d2-d5,-(a7)     ; save registers
        tst.l   d0
        smi     d4
        bpl     ld1
        neg.l   d0
ld1:
        tst.l   d1
        smi     d5
        bpl     ld2
        neg.l   d1
ld2:
        bsr     i_ldiv          /* d0 = d0/d1, d1 = d0%d1 */
        cmp.b   d4,d5
        beq     ld3
        neg.l   d0
ld3:
;        tst.b   d4
;        beq     ld4
;        neg.l   d1
;ld4:
        movem.l (a7)+,d2-d5
        rts

;---------------------------------------------------------------------

     ;----------------------------------------------------------------
     ; PROCEDURE OberonSys_MOD
     ;   l1 {D0} : LONGINT;
     ;   l2 {D1} : LONGINT)
     ; : LONGINT;
     ;
     ; Calculates l1 MOD l2, returning the result in D0.
     ;----------------------------------------------------------------

     SECTION OberonSys,CODE

     XDEF      OberonSys_MOD

OberonSys_MOD:

;        movem.l d2-d5,-(a7)     ; save registers
        movem.l d2-d4,-(a7)     ; save registers
        tst.l   d0
        smi     d4
        bpl     lmd1
        neg.l   d0
lmd1:
;        tst.l   d1
;        smi     d5
;        bpl     lmd2
;        neg.l   d1
;lmd2:
        bsr     i_ldiv          /* d0 = d0/d1, d1 = d0%d1 */
;        cmp.b   d4,d5
;        beq     lmd3
;        neg.l   d0
;lmd3:
        tst.b   d4
        beq     lmd4
        neg.l   d1
lmd4:
        move.l  d1,d0
;        movem.l (a7)+,d2-d5
        movem.l (a7)+,d2-d4
        rts

;---------------------------------------------------------------------

     SECTION OberonSys,CODE

     XREF OberonSys_CLEANUP

*A in d0, B in d1, return A/B in d0, A%B in d1
i_ldiv:
        tst.l   d1
        bne.s   nz1

*       divide by zero
        moveq.l #OS_ZeroDiv,D0      ;     HALT (ZeroDiv)
        bra     OberonSys_CLEANUP
nz1:
        cmp.l   d1,d0
        bhi     norm
        beq     is1
*       A<B, so ret 0, rem A
        move.l  d0,d1
        clr.l   d0
        rts
*       A==B, so ret 1, rem 0
is1:
        moveq.l #1,d0
        clr.l   d1
        rts
*       A>B and B is not 0
norm:
        cmp.l   #1,d1
        bne.s   not1
*       B==1, so ret A, rem 0
        clr.l   d1
        rts
*  check for A short (implies B short also)
not1:
        cmp.l   #$ffff,d0
        bhi     slow
*  A short and B short -- use 'divu'
        divu    d1,d0           /* d0 = REM:ANS */
        swap    d0              /* d0 = ANS:REM */
        clr.l   d1
        move.w  d0,d1           /* d1 = REM */
        clr.w   d0
        swap    d0
        rts
* check for B short
slow:
        cmp.l   #$ffff,d1
        bhi     slower
* A long and B short -- use special stuff from gnu
        move.l  d0,d2
        clr.w   d2
        swap    d2
        divu    d1,d2           /* d2 = REM:ANS of Ahi/B */
        clr.l   d3
        move.w  d2,d3           /* d3 = Ahi/B */
        swap    d3

        move.w  d0,d2           /* d2 = REM << 16 + Alo */
        divu    d1,d2           /* d2 = REM:ANS of stuff/B */

        move.l  d2,d1
        clr.w   d1
        swap    d1              /* d1 = REM */

        clr.l   d0
        move.w  d2,d0
        add.l   d3,d0           /* d0 = ANS */
        rts
*       A>B, B > 1
slower:
        move.l  #1,d2
        clr.l   d3
moreadj:
        cmp.l   d0,d1
        bhi.s   adj
        add.l   d2,d2
        add.l   d1,d1
        bpl     moreadj
* we shifted B until its >A or sign bit set
* we shifted #1 (d2) along with it
adj:
        cmp.l   d0,d1
        bhi.s   ltuns
        or.l    d2,d3
        sub.l   d1,d0
ltuns:
        lsr.l   #1,d1
        lsr.l   #1,d2
        bne     adj
* d3=answer, d0=rem
        move.l  d0,d1
        move.l  d3,d0
        rts

;---------------------------------------------------------------------

     END  ; OberonSys

**********************************************************************
*
* $Log: OberonSysDIVMOD.asm $
* Revision 1.2  1994/05/12  20:31:15  fjc
* - Prepared for release
*
* Revision 1.1  1994/01/15  18:31:52  fjc
* Start of revision control
*
* (12 Jan 1994) Modified to assemble with PhxAss instead of A68K
* ( 9 Jul 1993) Changed return code to OS_ZeroDiv.
* (29 May 1993) Split OberonSys.asm into several files to create
*               OberonSys.lib.
*
**********************************************************************

