aboutsummaryrefslogtreecommitdiff
path: root/bigfloat.s
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2016-01-17 04:08:52 -0500
committerB. Watson <yalhcru@gmail.com>2016-01-17 04:08:52 -0500
commitd72f8556e703eb8c84d055bfc5a8dcb2620ad61e (patch)
tree51326271fb66ee562b42911422c35ec9b28be362 /bigfloat.s
parentb9c1931a80c5d700ba356f9090e9a72f075377f7 (diff)
downloadtaipan-d72f8556e703eb8c84d055bfc5a8dcb2620ad61e.tar.gz
restore colors/font on exit, fix bank withdrawal bug, rename bignum stuff
Diffstat (limited to 'bigfloat.s')
-rw-r--r--bigfloat.s334
1 files changed, 334 insertions, 0 deletions
diff --git a/bigfloat.s b/bigfloat.s
new file mode 100644
index 0000000..9cfae63
--- /dev/null
+++ b/bigfloat.s
@@ -0,0 +1,334 @@
+
+
+ .importzp ptr3, ptr4, sreg
+ .import popeax, popax, pushax, _memcmp
+ .export _ulong_to_big, _big_to_ulong, _big_add, _big_sub, _big_mul, _big_div
+ .export _bank_maxed_out, _big_cmp, _big_copy, _big_negate
+
+ .include "atari.inc"
+
+;IFP = $d9aa
+
+ fptemp = $a0 ; for now
+ trampoline = $c0
+
+ NORMALIZE = $dc00
+
+ .rodata
+BIG_64K:
+ .byte $42, $06, $55, $36, $00, $00
+
+;BIG_ULONG_MAX:
+ ;.byte $44, $42, $94, $96, $72, $95
+
+ .code
+
+; TODO: replace these *_to_* with OS calls
+
+fr0_to_fptemp:
+ ldx #5
+@l:
+ lda FR0,x
+ sta fptemp,x
+ dex
+ bpl @l
+ rts
+
+fptemp_to_fr0:
+ ldx #5
+@l:
+ lda fptemp,x
+ sta FR0,x
+ dex
+ bpl @l
+ rts
+
+fptemp_to_fr1:
+ ldx #5
+@l:
+ lda fptemp,x
+ sta FR1,x
+ dex
+ bpl @l
+ rts
+
+fr0_to_ptr3:
+ ldy #5
+@l:
+ lda FR0,y
+ sta (ptr3),y
+ dey
+ bpl @l
+ rts
+
+ptr4_to_fr1:
+ ldy #5
+@l:
+ lda (ptr4),y
+ sta FR1,y
+ dey
+ bpl @l
+ rts
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; void __fastcall__ big_negate(bignump dest, bignump src);
+_big_negate:
+ sta ptr3
+ stx ptr3+1
+ jsr popax
+ sta ptr4
+ stx ptr4+1
+ ldy #0
+ lda (ptr3),y
+ eor #$80
+ sta (ptr4),y
+ rts
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; truncate FR0 to integer (no rounding: 2.8 -> 2)
+trunc_fr0:
+ lda FR0
+ and #$7f ; strip sign bit (we only care about exponent magnitude)
+ sec
+ sbc #$3f ; A now holds # of base-100 digits in integer part
+ bcs @ok ; # of int digits > 0?
+ jmp ZFR0 ; no, zero out FR0 and exit
+
+@ok:
+ cmp #5 ; are there <= 5 int digits?
+ bcs @done ; no, the number's already an integer.
+
+ tax ; zero out digits: X is first one after decimal point
+ lda #0
+@zloop:
+ sta FR0+1,x
+ inx
+ cpx #5
+ bne @zloop
+
+@done:
+ rts
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; void __fastcall__ big_copy(bignump dest, bignump src)
+_big_copy:
+ sta FLPTR ; src arg in FLPTR
+ stx FLPTR+1
+ jsr FLD0P ; load src value into FR0
+ jsr popax ; get dest arg
+ sta FLPTR ; dest arg in FLPTR
+ stx FLPTR+1
+ jmp FST0P ; store FR0 value into dest
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; void __fastcall__ big_binary_op(bignump dest, bignump a, bignump b, unsigned int jsraddr);
+_big_binary_op:
+
+ ; JSR address in A/X pair, set up JMP instruction
+ sta trampoline+1
+ stx trampoline+2
+ lda #$4c ; JMP opcode
+ sta trampoline
+
+ ; get 2nd operand (b), load into FR1
+ jsr popax
+ sta FLPTR
+ stx FLPTR+1
+ jsr PLD1P
+
+ ; get 1st operand (a), load into FR0
+ jsr popax
+ sta FLPTR
+ stx FLPTR+1
+ jsr FLD0P
+
+ ; call the FP routine
+ jsr trampoline
+
+; jsr NORMALIZE
+; .byte $02
+
+ ; result now in FR0, get destination & copy
+ jsr popax
+ sta FLPTR
+ stx FLPTR+1
+ jmp FST0P
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; void __cdecl__ big_add(bignump dest, bignump a, bignump b);
+_big_add:
+ lda #<FADD
+ ldx #>FADD
+ jmp _big_binary_op
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; void __cdecl__ big_sub(bignump dest, bignump a, bignump b);
+_big_sub:
+ lda #<FSUB
+ ldx #>FSUB
+ jmp _big_binary_op
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; void __cdecl__ big_mul(bignump dest, bignump a, bignump b);
+_big_mul:
+ lda #<FMUL
+ ldx #>FMUL
+ jmp _big_binary_op
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; void __cdecl__ big_div(bignump dest, bignump a, bignump b);
+_big_div:
+ lda #<FDIV
+ ldx #>FDIV
+ jmp _big_binary_op
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; void __fastcall__ big_trunc(bignump b);
+; C-callable wrapper for trunc_fr0
+ sta FLPTR
+ stx FLPTR+1
+ jsr FLD0P
+ jsr trunc_fr0
+ jsr FST0P
+ rts
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; void __fastcall__ ulong_to_big(const unsigned long l, bignum *b);
+_ulong_to_big:
+ sta ptr3
+ stx ptr3+1 ; save b (destination)
+
+ jsr popeax ; get low 16 bits of l in A/X (hi 16 bits in sreg)
+ sta FR0
+ stx FR0+1
+ jsr IFP ; convert A/X to fp
+
+ jsr fr0_to_fptemp ; stash it
+
+ lda sreg ; now get high 16 bits of l in A/X
+ sta FR0
+ ldx sreg+1
+ stx FR0+1
+ jsr IFP ; convert to fp
+
+ lda #<BIG_64K ; high value needs to be multiplied by 65536
+ sta ptr4
+ lda #>BIG_64K
+ sta ptr4+1
+ jsr ptr4_to_fr1
+
+ jsr FMUL ; multiply...
+ jsr fptemp_to_fr1 ; grab low value
+ jsr FADD ; add to total
+ jmp fr0_to_ptr3 ; store it in b and we're done.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; char __fastcall__ big_to_ulong(bignump b, unsigned long *l);
+;
+; This works, but it's not small, fast, or elegant...
+_big_to_ulong:
+ sta ptr3
+ stx ptr3+1 ; save *l (dest)
+
+ jsr popax ; get b
+ sta FLPTR
+ sta sreg
+ stx FLPTR+1
+ stx sreg+1
+ jsr FLD0P ; there's a typo in atari.inc, should be FLD1P
+
+ ldx #<BIG_64K ; FR1 = 65536
+ ldy #>BIG_64K
+ jsr FLD1R
+
+ jsr FDIV ; FR0 = FR0 / FR1
+ jsr trunc_fr0 ; FR0 = INT(FR0)
+ jsr fr0_to_fptemp ; stash for later...
+ jsr FPI ; get integer form
+ bcc @ok ; OS supposed to return with C set if range error
+
+ ; failed, return 0 to caller
+ lda #0
+ tax
+ rts
+
+@ok:
+ ldy #2 ; save top 16 bits of result where they belong
+ lda FR0
+ sta (ptr3),y
+ iny
+ lda FR0+1
+ sta (ptr3),y
+
+ jsr fptemp_to_fr0 ; this is int((*b)/65536) in FR0 now
+
+ ldx #<BIG_64K ; FR1 = 65536
+ ldy #>BIG_64K
+ jsr FLD1R
+
+ jsr FMUL ; FR0 now int((*b)/65536)*65536
+ jsr FMOVE ; FR1 = FR0
+
+ ldx sreg ; reload original *b in FR0
+ ldy sreg+1
+ jsr FLD0R
+ jsr trunc_fr0 ; grrr. If we don't do this, we get rounding (not desired)
+
+ jsr FSUB ; FR0 = FR0 - FR1
+ jsr FPI
+
+ ldy #0 ; store low 16 bits where they belong
+ lda FR0
+ sta (ptr3),y
+ iny
+ lda FR0+1
+ sta (ptr3),y
+
+ ; success. return 1 to caller.
+ tya
+ ldx #0
+ rts
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; char __fastcall__ bank_maxed_out(bignump b);
+_bank_maxed_out:
+ sta FLPTR
+ stx FLPTR+1
+ jsr FLD0P
+ jsr NORMALIZE ; just in case
+ lda FR0 ; get exponent
+ ldx #0
+ eor #$7f ; remove sign bit (should never be negative anyway!)
+ cmp #$46
+ bcc @false
+ lda #1
+ rts
+@false:
+ txa
+ rts
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; signed char __fastcall__ big_cmp(bignump a, bignump b)
+;
+; this could be better: it could be a wrapper for _big_binary_op. But
+; I'd have to move stuff all around on the stack.
+_big_cmp:
+ sta FLPTR
+ stx FLPTR+1
+ jsr FLD0P
+
+ jsr FMOVE ; move to FR1 (since it's the 2nd arg)
+
+ jsr popax ; get a arg
+
+ sta FLPTR
+ stx FLPTR+1
+ jsr FLD0P
+
+ ; subtract (and throw away the result, only care about sign)
+ jsr FSUB ; FR0 = FR0 - FR1
+
+ lda FR0 ; exponent has sign bit, and happily is 0 if the result was 0!
+ tax ; sign extension, grr.
+ rts
+