summaryrefslogblamecommitdiffstats
path: root/private/mvdm/softpc.new/base/ccpu386/div.c
blob: 773c2bde83f16fa3566d46286a2b0d9d29572cb3 (plain) (tree)






































































































































































                                                                         
/*[

div.c

LOCAL CHAR SccsID[]="@(#)div.c	1.8 02/12/95";

DIV CPU functions.
------------------

]*/


#include <insignia.h>

#include <host_def.h>
#include <xt.h>
#include <c_main.h>
#include <c_addr.h>
#include <c_bsic.h>
#include <c_prot.h>
#include <c_seg.h>
#include <c_stack.h>
#include <c_xcptn.h>
#include	<c_reg.h>
#include <div.h>
#include <c_div64.h>


/*
   =====================================================================
   EXTERNAL FUNCTIONS START HERE.
   =====================================================================
 */


/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Unsigned Divide.                                                   */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
DIV8
       	          
IFN1(
	IU32, op2	/* divisor operand */
    )


   {
   IU32 result;
   IU32 op1;

   if ( op2 == 0 )
      Int0();   /* Divide by Zero Exception */
   
   op1 = GET_AX();
   result = op1 / op2;		/* Do operation */

   if ( result & 0xff00 )
      Int0();   /* Result doesn't fit in destination */
   
   SET_AL(result);	/* Store Quotient */
   SET_AH(op1 % op2);	/* Store Remainder */

   /* 
    * PCBench attempts to distinguish between processors by checking for
    * the DIV8 instruction leaving all flags unchanged or clear. It is
    * important we behave through this test in the same way as the 'real'
    * 486 otherwise the app asks us to perform some unsupported ops.
    *
    * The real 486 has the following ('undefined') behaviour:
    *	CF set
    *   PF = pf_table[op2 - 1]
    *   AF = !( (op2 & 0xf) == 0 )
    *	ZF clear
    *	SF = (op2 <= 0x80)
    *   OF = some function of the actual division
    *
    * Given that the PCBench test is for a simple all-zero case, and that
    * implementing the above is a needless overhead on the assembler CPU,
    * we take the simplified form of ZF clear, CF set.
    */
#ifdef SET_UNDEFINED_DIV_FLAG
   SET_CF(1);
   SET_ZF(0);
   SET_SF(UNDEFINED_FLAG);
   SET_OF(UNDEFINED_FLAG);
   SET_PF(UNDEFINED_FLAG);
   SET_AF(UNDEFINED_FLAG);
#endif
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Unsigned Divide.                                                   */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
DIV16
       	          
IFN1(
	IU32, op2	/* divisor operand */
    )


   {
   IU32 result;
   IU32 op1;

   if ( op2 == 0 )
      Int0();   /* Divide by Zero Exception */
   
   op1 = (IU32)GET_DX() << 16 | GET_AX();
   result = op1 / op2;		/* Do operation */

   if ( result & 0xffff0000 )
      Int0();   /* Result doesn't fit in destination */
   
   SET_AX(result);	/* Store Quotient */
   SET_DX(op1 % op2);	/* Store Remainder */

   /* Set all undefined flag(s) */
#ifdef SET_UNDEFINED_DIV_FLAG
   SET_CF(1);		/* see DIV8 for flag choice reasoning */
   SET_ZF(0);
   SET_OF(UNDEFINED_FLAG);
   SET_SF(UNDEFINED_FLAG);
   SET_PF(UNDEFINED_FLAG);
   SET_AF(UNDEFINED_FLAG);
#endif
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Unsigned Divide.                                                   */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
DIV32
       	          
IFN1(
	IU32, op2	/* divisor operand */
    )


   {
   IU32 lr;   /* low result */
   IU32 hr;   /* high result */
   IU32 rem;  /* remainder */

   if ( op2 == 0 )
      Int0();   /* Divide by Zero Exception */
   
   hr = GET_EDX();
   lr = GET_EAX();
   divu64(&hr, &lr, op2, &rem);	/* Do operation */

   if ( hr )
      Int0();   /* Result doesn't fit in destination */
   
   SET_EAX(lr);	/* Store Quotient */
   SET_EDX(rem);	/* Store Remainder */

   /* Set all undefined flag(s) */
#ifdef SET_UNDEFINED_DIV_FLAG
   SET_CF(1);		/* see DIV8 for flag choice reasoning */
   SET_ZF(0);
   SET_OF(UNDEFINED_FLAG);
   SET_SF(UNDEFINED_FLAG);
   SET_PF(UNDEFINED_FLAG);
   SET_AF(UNDEFINED_FLAG);
#endif
   }