?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

  1. #ifndef included_f32toa
  2. #define included_f32toa
  3. #include "pushpop.z80"
  4. #include "f32_pow10_LUT.z80"
  5. #include "f32mul.z80"
  6. #include "mov4.z80"
  7. #include "common_str.z80"
  8.  
  9. ;#define EXTERNAL_FORMAT_LEN                  ;Uses an external reference to get the format length
  10. ;#define EXTERNAL_FORMAT_LEN fmtDigits    ;Use for TI-OS
  11.  
  12. ; Set a hard upper limit to the number of digits used
  13. ; This routine uses at most MAX_FORMAT_LEN+8 bytes of space
  14. #ifndef MAX_FORMAT_LEN
  15. #define MAX_FORMAT_LEN 8
  16. #endif
  17.  
  18. ; Set the default number of digits used. If EXTERNAL_FORMAT_LEN is defined and
  19. ; that value is 0 or greater than MAX_FORMAT_LEN, then FORMAT_LEN is used.
  20. #ifndef FORMAT_LEN
  21. #define FORMAT_LEN 6
  22. #endif
  23.  
  24. ; set the char to use for `e` notation
  25. #ifndef TOK_ENG
  26. #define TOK_ENG 'e'
  27. #endif
  28.  
  29. ; set the char to use for negatives
  30. #ifndef TOK_NEG
  31. #define TOK_NEG '-'
  32. #endif
  33.  
  34. ; set the char to use for decimal points
  35. #ifndef TOK_DECIMAL
  36. #define TOK_DECIMAL '.'
  37. #endif
  38.  
  39.  
  40. #define f32toa_x    scrap
  41.  
  42. f32toa:
  43. ;Inputs:
  44. ;   HL points to the input float
  45. ;   BC points to where the string gets written.
  46.   call pushpop
  47.   ld e,(hl)
  48.   inc hl
  49.   ld d,(hl)
  50.   inc hl
  51.   ld (f32toa_x),de
  52.   ld a,(hl)
  53.   ld e,a
  54.   add a,a
  55.   inc hl
  56.   ld a,(hl)
  57.   ld d,a
  58.   adc a,a
  59.   ld h,b
  60.   ld l,c
  61.   inc a
  62.   jp z,f32toa_return_infnan
  63.   res 7,d
  64.   ld (f32toa_x+2),de
  65.   jr nc,+_
  66.   ld (hl),TOK_NEG    ;negative sign
  67.   inc hl
  68. _:
  69. ;DEBC is the float, A is a copy of the exponent, HL points to the next byte to write
  70.   dec a
  71.   jp z,f32toa_return_0
  72.  
  73.   push hl
  74.  
  75.   ld (hl),'0' ; pad one more '0' to make room for rounding (i.e. 9.999999=>10.000000)
  76.   inc hl
  77.  
  78.   push hl
  79.  
  80. ; approximate the base-10 exponent as floor((A-127)*log10(2))
  81. ; which is approximately floor((A-127)*77/256)
  82.   ld h,0
  83.   ld l,a
  84.   ld b,h
  85.   ld c,a
  86.   add hl,hl ;2
  87.   add hl,hl ;4
  88.   add hl,hl ;8
  89.   add hl,bc ;9
  90.   add hl,hl ;18
  91.   add hl,bc ;19
  92.   add hl,hl ;38
  93.   add hl,hl ;76
  94.   add hl,bc ;77
  95.   ; now subtract 127*77 from HL and keep the upper 8 bits of the result
  96.   ld a,205
  97.   add a,l
  98.   ld a,217
  99.   adc a,h
  100.   ; A is the approximate base-10 exponent
  101. ;f32toa_x needs to be multipled by 10^-A
  102.   push af ; save the exponent
  103.   call nz,f32toa_adjust
  104. ;the float is now on [1, 20)
  105. ;Let's no work on the float as a 0.24 fixed-point value
  106. ;we'll first need to extract the integer component
  107.   ld hl,(f32toa_x)
  108.   ld de,(f32toa_x+2)
  109.   ld a,e
  110.   rlca
  111.   scf
  112.   rra
  113.   ld e,a
  114.   ld a,d
  115.   adc a,a
  116.   sub 126
  117. ; A is how many bits to shift out of HLE
  118.   ld b,a
  119.   xor a
  120. f32toa_first_digit_loop:
  121.   add hl,hl
  122.   rl e
  123.   rla
  124.   djnz f32toa_first_digit_loop
  125.  
  126. ; A is the first digit
  127.   pop bc  ; B is the base-10 exponent
  128.   ex (sp),hl
  129.   ld d,0
  130.   cp 10
  131.   jr c,f32toa_first_digit_fixed
  132.   inc d
  133.   dec hl
  134.   ld (hl),'1'
  135.   inc hl
  136.   sub 10
  137. f32toa_first_digit_fixed:
  138.   add a,'0'
  139.   ld (hl),a
  140.  
  141.   ld a,b
  142.   ex (sp),hl
  143.   pop bc
  144. ;A is the base-10 exponent
  145. ;BC is where to write the digits
  146. ;EHL is the 0.24 fixed-point number
  147. ;D is 1 if we have 2 digits already, else D is 0
  148.   push af
  149.   call f32toa_digits
  150.  
  151. ;BC points to the last digit. We'll want to round!
  152.   ld h,b
  153.   ld l,c
  154.   ld a,(hl)
  155.   ld (hl),0
  156.   add a,5
  157.   jr f32toa_round_start
  158. f32toa_round_loop:
  159.   dec hl
  160.   inc (hl)
  161.   ld a,(hl)
  162. f32toa_round_start:
  163.   cp '9'+1
  164.   jr nc,f32toa_round_loop
  165. ; the string is rounded
  166.   inc hl
  167.   ld (hl),0
  168.  
  169.   ; pop the exponent off the stack and sign-extend
  170.   pop af
  171.   ld e,a
  172.   add a,a
  173.   sbc a,a
  174.   ld d,a
  175.   pop hl
  176.   ; check if rounding caused overflow; increment exponent if so
  177.   ld a,(hl)
  178.   cp '0'
  179.   jp z,formatstr
  180.   inc de
  181.   jp formatstr
  182.  
  183.  
  184. f32toa_digits:
  185. ; How many digits do we need?
  186. #ifdef EXTERNAL_FORMAT_LEN
  187.   ; we define the number of digits externally
  188.   ld a,(EXTERNAL_FORMAT_LEN)
  189.  
  190.   ; if A is 0, use FORMAT_LEN
  191.   or a
  192.   jr nz,$+4
  193.   ld a,FORMAT_LEN
  194.  
  195.   ; if A > MAX_FORMAT_LEN, set A to MAX_FORMAT_LEN
  196.   cp MAX_FORMAT_LEN
  197.   jr c,$+4
  198.   ld a,MAX_FORMAT_LEN
  199.  
  200.   ; the first digit is written.
  201.   ; if we only wanted 1 digit, then A is 0 and we should stop
  202.   or a
  203.   ret z
  204. #else
  205.   ; the number of digits is not declared externally
  206.   ; the first digit is written.
  207.   ; if we only wanted 1 digit, then A is 0 and we should stop
  208. #if FORMAT_LEN < 2
  209.   ret
  210. #else
  211.   ld a,FORMAT_LEN
  212. #endif
  213. #endif
  214.  
  215. ; we want D more digits (an extra one for rounding)
  216. f32toa_digits_loop:
  217.   push af
  218.   call f32toa_next_digit
  219.   pop af
  220. f32toa_digits_start:
  221.   dec a
  222.   jr nz,f32toa_digits_loop
  223.   ret
  224.  
  225. f32toa_next_digit:
  226. ; multiply 0.EBC by 10
  227.   push bc
  228.   ld b,h
  229.   ld c,l
  230.   ld a,e
  231.   ld d,6  ;overflow digit. We shift d 3 times, that 6 turns into a 0x30 == '0'
  232.  
  233.   add hl,hl
  234.   adc a,a
  235.   rl d
  236.  
  237.   add hl,hl
  238.   adc a,a
  239.   rl d
  240.  
  241.   add hl,bc
  242.   adc a,e
  243.   jr nc,$+3
  244.   inc d
  245.  
  246.   add hl,hl
  247.   adc a,a
  248.   ld e,a
  249.   ld a,d
  250.   adc a,a
  251.  
  252.   pop bc
  253.   inc bc
  254.   ld (bc),a
  255.   ret
  256.  
  257.  
  258. f32toa_adjust:
  259.   ld hl,f32_pown10_LUT-4
  260.   jr c,f32toa_pow10LUT_mul
  261.   neg
  262.   ld hl,f32_pow10_LUT-4
  263. f32toa_pow10LUT_mul:
  264. ;HL points to the first entry of the LUT
  265. ;(f32toa_x) is the accumulator
  266. ;bottom 6 bits of A control which terms to multiply by
  267.   ld de,f32toa_x
  268.   ld b,d
  269.   ld c,e
  270. ; process f32toa_pow10LUT_mul_sub 6 times
  271.   call f32toa_pow10LUT_mul_sub3
  272. f32toa_pow10LUT_mul_sub3:
  273.   call f32toa_pow10LUT_mul_sub
  274.   call f32toa_pow10LUT_mul_sub
  275. f32toa_pow10LUT_mul_sub:
  276.   inc hl
  277.   inc hl
  278.   inc hl
  279.   inc hl
  280.   rra
  281.   jp c,f32mul
  282.   ret
  283.  
  284. f32toa_return_0:
  285.   ld (hl),'0'
  286.   inc hl
  287.   ld (hl),0
  288.   ret
  289.  
  290. f32toa_return_infnan:
  291.   rl b  ; save the sign
  292.   ld a,e
  293.   add a,a
  294.   ld de,(f32toa_x)
  295.   or d
  296.   or e
  297.   ex de,hl
  298.   ld hl,str_NaN
  299.   jr nz,f32toa_return
  300.   ld hl,str_inf
  301.   rr b
  302.   jr nc,f32toa_return
  303.   ld a,'-'
  304.   ld (de),a
  305.   inc de
  306. f32toa_return:
  307.   jp mov4
  308.  
  309. #include "formatstr.z80"
  310. #endif
  311.