;;;-*- Mode:LISP; Package:NEW-MATH; Base:10; Readtable:CL -*- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum multiply ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun multiply-fixnum (x y) (hw::load-q-register x) (let* ((high-half (hw:signed-multiply-step y (hw:signed-multiply-step y (hw:signed-multiply-step y (hw:signed-multiply-step y (hw:signed-multiply-step y (hw:signed-multiply-step y (hw:signed-multiply-step y (hw:signed-multiply-step y (hw:signed-multiply-step y (hw:signed-multiply-step y (hw:signed-multiply-step y (hw:signed-multiply-first-step y 0))))))))))))) (low-half (hw::read-q-register-boxed)) (sign (hw::ldb low-half (byte 1. 31.) 0))) (if (zerop (hw:24+ high-half sign)) low-half ;; We overflowed, make a bignum (let ((biggy (allocate-bignum 2))) (hw:write-md-unboxed (hw:dpb-unboxed high-half (byte 8. 24.) low-half)) (hw:vma-start-write-no-gc-trap-unboxed (hw:32-1+ biggy)) (hw:write-md-unboxed (hw:32arithmetic-shift-down (hw:32-sign-extend high-half) 8.)) (hw:vma-start-write-no-gc-trap-unboxed (hw:32-2+ biggy)) (shrink-bignum-structure biggy))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum divide ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun divide-fixnum (dividend divisor) (if (zerop divisor) (trap::illop "Zero divide") (let* ((almost-remainder (hw:signed-divide-last1 divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-step divisor (hw:signed-divide-first-step divisor (hw:24-sign-fill (hw:load-q-register dividend)) )))))))))))))))))))))))))) (cruft (hw:signed-divide-last2 divisor almost-remainder)) (remainder (hw:remainder-correct divisor almost-remainder)) (quotient (hw:quotient-correct (hw:read-q-register-boxed)))) (if (not (hw:alu-status-logbitp hw:%%alu-status-overflow)) (let ((biggy (allocate-bignum 2))) (hw:write-md-unboxed (hw:unboxed-constant #x80000000)) (hw:vma-start-write-no-gc-trap-unboxed (hw:32-1+ biggy)) (hw:memory-wait) (hw:write-md-unboxed (hw:unboxed-constant 0)) (hw:vma-start-write-no-gc-trap-unboxed (hw:32-2+ biggy)) (values biggy remainder)) (values quotient remainder))))) (defun truncate-fixnum (dividend divisor) (divide-fixnum dividend divisor)) (defun floor-fixnum (dividend divisor) (multiple-value-bind (quotient remainder) (divide-fixnum dividend divisor) (if (and (minusp quotient) (not (zerop remainder))) (values (1- quotient) (+ remainder divisor)) (values quotient remainder)))) (defun ceiling-fixnum (dividend divisor) (multiple-value-bind (quotient status remainder) (divide-fixnum dividend divisor) (if (and (not (minusp quotient)) (not (zerop remainder))) (values (1+ quotient) (- remainder divisor)) (values quotient remainder)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum add that may overflow ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun add-fixnum (x y) (let* ((sum24 (hw:24+ x y)) (status (hw:read-alu-status))) (if (hw:32logbitp hw:%%alu-status-overflow status) (let ((biggy (allocate-bignum 1))) (hw:write-vma-unboxed (hw:32-1+ biggy)) (hw:md-start-write-no-gc-trap-unboxed (hw:32+ (hw:32-sign-extend x) (hw:32-sign-extend y))) (values biggy (hw:read-alu-status))) (values sum24 status)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum subtract that may overflow ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun subtract-fixnum (x y) (let* ((diff24 (hw:24- x y)) (status (hw:read-alu-status))) (if (hw:32logbitp hw:%%alu-status-overflow status) (let ((biggy (allocate-bignum 1))) (hw:write-vma-unboxed (hw:32-1+ biggy)) (hw:md-start-write-no-gc-trap-unboxed (hw:32- (hw:32-sign-extend x) (hw:32-sign-extend y))) (values biggy (hw:read-alu-status))) (values diff24 status)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum compare ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun compare-fixnum (x y) (values (hw:24- x y) (hw:read-alu-status))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum compare ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun test-fixnum (x) (values (hw:24- x 0) (hw:read-alu-status))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum negate that may overflow ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun negate-fixnum (x) (if (= x -8388608.) (let ((biggy (allocate-bignum 1))) (hw:write-vma-unboxed (hw:32-1+ biggy)) (hw:md-start-write-no-gc-trap-unboxed (hw:unboxed-constant #x800000)) (values biggy (hw:read-alu-status))) (values (- x) (hw:read-alu-status)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum field pass ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun field-pass-fixnum (x y byte-spec ldb-p) (multiple-value-bind (hard size position) (resolve-byte-spec byte-spec ldb-p) (if hard (field-pass-bignum (convert-fixnum-to-bignum x) (convert-fixnum-to-bignum y) byte-spec ldb-p) ;; (ALU FIELD-PASS ...) ;; does dpb if (byte-position byte-spec) is positive ;; does ldb if (byte-position byte-spec) is negative ;; pfc 5/25 (values (if ldb-p (hw:ldb x byte-spec y) (hw:dpb x byte-spec y)) (hw:read-alu-status))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Resolve byte specifier ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun resolve-byte-spec (bs ldb-p) (multiple-value-bind (size position) (if (hw:field= bs gr:*zero* vinc::%%data-type) ;fixnum --> short format byte spec (let ((fsize (hw:ldb bs (byte 5. 8.) 0))) (values (if (zerop fsize) 32. fsize) (hw:dpb-boxed vinc:$$dtp-fixnum vinc::%%data-type (hw:32arithmetic-shift-down (hw:dpb-unboxed bs (byte 8. 24.) gr:*all-zero*) 24.)))) (values (cons:car bs) (cons:cdr bs))) (when (< size 1) (trap:illop "Illegal size in byte specifier")) (when ldb-p (setq position (- position))) ; fixed --pfc 4/25 (if (or (and (<= position 0) ; big ldb's are hard (<= (- size position) 24.)) ; allowed to ldb from sign bit !! (and (not (minusp position)) ; big dpb's are hard (<= (+ position size) 23.))) ; not allowed to dpb into sign bit !! (values nil size position) ; not hard (values t size position)))) ; hard (defun byte-position (bs) (if (hw:field= bs gr:*zero* vinc::%%data-type) (hw:dpb-boxed gr:*zero* vinc::%%data-type (hw:32arithmetic-shift-down (hw:dpb-unboxed bs (byte 8. 24.) gr:*all-zero*) 24.)) (cons:cdr bs))) (defun byte-size (bs) (if (hw:field= bs gr:*zero* vinc::%%data-type) (let ((fsize (hw:ldb bs (byte 5. 8.) 0))) (if (zerop fsize) 32. fsize)) (cons:car bs))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum ash ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun ash-fixnum (i shift) (when (not (hw:field= shift gr:*zero* vinc::%%data-type)) (trap:illop "Bad shift to ash")) (let* ((big-i (hw:32-sign-extend i))) (if (minusp shift) (let ((x-shift (if (< shift -24.) -32. shift))) (values (hw:dpb-boxed (hw:32arithmetic-shift-down big-i x-shift) (byte 24. 0.) gr:*zero*) (hw:read-alu-status))) (let* ((raw-i (if (minusp i) (hw:ldb-not i (byte 24. 0.) 0) i)) (unused-bits (hw:dpb-boxed vinc:$$dtp-fixnum vinc::%%data-type (hw:24-prioritize raw-i)))) (if (>= shift unused-bits) (ash-bignum (convert-fixnum-to-bignum i) shift) (values (hw:dpb-boxed (hw:32logical-shift-up big-i shift) (byte 24. 0.) gr:*zero*) (hw:read-alu-status))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum logand ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun logand-fixnum (x y) (logand x y)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum logior ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun logior-fixnum (x y) (logior x y)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum logxor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun logxor-fixnum (x y) (logxor x y)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum logxnor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun logxnor-fixnum (x y) (logeqv x y)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Fixnum lognot ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun lognot-fixnum (x) (lognot x)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; For slightly large fixnums ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;********************************** ;;;* * ;;;* ALLOCATING STORAGE FOR BIGNUMS * ;;;* * ;;;********************************** (defun allocate-bignum (size) (if (or (<= size 0) (>= size #x040000)) (trap:illop "Bad size to allocate-bignum") (cons::allocate-structure 1 size $$dtp-bignum (hw:dpb-unboxed $$dtp-unboxed-header vinc::%%data-type size)))) ;;;********************************** ;;;* * ;;;* SHRINK BIGNUM STRUCTURE * ;;;* * ;;;********************************** (defun shrink-bignum-structure (bignum-ptr) (let* ((size (progn (hw:vma-start-read-vma-boxed-md-boxed bignum-ptr) (hw:ldb (hw:read-md) vinc::%%pointer (hw:unboxed-constant 0)))) (high-word (progn (hw:vma-start-read-no-transport-vma-unboxed-md-unboxed (hw:32+ size bignum-ptr)) (hw:read-md)))) (labels ((small-bignum (word) ;;Returns T if bignum word can fit in a fixnum (let ((high-bits (hw:ldb word (byte 9. 23.) 0))) (or (zerop high-bits) (= high-bits #b111111111)))) (reduce-bignum () (if (hw:32= size (hw:unboxed-constant 1)) (progn (hw:write-md-unboxed (hw:dpb-unboxed $$dtp-unboxed-header vinc::%%data-type size)) (hw:vma-start-write-no-gc-trap-unboxed bignum-ptr) (if (small-bignum word) (values (+ 0 (hw:ldb high-word vinc::%%fixnum-field 0)) (hw:read-alu-status)) (values bignum-ptr (hw:dpb (hw:ldb high-word (byte 1. 31.) 0) (byte 1. 17.) 0)))) (let ((next-word (progn (hw:vma-start-read-no-transport-vma-unboxed-md-unboxed (hw:32+ (hw:32- size (hw:unboxed-constant 1)) bignum-ptr)) (hw:read-md)))) (if (hw:32zerop (hw:32+ high-word (hw:ldb next-word (byte 1. 31.) (hw:unboxed-constant 0)))) (progn (hw:write-md-unboxed (hw:unboxed-constant 0)) (hw:vma-start-write-no-gc-trap-unboxed (hw:32+ size bignum-ptr)) (setq size (hw:32- size (hw:unboxed-constant 1))) (setq high-word next-word) (reduce-bignum)) (values bignum-ptr (hw:dpb (hw:ldb high-word (byte 1. 31.) 0) (byte 1. 17.) 0))))))) (reduce-bignum))))