;;;-*- Mode:LISP; Package:NEW-MATH; Base:10.; Readtable:CL -*-

;**************************************************
;*  Floating point functions			  *
;**************************************************

;;WKF: This is needed so that defconstant will work.
;;       Defconstant is evaluated at run time thus causeing problems.
;(defun new-math:unboxed-constant (arg)
;  (hw:unboxed-constant arg))
;Above does not work.  Macro def for hw:unboxed-constant is in file compiler-support.lisp

(defconstant float-error-mask (new-math:unboxed-constant
				  (cl:logior (cl:ash 1. hw:$$fpu-exact-infinity)
					     (cl:ash 1. hw:$$fpu-overflow-inexact)
					     (cl:ash 1. hw:$$fpu-x-denormalized)
					     (cl:ash 1. hw:$$fpu-y-denormalized)
					     (cl:ash 1. hw:$$fpu-xy-denormalized)
					     (cl:ash 1. hw:$$fpu-zero-divide)
					     (cl:ash 1. hw:$$fpu-x-nan)
					     (cl:ash 1. hw:$$fpu-y-nan)
					     (cl:ash 1. hw:$$fpu-xy-nan)
					     (cl:ash 1. hw:$$fpu-invalid-operation))))

(defmacro fpu-status ()
  '(hw:field-extract (hw:read-processor-status)
		     hw:%%processor-status-floating-point-status))

(defconstant alu-status-equal   #x80000)
(defconstant alu-status-greater #x00000)
(defconstant alu-status-less    #x20000)

;**************************************************
;*  Weitek floating point chip initializer
;**************************************************

(defafun init-float ()
  (falu fpu-default-mode0 nop ignore ignore fpu-load-mode fpu-unload-high)
  (falu fpu-default-mode1 nop ignore ignore fpu-load-mode fpu-unload-high)
  (falu fpu-default-mode2 nop ignore ignore fpu-load-mode fpu-unload-high)
  (falu fpu-default-mode3 nop ignore ignore fpu-load-mode fpu-unload-high)
  (fmul fpu-default-mode0 nop ignore ignore fpu-load-mode fpu-unload-high)
  (fmul fpu-default-mode1 nop ignore ignore fpu-load-mode fpu-unload-high)
  (fmul fpu-default-mode2 nop ignore ignore fpu-load-mode fpu-unload-high)
  (fmul fpu-default-mode3 nop ignore ignore fpu-load-mode fpu-unload-high)
  (return gr:*nil* boxed-right))

;**************************************************
;*  Short precision
;**************************************************

(defconstant short-float-pointer (new-math:unboxed-constant (ash vinc:$$dtp-short-float 26.)))

(defconstant %%dpb-short (byte 26. 6.))

(defun add-short (xx yy)
  (let* ((x (hw:dpb-unboxed xx %%dpb-short gr:*all-zero*))
	 (y (hw:dpb-unboxed yy %%dpb-short gr:*all-zero*))
	 (tflag (hw:trap-off))
	 (result (hw:float-add-single x y))
	 (status (fpu-status)))
      (fixup-short result status tflag)))

(defun subtract-short (xx yy)
  (let* ((x (hw:dpb-unboxed xx %%dpb-short gr:*all-zero*))
	 (y (hw:dpb-unboxed yy %%dpb-short gr:*all-zero*))
	 (tflag (hw:trap-off))
	 (result (hw:float-subtract-single x y))
	 (status (fpu-status)))
      (fixup-short result status tflag)))

(defun multiply-short (xx yy)
  (let* ((x (hw:dpb-unboxed xx %%dpb-short gr:*all-zero*))
	 (y (hw:dpb-unboxed yy %%dpb-short gr:*all-zero*))
	 (tflag (hw:trap-off))
	 (result (hw:float-multiply-single x y))
	 (status (fpu-status)))
      (fixup-short result status tflag)))

(defun divide-short (xx yy)
  (let* ((x (hw:dpb-unboxed xx %%dpb-short gr:*all-zero*))
	 (y (hw:dpb-unboxed yy %%dpb-short gr:*all-zero*))
	 (tflag (hw:trap-off))
	 (result (hw:float-divide-single x y))
	 (status (fpu-status)))
      (fixup-short result status tflag)))

(defun fixup-short (result status tflag)
  (hw:write-memory-control						 ;traps on
    (hw:dpb-unboxed tflag (byte 1 31.) (hw:read-memory-control)))
  (if (hw:32logbitp status float-error-mask)				 ;test error status
      (li:error "Short float operation" status)
    (progn
      (setq result (hw:ldb-boxed result %%dpb-short short-float-pointer)) ;make short float
      (setq status (hw:read-alu-status))				  ;save Z bit
      (values
	result
	(hw:dpb (hw:ldb result (byte 1 25.) 0) (byte 1 17.) status)))))   ;insert N bit

(defun compare-short (xx yy)
  (let* ((x (hw:dpb-unboxed xx %%dpb-short gr:*all-zero*))
	 (y (hw:dpb-unboxed yy %%dpb-short gr:*all-zero*))
	 (tflag (hw:trap-off))
	 (result (hw:float-compare-single x y))
	 (status (fpu-status)))
    (hw:write-memory-control						 ;traps on
      (hw:dpb-unboxed tflag (byte 1 31.) (hw:read-memory-control)))
    (dispatch (byte 2 0) status
       (0 (values 0  alu-status-equal))
       (1 (values -1 alu-status-less))
       (2 (values 1 alu-status-greater))
       (3 (li:error "Short float compare" status)))))

(defun test-short (xx)
  (let* ((x (hw:dpb-unboxed xx %%dpb-short gr:*all-zero*))
	 (status (hw:read-alu-status)))
    (cond ((hw:32< x gr:*all-zero*) (values -1 status))
	  ((hw:32> x gr:*all-zero*) (values  1 status))
	  (t                         (values  0 status)))))

(defun negate-short (xx)
  (setf (hw:r0) (hw:dpb-unboxed xx %%dpb-short gr:*all-zero*))
  (let* ((status (hw:read-alu-status))
	 (result (hw:dpb-xor 1 (byte 1. 25.) xx)))
    (values result status)))

;**************************************************
;*  Single precision
;**************************************************

(defun add-single (xx yy)
  (let* ((x (array:%vm-read32 xx 1))
	 (y (array:%vm-read32 yy 1))
	 (tflag (hw:trap-off))
	 (result (hw:float-add-single x y))
	 (status (fpu-status)))
      (fixup-single result status tflag)))

(defun subtract-single (xx yy)
  (let* ((x (array:%vm-read32 xx 1))
	 (y (array:%vm-read32 yy 1))
	 (tflag (hw:trap-off))
	 (result (hw:float-subtract-single x y))
	 (status (fpu-status)))
      (fixup-single result status tflag)))

(defun multiply-single (xx yy)
  (let* ((x (array:%vm-read32 xx 1))
	 (y (array:%vm-read32 yy 1))
	 (tflag (hw:trap-off))
	 (result (hw:float-multiply-single x y))
	 (status (fpu-status)))
      (fixup-single result status tflag)))

(defun divide-single (xx yy)
  (let* ((x (array:%vm-read32 xx 1))
	 (y (array:%vm-read32 yy 1))
	 (tflag (hw:trap-off))
	 (result (hw:float-divide-single x y))
	 (status (fpu-status)))
      (fixup-single result status tflag)))

(defun fixup-single (result status tflag)
  (hw:write-memory-control						 ;traps on
    (hw:dpb-unboxed tflag (byte 1 31.) (hw:read-memory-control)))
  (if (hw:32logbitp status float-error-mask)				 ;test error status
      (li:error "Single float operation" status)
    (let ((ptr (cons:allocate-structure 1 1 vinc:$$dtp-single-float
					(cons:make-header vinc:$$dtp-unboxed-header 1))))
      (array:%vm-write32 ptr 1 result)
      (setf (hw:r0) result) ;update ALU status
      (setq status (hw:read-alu-status))				  ;save Z bit
      (values
	ptr
	(hw:dpb (hw:ldb result (byte 1 31.) 0) (byte 1 17.) status)))))   ;insert N bit

(defun compare-single (xx yy)
  (let* ((x (array:%vm-read32 xx 1))
	 (y (array:%vm-read32 yy 1))
	 (tflag (hw:trap-off))
	 (result (hw:float-compare-single x y))
	 (status (fpu-status)))
    (hw:write-memory-control						 ;traps on
      (hw:dpb-unboxed tflag (byte 1 31.) (hw:read-memory-control)))
    (dispatch (byte 2 0) status
       (0 (values 0  alu-status-equal))
       (1 (values -1 alu-status-less))
       (2 (values 1 alu-status-greater))
       (3 (li:error "Single float compare" status)))))

(defun test-single (xx)
  (let* ((x (array:%vm-read32 xx 1))
	 (status (hw:read-alu-status)))
    (cond ((hw:32< x gr:*all-zero*) (values -1 status))
	  ((hw:32> x gr:*all-zero*) (values  1 status))
	  (t                         (values  0 status)))))

(defun negate-single (xx)
  (let* ((x (array:%vm-read32 xx 1))
	 (ptr (cons:allocate-structure 1 1 vinc:$$dtp-single-float
				       (cons:make-header vinc:$$dtp-unboxed-header 1)))
	 (result (hw:dpb-xor 1 (byte 31. 0) x)))
    (let ((status (hw:read-alu-status)))
      (array:%vm-write32 ptr 1 result)
      (values ptr status))))

;**************************************************
;*  Double precision
;**************************************************

(defun add-double (xx yy)
  (let* ((x-lo (array:%vm-read32 xx 1))
	 (x-hi (array:%vm-read32 xx 2))
	 (y-lo (array:%vm-read32 yy 1))
	 (y-hi (array:%vm-read32 yy 2))
	 (tflag (hw:trap-off)))
    (multiple-value-bind (result-hi result-lo)
	(hw:float-add-double x-hi x-lo y-hi y-lo)
      (let ((status (fpu-status)))
	(fixup-double result-hi result-lo status tflag)))))

(defun subtract-double (xx yy)
  (let* ((x-lo (array:%vm-read32 xx 1))
	 (x-hi (array:%vm-read32 xx 2))
	 (y-lo (array:%vm-read32 yy 1))
	 (y-hi (array:%vm-read32 yy 2))
	 (tflag (hw:trap-off)))
    (multiple-value-bind (result-hi result-lo)
	(hw:float-subtract-double x-hi x-lo y-hi y-lo)
      (let ((status (fpu-status)))
	(fixup-double result-hi result-lo status tflag)))))

(defun multiply-double (xx yy)
  (let* ((x-lo (array:%vm-read32 xx 1))
	 (x-hi (array:%vm-read32 xx 2))
	 (y-lo (array:%vm-read32 yy 1))
	 (y-hi (array:%vm-read32 yy 2))
	 (tflag (hw:trap-off)))
    (multiple-value-bind (result-hi result-lo)
	(hw:float-multiply-double x-hi x-lo y-hi y-lo)
      (let ((status (fpu-status)))
	(fixup-double result-hi result-lo status tflag)))))

(defun divide-double (xx yy)
  (let* ((x-lo (array:%vm-read32 xx 1))
	 (x-hi (array:%vm-read32 xx 2))
	 (y-lo (array:%vm-read32 yy 1))
	 (y-hi (array:%vm-read32 yy 2))
	 (tflag (hw:trap-off)))
    (multiple-value-bind (result-hi result-lo)
	(hw:float-divide-double x-hi x-lo y-hi y-lo)
      (let ((status (fpu-status)))
	(fixup-double result-hi result-lo status tflag)))))

(defun fixup-double (result-hi result-lo status tflag)
  (hw:write-memory-control						 ;traps on
    (hw:dpb-unboxed tflag (byte 1 31.) (hw:read-memory-control)))
  (if (hw:32logbitp status float-error-mask)				 ;test error status
      (li:error "Double float operation" status)
    (let ((ptr (cons:allocate-structure 1 2 vinc:$$dtp-double-float
					(cons:make-header vinc:$$dtp-unboxed-header 2))))
      (array:%vm-write32 ptr 1 result-lo)
      (array:%vm-write32 ptr 2 result-hi)
      (setf (hw:r0) (hw:32logior result-hi result-lo)) ;update alu status
      (setq status (hw:read-alu-status))				  ;save Z bit
      (values
	ptr
	(hw:dpb (hw:ldb result-hi (byte 1 31.) 0) (byte 1 17.) status)))))   ;insert N bit

(defun compare-double (xx yy)
  (let* ((x-lo (array:%vm-read32 xx 1))
	 (x-hi (array:%vm-read32 xx 2))
	 (y-lo (array:%vm-read32 yy 1))
	 (y-hi (array:%vm-read32 yy 2))
	 (tflag (hw:trap-off)))
    (multiple-value-bind (result-hi result-lo)
	(hw:float-compare-double x-hi x-lo y-hi y-lo)
      (setf (hw:r0) result-hi) ;force the stupid compiler to emit code!
      (let ((status (fpu-status)))
	(hw:write-memory-control						 ;traps on
	  (hw:dpb-unboxed tflag (byte 1 31.) (hw:read-memory-control)))
	(dispatch (byte 2 0) status
		  (0 (values 0  alu-status-equal))
		  (1 (values -1 alu-status-less))
		  (2 (values 1 alu-status-greater))
		  (3 (li:error "Double float compare" status)))))))

(defun test-double (xx)
  (let* ((x-hi (array:%vm-read32 xx 1))
	 (x-lo (array:%vm-read32 xx 2)))
        (let* ((x-or (hw:32logior x-hi x-lo))
	       (status (hw:read-alu-status)))
      (cond ((hw:32= x-or gr:*all-zero*) (values 0  alu-status-equal))
	    ((hw:32logbitp 31. x-hi)     (values -1 alu-status-less))
	    (t                           (values 1  alu-status-greater))))))

(defun negate-double (xx)
  (let* ((x-lo (array:%vm-read32 xx 1))
	 (x-hi (hw:dpb-xor 1 (byte 1. 31.) (array:%vm-read32 xx 2)))
	 (x-or (hw:32logior x-hi x-lo))
	 (status (hw:read-alu-status))
	 (ptr (cons:allocate-structure 1 2 vinc:$$dtp-single-float
				       (cons:make-header vinc:$$dtp-unboxed-header 2))))
      (array:%vm-write32 ptr 1 x-lo)
      (array:%vm-write32 ptr 2 x-hi)
      (setq status (hw:dpb (hw:ldb x-hi (byte 1. 31.) 0) (byte 1. 19.) status))
      (values ptr status)))


;**************************************************
;*  Convert fix to short
;**************************************************

(defafun convert-fixnum-to-short (i)
  (alu sex-r a1 a0 a0 bw-24 unboxed dt-both-fixnum)
  (move a2 trap-off unboxed)
  (falu single-float nop ignore a1 fpu-load-x   fpu-unload-high unboxed)
  (falu single-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu single-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu single-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu single-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu single-float a3  ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (alu-field field-pass memory-control a2 memory-control (byte 1. 31.) unboxed)
  (movei a4 #.(ash vinc:$$dtp-short-float 26.) unboxed)
  (alu-field field-pass return a3 a4 (byte 26. -6.) boxed ch-return next-pc-return)
 )

;**************************************************
;*  Convert fix to single
;**************************************************

(defafun convert-fixnum-to-single (i)
  (alu sex-r a1 ignore a0 bw-24 unboxed dt-both-fixnum)
  (move a2 trap-off unboxed)
  (falu single-float nop ignore a1 fpu-load-x   fpu-unload-high unboxed)
  (falu single-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu single-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu single-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu single-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu single-float a3  ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (alu-field field-pass memory-control a2 memory-control (byte 1. 31.) unboxed)
  (tail-open-call (array:make-single-float 1) (o0 a3))
 )

;**************************************************
;*  Convert fix to double
;**************************************************

(defafun convert-fixnum-to-double (i)
  (alu sex-r a1 ignore a0 bw-24 unboxed)
  (move a2 trap-off unboxed)
  (falu double-float nop ignore a1 fpu-load-x   fpu-unload-high unboxed)
  (falu double-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu double-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu double-float nop ignore a1 fpu-load-nop fpu-unload-high unboxed)
  (falu double-float nop ignore a1 fpu-load-nop fpu-unload-low  unboxed)
  (falu double-float o0  ignore a1 fpu-load-nop fpu-unload-low  unboxed ch-tail-open)
  (falu double-float o1  ignore a1 fpu-load-nop fpu-unload-low  unboxed)
  (alu-field field-pass memory-control a2 memory-control (byte 1. 31.) unboxed)
  (tail-call (array:make-double-float 2) ())
 )

;**************************************************
;*  Convert short to single
;**************************************************

(defun convert-short-to-single (x)
  (array:make-single-float (hw:dpb-unboxed x (byte 26. 6.) gr:*all-zero*)))

;**************************************************
;*  Convert short to double
;**************************************************

(defafun convert-short-to-double (x)
  (alu-field field-extract-r a1 ignore a0 (byte 26. 6.) unboxed-md)
  (move a2 trap-off unboxed)
  (falu single-to-double nop a1 ignore fpu-load-x   fpu-unload-high unboxed)
  (falu single-to-double nop a1 ignore fpu-load-nop fpu-unload-high unboxed)
  (falu single-to-double nop a1 ignore fpu-load-nop fpu-unload-high unboxed)
  (falu single-to-double nop a1 ignore fpu-load-nop fpu-unload-high unboxed)
  (falu single-to-double nop a1 ignore fpu-load-nop fpu-unload-low  unboxed)
  (falu single-to-double o0  a1 ignore fpu-load-nop fpu-unload-low  unboxed ch-tail-open)
  (falu single-to-double o1  a1 ignore fpu-load-nop fpu-unload-low  unboxed)
  (alu-field field-pass memory-control a3 memory-control (byte 1. 31.) unboxed)
  (tail-call (array:make-double-float 2) ())
 )

;**************************************************
;*  Convert single to double
;**************************************************

(defafun convert-single-to-double (x)
  (alu r+1 vma-start-read ignore a0 unboxed-vma unboxed-md)
  (nop)
  (move a1 md unboxed)
  (move a2 trap-off unboxed)
  (falu single-to-double nop a1 ignore fpu-load-x   fpu-unload-high unboxed)
  (falu single-to-double nop a1 ignore fpu-load-nop fpu-unload-high unboxed)
  (falu single-to-double nop a1 ignore fpu-load-nop fpu-unload-high unboxed)
  (falu single-to-double nop a1 ignore fpu-load-nop fpu-unload-high unboxed)
  (falu single-to-double nop a1 ignore fpu-load-nop fpu-unload-low  unboxed)
  (falu single-to-double o0  a1 ignore fpu-load-nop fpu-unload-low  unboxed ch-tail-open)
  (falu single-to-double o1  a1 ignore fpu-load-nop fpu-unload-low  unboxed)
  (alu-field field-pass memory-control a3 memory-control (byte 1. 31.) unboxed)
  (tail-call (array:make-double-float 2) ())
 )

;**************************************************
;*  DECODE-FLOAT
;**************************************************
;;; DECODE-FLOAT dispatches to these depending on the type of float.
;;; We should return three values:
;;;    - a floating point number of the same format as our argument but
;;;      between zero and one (a zero exponent),
;;;    - an integer representing the exponent.
;;;    - a floating point 1.0 of the same format with the same sign as the argument.

;;; short floats are the top 26 bits of the single float representation
(defun decode-float-short (float)
  (let ((sign-value (cons:make-pointer $$dtp-short-float
				       (hw:dpb-aligned float hw:%%short-float-sign
						       (hw:dpb-unboxed hw:$$short-float-exponent-excess
										   hw:%%short-float-exponent 0))))
	(one-half (hw:dpb-unboxed (1- hw:$$short-float-exponent-excess)
					      hw:%%short-float-exponent 0)))
    (if (hw:field= float (hw:unboxed-constant 0) (byte 25. 0))	;is all but sign bit = zero
	(values (cons:make-pointer $$dtp-short-float (hw:unboxed-constant 0))
		0 sign-value)
      (values (cons:make-pointer $$dtp-short-float
				 (hw:dpb-aligned float hw:%%short-float-mantissa one-half))
	      (- (hw:ldb float hw:%%short-float-exponent 0) hw:$$short-float-exponent-excess)
	      sign-value) )))

(defun decode-float-single (float)
  (let* ((word (array::%vm-read32 float 1))
	 (sign-value (array:make-single-float		;deposit sign bit into representation of 1.0
		       (hw:dpb-aligned word hw:%%single-float-sign
				       (dpb hw:$$single-float-exponent-excess
								   hw:%%single-float-exponent 0))))
	 (one-half (dpb (1- hw:$$single-float-exponent-excess)
					       hw:%%single-float-exponent 0)))
    (if (hw:field= word (hw:unboxed-constant 0) (byte 31. 0))	;is it zero?  (ignoring sign bit).
	(values (array:make-single-float (hw:unboxed-constant 0))
		0 sign-value)
      (values (array:make-single-float (hw:dpb-aligned word hw:%%single-float-mantissa one-half))
	      (- (hw:ldb word hw:%%single-float-exponent 0) hw:$$single-float-exponent-excess)
	      sign-value))))

;;; this still needs to be hacked to use the new byte specifiers
;(defun decode-float-double (float)
;  (let* ((word1 (array::%vm-read32 float 1))
;	 (word2 (array::%vm-read32 float 2))
;	 (one-half2 (dpb (1- hw:$$double-float-exponent-excess)
;			(byte-in-byte hw:%%double-float-exponent (byte 32. 32.))
;			0))
;;	 (one-half2 (hw:unboxed-constant #x3fe00000))
;	 (sign-value (array:make-double-float (hw:dpb-aligned word2
;							      (byte-in-byte hw:%%double-float-sign (byte 32. 32.))
;							      (hw:unboxed-constant #x3ff00000))
;					      (hw:unboxed-constant #x0))))
;    (if (and (hw:32= word1 (hw:unboxed-constant 0))
;	     (hw:field= word2 (hw:unboxed-constant 0)
;			(byte-in-byte (byte-union hw:double-float-exponent
;						  hw:double-float-mantissa)
;				      (byte 32. 32.))))	;is it zero?  (ignoring sign bit).
;	(values (array:make-double-float (hw:unboxed-constant 0)
;				   (hw:unboxed-constant 0))
;		0 sign-value)
;      (values (array:make-double-float (hw:dpb-aligned word2 (byte 20. 0) one-half2) word1)
;	      (- (hw:ldb word2 (byte-in-byte hw:%%double-float-exponent (byte 32. 32.)) 0)
;		 hw:$$double-float-exponent-excess)
;	      sign-value))))

(defun DECODE-FLOAT (float)
  (prims:dispatch vinc::%%data-type float
     ($$dtp-short-float     (decode-float-short float))
     ($$dtp-single-float    (decode-float-single float))
     ($$dtp-double-float    (decode-float-double float))
     (t (li:error "~d is not a floating point number" float))))

;**************************************************
;*  INTEGER-DECODE-FLOAT
;**************************************************
;;; These are similar to the DECODE-FLOAT functions except
;;; that the first value is an integer which represents the
;;; scaled mantissa.
(defun integer-decode-float-short (float)
  (let ((sign-value (cons:make-pointer $$dtp-short-float
				       (hw:dpb-aligned float hw:%%short-float-sign
						       (hw:dpb-unboxed hw:$$short-float-exponent-excess
								       hw:%%short-float-exponent 0)))))
    (if (hw:field= float (hw:unboxed-constant 0) (byte 25. 0))	;is it zero
	(values 0 0 sign-value)
      (values (hw:ldb float hw:%%short-float-mantissa
		      (hw:dpb-unboxed 1 (byte 1 (byte-size hw:%%short-float-mantissa))
				      (hw:unboxed-constant 0)))	;zero plus hidden bit
	      (- (hw:ldb float hw:%%short-float-exponent 0)
		 hw:$$short-float-exponent-excess (byte-size hw:%%short-float-mantissa))
	      sign-value) )))

(defun integer-decode-float-single (float)
  (let* ((word (array::%vm-read32 float 1))
	 (sign-value (array:make-single-float	;deposit sign bit into representation of 1.0
		       (hw:dpb-aligned word hw:%%single-float-sign
				       (hw:dpb-unboxed hw:$$single-float-exponent-excess
						       hw:%%single-float-exponent 0)))))
    (if (hw:field= word (hw:unboxed-constant 0) (byte 31. 0))	;is it zero?  (ignoring sign bit).
	(values 0 0 sign-value)
      (let ((bignum (allocate-bignum 1)))
	(array::%vm-write32 bignum 1
			    (hw:dpb-aligned word hw:%%single-float-mantissa
					    (hw:dpb-unboxed 1 (byte 1 (byte-size hw:%%single-float-mantissa))
							    (hw:unboxed-constant 0))))
	(values (shrink-bignum-structure bignum)
		(- (hw:ldb word hw:%%single-float-exponent 0)
		   hw:$$single-float-exponent-excess (byte-size hw:%%single-float-mantissa))
		sign-value)))))

;;; this still needs to be hacked to use the new byte specifiers
;(defun integer-decode-float-double (float)
;  (let* ((word1 (array::%vm-read32 float 1))
;	 (word2 (array::%vm-read32 float 2))
;	 (sign-value (array:make-double-float (hw:dpb-aligned word2
;							      (byte-in-byte hw:%%double-float-sign (byte 32. 32.))
;							      (hw:unboxed-constant #x3ff00000))
;					      (hw:unboxed-constant #x0))))
;    (if (and (hw:32= word1 (hw:unboxed-constant 0))
;	     (hw:field= word2 (hw:unboxed-constant 0)
;			(byte-in-byte (byte-union hw:double-float-exponent
;						  hw:double-float-mantissa)
;				      (byte 32. 32.))))	;is it zero?  (ignoring sign bit).
;	(values (array:make-double-float (hw:unboxed-constant 0)	;double float zero
;					 (hw:unboxed-constant 0))
;		0 sign-value)
;      (let ((bignum (allocate-bignum 2)))
;	(array::%vm-write32 bignum 1 word1)
;	(array::%vm-write32 bignum 2
;			    (HW:DPB-ALIGNED WORD2 (BYTE 20. 0)
;					    (hw:unboxed-constant #x80000)))
;	(values (shrink-bignum-structure bignum)
;		(- (HW:LDB WORD2 (byte-in-byte hw:%%double-float-exponent (byte 32. 32.)) 0)
;		   hw:$$double-float-exponent-excess
;		   (byte-size hw:%%double-float-mantissa))
;		sign-value) ))))

(defun INTEGER-DECODE-FLOAT (float)
  (prims:dispatch vinc::%%data-type float
     ($$dtp-short-float     (integer-decode-float-short float))
     ($$dtp-single-float    (integer-decode-float-single float))
     ($$dtp-double-float    (integer-decode-float-double float))
     (t (li:error "~d is not a floating point number" float))))


;**************************************************
;*  things to TRUNCATE floats
;**************************************************

;(defun truncate-fix-sign (quotient remainder sign)
;  (if (< sign 0)
;      (values (- quotient) (- remainder))
;    (values quotient remainder)))

;(defun truncate-short (float)
;  (multiple-value-bind (mantissa exponent sign)
;      (integer-decode-float-short float)
;    (flet ((haulong (n)
;	     (if (zerop n) 0 (- 32. (hw:32-prioritize n)))) )
;      (cond ((>= exponent 0)
;	     ;all bits are integer, none are fraction:
;	     (truncate-fix-sign (ash mantissa exponent) 0 sign))
;	    ((> exponent (- (1+ (byte-size hw:%%short-float-mantissa))))
;	     ;;; remember that with the hidden bit, the mantissa is one bit wider than the field it is stored in.
;	     ;;; Some bits are integer, some are fraction.  Exponent is enough to shift the binary point
;	     ;;; somewhere into the mantissa but not so big as to move it beyond the left edge.
;	     (let* ((frac-int		 (hw:ldb mantissa (byte (- exponent) 0) (hw:unboxed-constant 0)))
;		    (significant-bits	 (haulong frac-int))
;		    (mantissa-byte-width (1- significant-bits))
;		    (mantissa-byte-position (- (byte-size hw:%%short-float-mantissa)
;					       mantissa-byte-width))
;		    (new-expt (+ exponent mantissa-byte-width))
;		    (new-mant (hw:dpb-unboxed frac-int
;					      (byte mantissa-byte-width mantissa-byte-position)
;					      (hw:unboxed-constant 0))))
;	       (truncate-fix-sign int-mantissa
;				  (cons:make-pointer $$dtp-short-float
;						     (hw:dpb-unboxed (+ new-expt hw:$$short-float-exponent-excess)
;								     hw:%%short-float-exponent new-mant))
;				  sign) ))
;	    (t ;;;all the bits are fraction so the argument is the remainder
;	     (values 0 float)) ))))

;(defun truncate-single (float)
;  (multiple-value-bind (mantissa exponent sign)
;      (integer-decode-float-single float)
;    (flet ((haulong (n) (if (zerop n) 0 (- 32. (hw:32-prioritize n)))) )
;      (cond ((>= exponent 0)
;	     ;;; all bits are integer, none are fraction:
;	     (truncate-fix-sign (ash mantissa exponent) 0 sign))
;	    ((> exponent (- (1+ (byte-size hw:%%single-float-mantissa))))
;	     ;;; remember that with the hidden bit, the mantissa is one bit wider than the field it is stored in.
;	     ;;; Some bits are integer, some are fraction.  Exponent is enough to shift the binary point
;	     ;;; somewhere into the mantissa but not so big as to move it beyond the left edge.
;	     (let* ((frac-int		 (hw:ldb mantissa (byte (- exponent) 0) (hw:unboxed-constant 0)))
;		    (significant-bits	 (haulong frac-int))
;		    (mantissa-byte-width (1- significant-bits))
;		    (mantissa-byte-position (- (byte-size hw:%%single-float-mantissa)
;					       mantissa-byte-width))
;		    (new-expt (+ exponent mantissa-byte-width))
;		    (new-mant (hw:dpb-unboxed frac-int
;					      (byte mantissa-byte-width mantissa-byte-position)
;					      (hw:unboxed-constant 0))))
;	       (truncate-fix-sign int-mantissa
;				  (array:make-single-float
;				    (hw:dpb-unboxed (+ new-expt hw:$$short-float-exponent-excess)
;						    hw:%%short-float-exponent new-mant))
;				  sign) ))
;	    (t ;;;all the bits are fraction so the argument is the remainder
;	     (values 0 float)) ))))

;;; this just has the "single" code lifted for now.  rememebr to fix this before usung
;(defun truncate-double (float)
;  (multiple-value-bind (mantissa exponent sign)
;      (integer-decode-float-double float)
;    (flet ((haulong (n) (if (zerop n) 0 (- 32. (hw:32-prioritize n)))) )
;      (cond ((>= exponent 0)
;	     ;;; all bits are integer, none are fraction:
;	     (truncate-fix-sign (ash mantissa exponent) 0 sign))
;	    ((> exponent (- (1+ (byte-size hw:%%single-float-mantissa))))
;	     ;;; remember that with the hidden bit, the mantissa is one bit wider than the field it is stored in.
;	     ;;; Some bits are integer, some are fraction.  Exponent is enough to shift the binary point
;	     ;;; somewhere into the mantissa but not so big as to move it beyond the left edge.
;	     (let* ((frac-int		 (hw:ldb mantissa (byte (- exponent) 0) (hw:unboxed-constant 0)))
;		    (significant-bits	 (haulong frac-int))
;		    (mantissa-byte-width (1- significant-bits))
;		    (mantissa-byte-position (- (byte-size hw:%%single-float-mantissa)
;					       mantissa-byte-width))
;		    (new-expt (+ exponent mantissa-byte-width))
;		    (new-mant (hw:dpb-unboxed frac-int
;					      (byte mantissa-byte-width mantissa-byte-position)
;					      (hw:unboxed-constant 0))))
;	       (truncate-fix-sign int-mantissa
;				  (array:make-single-float
;				    (hw:dpb-unboxed (+ new-expt hw:$$short-float-exponent-excess)
;						    hw:short-float-exponent new-mant))
;				  sign) ))
;	    (t ;;;all the bits are fraction so the argument is the remainder
;	     (values 0 float)) )))
;  )

