; float.h -- standard Hawk definitions for floating point ; language: SMAL32 assembly language, intended as an include file ; author: Douglas W. Jones ; date: Dec 1, 2019 ; revised: Jan 2, 2024 -- made compatible with revised hawk.h ; revised: May 30, 2024 -- use =: for immutable names, _ in private names ; ; example: at the head of a smal 32 source file, include this line: ; | ; | USE "float.h" ; | ; --------------------- ; floating coprocessor registers FPLOW =: _COPROCREG_+1 FPA0 =: _COPROCREG_+2 FPA1 =: _COPROCREG_+3 ; --------------------- ; COSTAT bits and fields FPENAB =: #0002 FPSEL =: #0100 FPLONG =: #1000 FPSHORT =: #0000 FPENBIT =: 1 ; --------------------- ; floating point operations on COSET (add to dest FP register) FPINT =: 2 FPSQRT =: 4 FPADD =: 6 FPSUB =: 8 FPMUL =: 10 FPDIV =: 12 ; --------------------- ; floating point operations on COGET (add to src FP register) FPNEG =: 2 FPABS =: 4 ; --------------------- ; floating point operations in Hawk monitor EXT FTOI ; float to int conversion ; takes R3 = f, floating point number ; wipes out R4-5 ; uses no stack ; returns R3 = i, the truncated integer equivalent ; R3 = #80000000 is used when f is too big ; C equivalent: i = (int) f ; --------------------- ; support macros for single floating point conversions ; convention: all internal names are of form _FPxxxx_ ; intent: None of the following macros should be called ; from outside this package ; ; _FPVAL_ - the binary value, eventually the entire floating value ; accumulated as an integer, so 123.456 accumulates as 123456 ; normalized as 00.00000000...000 (30 bits left of the point) ; finally assembled into the number ; _FPSCL_ - decimal scale factor, zero unless fractional or exponent part ; _FPSGN_ - the sign, 0 = positive, -1 = negative ; _FPEXP_ - the exponent. ; parser: skip leading + or - sign, record sign MACRO _FPSIGN_ (a), (b) IF "a" = "-" _FPSGN_ = -1 _FPINT_ (b):1:1, (b):2:LEN(b)-1 ELSEIF "a" = "+" _FPINT_ (b):1:1, (b):2:LEN(b)-1 ELSE _FPINT_ (a), (b) ENDIF ENDMAC ; parser: recursively accumulate digits of integer part MACRO _FPINT_ (a), (b) IF ("a" < "0")!("a" > "9") _FPOINT_ (a), (b) ELSE _FPVAL_ = (((_FPVAL_ << 2) + _FPVAL_) << 1) + a IF _FPVAL_ < 0 ERROR "a'b" too many digits ELSE _FPINT_ (b):1:1, (b):2:LEN(b)-1 ENDIF ENDIF ENDMAC ; parser: if there's a point, get the fractional part MACRO _FPOINT_ (a), (b) IF "a" = "." _FPFRAC_ (b):1:1, (b):2:LEN(b)-1 ELSE _FPEXPE_ (a), (b) ENDIF ENDMAC ; parser: recursively accumulate the fractional part MACRO _FPFRAC_ (a), (b) IF ("a" < "0")!("a" > "9") _FPEXPE_ (a), (b) ELSE _FPVAL_ = (((_FPVAL_ << 2) + _FPVAL_) << 1) + a _FPSCL_ = _FPSCL_ - 1; IF _FPVAL_ < 0 ERROR "a'b" too many digits ELSE _FPFRAC_ (b):1:1, (b):2:LEN(b)-1 ENDIF ENDIF ENDMAC ; parser: if there's an e or E, get the exponent MACRO _FPEXPE_ (a), (b) IF ("a" = "e")!("a" = "E") _FPEXPS_ (b):1:1, (b):2:LEN(b)-1 ELSEIF ~("a" = "") ERROR "a'b" extra characters in mantissa ENDIF ENDMAC ; parser: if theres a + or -, handle the exponent sign MACRO _FPEXPS_ (a), (b) _FPEXP_ = 0 IF "a" = "-" _FPEXPV_ (b):1:1, (b):2:LEN(b)-1 _FPSCL_ = _FPSCL_ - _FPEXP_ ELSEIF "a" = "+" _FPEXPV_ (b):1:1, (b):2:LEN(b)-1 _FPSCL_ = _FPSCL_ + _FPEXP_ ELSE _FPEXPV_ (a), (b) _FPSCL_ = _FPSCL_ + _FPEXP_ ENDIF ENDMAC ; parser: recursively accumulate the exponent value MACRO _FPEXPV_ (a), (b) IF ("a" < "0")!("a" > "9") IF ~("a" = "") ERROR "a'b" extra characters in exponent ENDIF ELSE _FPEXP_ = (((_FPEXP_ << 2) + _FPEXP_) << 1) + a _FPEXPV_ (b):1:1, (b):2:LEN(b)-1 ENDIF ENDMAC ; normalize FPVAL FPEXP (31 bit mantissa, 2's comp exponent) MACRO _FPNORM_ IF _FPVAL_ < #40000000 _FPVAL_ = _FPVAL_ << 1 _FPEXP_ = _FPEXP_ - 1 _FPNORM_ ENDIF ENDMAC ; recursively decrement SCALE to zero while multiplying FPVAL FPEXP by 10 ; this is tricky! *10 => FPVAL * 1.25, EXP + 3, since 8*1.25 = 10 ; all this is done post normalize, so a renormalize step is included. MACRO _FPSCDN_ _FPVAL_ = _FPVAL_ + (_FPVAL_ >>> 2) _FPSCL_ = _FPSCL_ - 1 _FPEXP_ = _FPEXP_ + 3 IF _FPVAL_ < 0 _FPVAL_ = _FPVAL_ >>> 1 _FPEXP_ = _FPEXP_ + 1 ENDIF IF _FPSCL_ > 0 _FPSCDN_ ENDIF ENDMAC ; recursively increment SCALE to zero while dividing FPVAL FPEXP by 10 ; this is tricky! /10 => FPVAL * 1.6, EXP - 4, since 1.6/16 = 0.1 ; all this is done post normalize, so a renormalize step is included. MACRO _FPSCUP_ _FPVAL_ = ((_FPVAL_ >>> 1) + _FPVAL_) _FPVAL_ = ((_FPVAL_ >>> 4) + _FPVAL_) _FPVAL_ = ((_FPVAL_ >>> 8) + _FPVAL_) _FPVAL_ = ((_FPVAL_ >>>16) + _FPVAL_) _FPSCL_ = _FPSCL_ + 1 _FPEXP_ = _FPEXP_ - 4 IF _FPVAL_ < 0 _FPVAL_ = _FPVAL_ >>> 1 _FPEXP_ = _FPEXP_ + 1 ENDIF IF _FPSCL_ < 0 _FPSCUP_ ENDIF ENDMAC ; recursively denormalize until exponent within bounds MACRO _FPDENO_ _FPVAL_ = _FPVAL_ >>> 1 _FPEXP_ = _FPEXP_ + 1 IF _FPEXP_ < -126 _FPDENO_ ENDIF ENDMAC ; --------------------- ; macro to convert text to single floating point ; _FPCONV_ s ;where s = [+|-]int[.frac][(e|E)[+|-]exp] ; converted value left in _FPVAL_ ; uses above utility macros ; no other code should use these utility macros ; this is tricky! Accumulates value (FPVAL, FPSCL, FPEXP) ; then normalizes 31-bit mantissa and rounds to 24 places and renormalizes ; then deals with out-of-range exponents MACRO _FPCONV_ s _FPVAL_ = 0 _FPSCL_ = 0 _FPSGN_ = 0 _FPSIGN_ (s):1:1, (s):2:LEN(s)-1 _FPEXP_ = 30 IF ~(_FPVAL_ = 0) _FPNORM_ IF _FPSCL_ > 0 _FPSCDN_ ELSEIF _FPSCL_ < 0 _FPSCUP_ ENDIF ENDIF _FPVAL_ = _FPVAL_ + #40 IF _FPVAL_ < 0 _FPVAL_ = _FPVAL_ >>> 1 _FPEXP_ = _FPEXP_ + 1 ENDIF _FPVAL_ = _FPVAL_ >>> 7 IF _FPEXP_ < -149 _FPVAL_ = 0 ELSEIF _FPEXP_ > 126 _FPEXP_ = 128 _FPVAL_ = #00400000 ENDIF IF (_FPEXP_ < -126) & ~(_FPVAL_ = 0) _FPDENO_ _FPEXP_ = -127 ENDIF IF ~(_FPVAL_ = 0) _FPVAL_ = _FPVAL_ & #7FFFFF _FPEXP_ = (_FPEXP_ + #7F) << 23 _FPSGN_ = _FPSGN_ << 31 _FPVAL_ = _FPSGN_ ! _FPEXP_ ! _FPVAL_ ENDIF ENDMAC ; --------------------- ; macro to assemble a single precision IEEE floating point constant ; F s ;see _FPCONV_ for constant format MACRO F s _FPCONV_ s W _FPVAL_ ENDMAC ; --------------------- ; macro to load a single precision IEEE floating point constant ; LIW r,s ;see _FPCONV_ for constant format MACRO LIF =r,s _FPCONV_ s LIW r,_FPVAL_ ENDMAC END