;------------------------------------------------------------------
;                  16 bit fixpoint math rutines ver 1.0           ;
;                                                                 ;
; 16 bit fixpoint and 2's complement 16 bit fixpoint              ;
; math rutines by Dines Justesen Corp. 1996                       ;
;                                                                 ;
; Some rutines is based on work by or written by the following    ;
; people:                                                         ;
;   Magnus Hagander (e95_mha@e.kth.se)                            ;
;   Darryl Nester (nesterd@bluffton.edu)                          ;
;                                                                 ;
; You are allow to include the following rutines in your programs ;
; as long as you follow the rules stated below.                   ;
;                                                                 ;
; If you use any of the functions in one of your programs give me ;
; credit for my work. Some of the functions included was made by  ;
; others or based on some one elses work, they too should get the ;
; credit for their work. One way of doing this is by including    ;
; lines like the ones below in the documentation.                 ;
;                                                                 ;
; Fixpoint math by Dines Justesen (c958362@student.dtu.dk)        ;
; Some rutines by/based on work by Magnus Hagander                ;
;                                                                 ;
; You are NOT ALLOWED to distribute any modified versions of these;
; rutines, or only parts of the document.                         ;
;                                                                 ;
; The reason i decieded to release the source code for these      ;
; rutines was to help other people getting stared with more math  ;
; intensive programs. So  please don't just rip things off, either; 
; give methe credit or make your own rutines.                     ; 
;                                                                 ;
; This is the first version and some of the rutines are completly ;
; new,so there might by bugs in some rutines. The rutines to show ;
; numbers was written really fast so they a probably a bit slow.  ;
; If you find any bugs please report them to me. Any suggestion of;
; new rutines or improvements of the in the document are very     ;
; welcome, and i will include them in a future relase.            ;
;                                                                 ;
; Send comments and ideas to:                                     ;
;   Dines Justesen : c958362@student.dtu.dk or                    ;
;                    dines@MAILHOST.NET                           ;
;                    http://www.gbar.dtu.dk/~c958362/             ;
; Dines justesen april, 1996                                      ;
;------------------------------------------------------------------

#INCLUDE "TI-85.H"

RES = $80DF ; Used for temporary storage

.org 0
;------------------------------------------------------------------
;
; Program to test some of the fixpoint rutines
;
;------------------------------------------------------------------

.db "Fix Test",0
        ld a,4                  ; Clear LCD
        out (5),a
        ROM_CALL(CLEARLCD)      
        ld l,11111111b          ;Show a negative 2's complement number
        ld h,11111111b
        CALL_(ShowFix2)
        CALL_(Loop)
        ld bc,$0280             ;Multiply 2.5 and 16.125
        ld de,$1020
        CALL_(Mul16)
        ld h,c
        ld l,d
        CALL_(ShowFix2)
        CALL_(Loop)
        ld hl,1111110110000000b             ;add -2.5 and -3.25
        ld bc,1111110011000000b
        CALL_(Add162)
        CALL_(ShowFix2)
KeyLoop1:
	call GET_KEY
	cp $37
        ret z                   ; return if [EXIT] is pressed
        jr KeyLoop1

Loop:                             ; Label
        call GET_KEY              ; Call getkey
        cp 9                      ; Enter ?
        jr nz,Loop                ; No, loop
        ret

;------------------------------------------------------------------
;
; Below is the math rutines tested above
;
;------------------------------------------------------------------

;------------------------------------------------------------------
;
; Addition + Subtraction
;
; Both of these operations are buldt in the z80. Use sbc, add, and
; add.
;
;------------------------------------------------------------------

;------------------------------------------------------------------
;
; Add162
;
; Addition of 2  16 bit fixpoint 2's complement number
;
; Entry :  Hl = Op1 BC = Op2
; Exit  :  HL = Op1+Op2
;
;------------------------------------------------------------------

Add162:                 ;H bit 7 = x = B bit 7 check at res bit 7 = x
  bit 7,H               ;Check bit 7
  jr nz,First1          ;Jump if 1
  bit 7,B               ;Check bit 7
  jr nz,Zeroes          ;Jump if 0
AddIt:
  Add Hl,BC             ;Add  
  AND A                 ;Clear carry
  Ret                   ;Return
First1:
  bit 7,b               ;Check bit 7
  jr z,AddIt            ;If 0 then add
  Add HL,BC             ;Add
  Bit 7,H               ;Check bit 7
  Jr z,AddOv            ;If 0 then overflow !!
  AND A                 ;Clear carry
  Ret                   ;Return
Zeroes:
  Add Hl,BC             ;Add
  Bit 7,H               ;Check bit 7
  jr nz,AddOv           ;If 1 then overflow !!
  AND A                 ;Clear carry
  Ret                   ;Return
AddOv:
  Scf                   ;Set carry flag
  Ret                   ;Return

;------------------------------------------------------------------
;
; Sub162
;
; Subtraction of 2  16 bit fixpoint 2's complement number
;
; Entry :  Hl = Op1 DE = Op2
; Exit  :  Hl = Op1-Op2
;
;------------------------------------------------------------------

                        ; bit 7 = X = not bit 7 res=X
Sub16:                  ; (-x)-(y) = -z  (x)-(-y) = +z
  bit 7,h
  jr nz,SFirst1
  bit 7,d
  jr nz,PosRes
JustSub:
  And A                 ;Clear carry
  Sbc Hl,DE             ;Subtract
  And A                 ;Clear carry
  Ret                   ;Return
SFirst1:                
  bit 7,d
  jr nz,JustSub
  And A                 ;Clear carry
  Sbc Hl,De             ;Subtract
  bit 7,h               
  jr z,SOver
  And A                 ;Clear carry
  Ret                   ;Return
PosRes:                 
  And A
  Sbc Hl,De
  bit 7,h
  jr nz,SOver
  And A
  Ret
SOver:
  Scf                   ;Set carry
  Ret                   ;Return

;------------------------------------------------------------------
;
; Mul16
;
; Multiplication of two 16 bit numbers giving a 32 bit result.
; If fixpoint numbers are used then discard 8 LSB's if the 8 MSB's
; <>0 then the number is too big to stor as normal 16 bit fixpoint.
;
; Entry : BC = Mult1 DE= Mult2
; Exit  : BCDE = Mult1*Mult2 (B=MSB, E=LSB)
;         Destroys hl 
;
;------------------------------------------------------------------

Mul16:
  push af               ;Save regs
  push hl          
  ld hl,0               ;reset hl
  ld a,10h              ;counter = 16 bits
mulloop:
  add hl,hl             ;shift left temp result
  rl e                  ;move next bit to carry
  rl d
  jr nc,mulover         ;if bit=0 then next
  add hl,bc             ;else add multplcant to temp. result
  jr nc,mulover         ;if no overflow then continue
  inc de                ;else inc high 16 bits
mulover:
  dec a                 ;dec counter
  jr nz,mulloop         ;if all bits done
  ex de,hl              ;move low 16 bits of result to DE
  ex (sp),hl            ;put high 16 bits on stack
  pop bc                ;Bc = high 16 bits of result
  pop af                ;Restore AF
  ret 

;------------------------------------------------------------------
; Cmp16
;
; 16 bit Compare works for both normal fixpoint numbers and 2's comp.
; This rutine is from the book Z80 assembly language subrutines by
; Lance A. Leventhal.
;
; Entry : HL=Value1 De=Value2
; Exit  : if 2'scomplement is used then
;               zero=1 and sign=0 then Value1=Value2
;               zero=0 and sign=0 then Value1>Value2
;               zero=0 and sign=1 then Value1<Value2
;         if not 2's complement then use carry instead of sign.
;         hl and a are destroyed.         
;
;------------------------------------------------------------------

Cmp16:
  or a                  ;Clear carry
  sbc hl,de             ;Value1-Value2
  ret po                ;If no overflow occured
                        ;If overflow occured then signed is
                        ;changed on 2's complement
  ld a,h                ;Get 8 MSB
  rra                   ;Save carry from subtraction
  xor 01000000b         ;Complement sign bit
  scf                   ;ensure a non-zero result
  adc a,a               ;restore carry, complemented sign
                        ;zero flag=0
  ret
  

;------------------------------------------------------------------
;
; ShowFix2
;
; Shows the 16 bit 2's complement fixpoint number stored in hl on
; the display
;
; Uses ShowFix
;
;------------------------------------------------------------------

ShowFix2:
        bit 7,h         ;Check sign
        jr z,notneg     ;Jump if positive
        ld de,$FFFF     ;16 bit not
        ex de,hl
        sbc hl,de
        inc hl          ;add 1
        ld a,'-'        ;Display sign
        ROM_CALL(TX_CHARPUT)
notneg:
        CALL_(ShowFix)  ;Show number
        ret
;------------------------------------------------------------------
;
; ShowFix
;
; Shows the 16 bit fixpoint number stored in hl on the display
;
; Uses  : ShowInt and ShowFrac
;
;------------------------------------------------------------------

ShowFix:                
        push hl         ;Save number for later use
        ld a,h          ;Get integer part
        CALL_(ShowInt)  ;Show it
        ld a,'.'        ;Show decimal point
        ROM_CALL(TX_CHARPUT)
        pop hl          ;Restore number
        ld a,l          ;Get fraction
        CALL_(ShowFrac) ;Show it
        ret

;------------------------------------------------------------------
;
; ShowInt
;
; Displays integer part of a fixpoint number (8 MSB)
; This rutines is based on the rutine used in TEXAN by
; Magnus Hagander (e95_mha@e.kth.se), but has been
; changed a bit by me :-)
;
; Entry : A holds value to be printed
; Exit  : A HL and DE destroyed
;
;------------------------------------------------------------------

ShowInt:
        ld l,a          ;Store value in hl
        ld a,0
        ld h,a
        ld de,RES+3     ;Location of the end of the string
        ld (de),a       ;Make string 0 terminated
        dec de          ;point to last digit
        ld b,3          ;Number of digits
ConvLoop:
        call UNPACK_HL  ;Unpack on digit from hl
        cp 0
        add a,'0'       ;make it ascii
        ld (de),a       ;store it
        dec de          ;point to next digit
        djnz ConvLoop
        ld hl,RES       ;point to string
        ROM_CALL(D_ZT_STR) ;Display it
        ret

;------------------------------------------------------------------
;
; ShowFrac
;
; Displays the fraction part of a fixpoint number on screen.
;
; Entry : A holds value (lower 8 bits of a number)
; Exit  : All regs destroyed
; Uses  : RES and the most of the rutines below
;------------------------------------------------------------------

ShowFrac:
        CALL_(Frac2bcd)         ;Convert number to BCD array
        ld hl,RES               ;Point to array
        CALL_(PrintArray)       ;Print number
        ret

;------------------------------------------------------------------
; Frac2bcd
;
; This procedure converts the fraction part of a fixpoint number to
; a 4 byte array containing the BCD values. Result is stored at adr.
; RES
;
; Entry : a hold the value to be converted
; Exit  : all regs destroyed
; Uses  : Addarray
;------------------------------------------------------------------

Frac2bcd:
        ld b,8                  ;Number of bits in number
        ld hl,RES               ;point to string
        ld d,0                  ;Set result to 0
reset:
        ld (hl),d
        inc hl
        djnz reset
        ld hl,RES               ;point to string
        ld b,8                  ;number of bits
        push hl                 ;Store pointer to result
        ld hl,Cstart            ;Get adr. of first string
        ld de,(PROGRAM_ADDR)    ;Add program offset
        add hl,de
        ex de,hl                ;store in de
        pop hl                  ;Restore pointer to result
loop:
        rr a                    ;Shift left
        jr nc,next              ;skip if bit=0
        push hl                 ;Save pointer to result
        CALL_(Addarray)         ;Add number
        pop hl                  ;Restore pointer to result
        jr next2                ;
next:
        dec de                  ;Point to next number
        dec de
        dec de
        dec de
next2:
        djnz loop               ;Repeat for all bits
                                ;Now RES cointains a 8 byte bcd array with the 
result.
        ret

;------------------------------------------------------------------
;
; PrintBCD
;
; Prints the BCD number in A on the display. This function was
; originally called PrintHex and was made by Darryl Nester
; (email : nesterd@bluffton.edu)
;
; Entry : A holds value to be printed
; Exit  : No regs destroyed
;------------------------------------------------------------------

PrintBCD:
  push  af                      ;Save number
  rrca                          ;Make the 4 MSB's the 4 LSB's
  rrca
  rrca
  rrca
  CALL_(Digit)                  ;Display first digit
  pop   af                      ;Restore number
Digit:
  and $0F                       ;Use only lower 4 bits
  add a,'0'                     ;Make ascii
  ROM_CALL(TX_CHARPUT)          ;Show digit
  ret

;------------------------------------------------------------------
;
; PrintArray
;
; Prints a 4 byte array of BCD numbers on the display.
;
; Entry : HL points to array
; Exit  : Destroys A and HL
; Uses  : uses PrintBCD to print each digit
;
;------------------------------------------------------------------

PrintArray:
        ld b,4                  ;Number of bytes in array
PALoop:
        ld a,(hl)               ;Get byte
        CALL_(PrintBCD);        ;Print it
        inc hl                  ;point to next byte
        djnz PALoop
        ret

;------------------------------------------------------------------
; Addarray
;
; Addition of two 8 byte long bcd/numbers.
;
; Entry : hl points to start of array
;         de points to last byte in second array  
; Exit  : destroys bc,de,hl and flags
;------------------------------------------------------------------

Addarray:
        ld bc,$0003             ;Lenght of string-1
        add hl,bc               ;Point to end of string
        ld b,4                  ;Number of bytes
        ld c,a                  ;Save a reg
        and a                   ;clear carry
Addloop:
        ld a,(de)               ;Get first byte
        adc a,(hl)              ;Add second byte
        daa                     ;Make BCD
        ld (hl),a               ;Store result
        dec hl                  ;Point to next bytes
        dec de
        djnz Addloop            ;Do it for all bytes in array
        ld a,c                  ;Restore A reg
        ret                     ;Done

C7:
.db $50,$00,$00,$00             ;Arrays used for bin->ascii convertion of fracs.
C6:
.db $25,$00,$00,$00
C5:
.db $12,$50,$00,$00
C4:
.db $06,$25,$00,$00
C3:
.db $03,$12,$50,$00
C2:
.db $01,$56,$25,$00
C1:
.db $00,$78,$12,$50
C0:
.db $00,$39,$06
Cstart:                         ;Make it easy to point last byte
.db $25
.END

