From ffabea98c1cde420f884f5e00037e4235899c021 Mon Sep 17 00:00:00 2001 From: marcobaye Date: Thu, 27 Jun 2013 20:29:08 +0000 Subject: [PATCH] Added library file for FLPT format. git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@17 4df02467-bbd4-4a76-a152-e7ce94205b78 --- ACME_Lib/cbm/c64/float.a | 29 ++++++++----- ACME_Lib/cbm/flpt.a | 93 ++++++++++++++++++++++++++++++++++++++++ ACME_Lib/cbm/mflpt.a | 22 +++++++--- 3 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 ACME_Lib/cbm/flpt.a diff --git a/ACME_Lib/cbm/c64/float.a b/ACME_Lib/cbm/c64/float.a index 1077cfb..70fbb9d 100644 --- a/ACME_Lib/cbm/c64/float.a +++ b/ACME_Lib/cbm/c64/float.a @@ -4,10 +4,15 @@ lib_cbm_c64_float_a = 1 ; Here are some definitions to help you call the floating-point functions of the -; C64's BASIC ROM. They work using two structures in zero page, called fac1 and -; fac2 (floating-point accumulator 1 and 2, located at $61 and $69). +; C64's BASIC ROM. They work on "float registers", which are actually just +; structures in zero page: +fac1_base = $61 ; base address of floating-point accumulator 1 +fac2_base = $69 ; base address of floating-point accumulator 2 +; There is really no need to use these addresses directly when calling the ROM +; functions. You'd only need the addresses when using . -!source ; include macro to store floats in MFLPT format +!source ; include macro to store floats in six-byte FLPT format +!source ; include macro to store floats in five-byte MFLPT format ; convenience macros: @@ -72,24 +77,26 @@ fac1_read_unsignedY = $b3a2 ; convert 8 bit unsigned int to float fac1_read_string = $b7b5 ; $22/23 must point to string, A must be string length fac1_to_unsignedYA = $b7f7 ; might throw ILLEGAL QUANTITY (result is also in $14/15) fac1_add_point5 = $b849 ; for rounding, call this before fac1_int -fac1_memAY_minus_fac1 = $b850 +fac1_memAY_minus_fac1 = $b850 ; subtract fac1 from mflpt value fac1_fac2_minus_fac1 = $b853 -fac1_add_memAY = $b867 +fac1_add_memAY = $b867 ; add mflpt value fac1_add_fac2 = $b86a fac1_log = $b9ea ; LOG() -fac1_times_memAY = $ba28 -fac2_read_memAY = $ba8c ; load value from memory into fac2 +fac1_times_memAY = $ba28 ; multiply by mflpt value +fac2_read_memAY = $ba8c ; load mflpt value from memory into fac2 +fac2_read_mem_via0x22ptr = $ba90 ; load mflpt value from memory into fac2 fac1_times_10 = $bae2 fac1_divide_by_10 = $bafe -fac1_divide_memAY_by_fac1 = $bb0f -fac1_read_memAY = $bba2 ; load value from memory into fac1 -fac1_to_memXY = $bbd4 ; store fac1 to memory +fac1_divide_memAY_by_fac1 = $bb0f ; divide mflpt value by fac1 value +fac1_read_memAY = $bba2 ; load mflpt value from memory into fac1 +fac1_read_mem_via0x22ptr = $bba6 ; load mflpt value from memory into fac1 +fac1_to_memXY = $bbd4 ; store fac1 to memory as mflpt fac1_read_fac2 = $bbfc ; copy fac2 to fac1 fac2_read_fac1 = $bc0c ; copy fac1 to fac2 fac1_sign_to_A = $bc2b ; $ff, $0, $1 for negative, zero, positive fac1_sgn = $bc39 ; SGN() fac1_abs = $bc58 ; ABS() -fac1_compare_to_memAY = $bc5b +fac1_compare_to_memAY = $bc5b ; compare to mflpt value in memory fac1_to_signed32 = $bc9b fac1_int = $bccc ; INT() fac1_print_unsignedXA = $bdcd diff --git a/ACME_Lib/cbm/flpt.a b/ACME_Lib/cbm/flpt.a new file mode 100644 index 0000000..faf5015 --- /dev/null +++ b/ACME_Lib/cbm/flpt.a @@ -0,0 +1,93 @@ +;ACME 0.94.5 + +!ifdef lib_cbm_flpt_a !eof +lib_cbm_flpt_a = 1 + +; CAUTION! The Commodore BASIC interpreter uses two different formats for +; handling floating-point values, so do not confuse them: +; The "float registers" fac1 and fac2 (actually structures in zero page) use a +; six-byte format commonly known as "flpt" (floating point). +; When storing values in variables (or reading values from ROM), a compressed +; five-byte format is used, commonly known as "mflpt" (memory floating point). + +; This file contains a macro for writing floating point numbers in the six-byte +; "flpt" format, where the sign bit occupies the sixth byte. +; There are no interpreter functions to use this format, so you will have to +; write you own functions for "copy-mem-to-fac1", "copy-fac2-to-mem" etc. + +; Use the macro like this: +; +flpt 3.1415926 ; each use will take up six bytes of memory + + +; now for the technical stuff (stop reading right now if you value your sanity) + +; six-byte layout in memory: +; eeeeeeee 1mmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm sxxxxxxx ; eight bits exponent, 32 bits mantissa with leading '1', sign byte + +; exponent byte: +; exponent has a bias of 128 (128 means the decimal point is right before the mantissa's leading digit) +; if exponent is zero, number value is considered to be zero, regardless of mantissa +; exponents 1..128 are for values < 1 +; exponents 129..255 are for values >= 1 + +; mantissa: +; mantissa is stored big-endian(!) +; the mantissa's leading digit is always '1' (unless the whole value represents zero) + +; sign byte: +; most significant bit is sign: 0 means positive number, 1 means negative number +; the seven lower bits are unused + +; so logically, this is equivalent to: +; + .1mmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm * 2^(eeeeeeee - 128) if sign bit is 0 +; - .1mmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm * 2^(eeeeeeee - 128) if sign bit is 1 + + + +; this is ugly, but it gets the job done +; (if it's stupid, but it works, then it's not stupid) +!macro flpt .value { + !set .float = float(.value) ; make sure to do passes until value is defined + !ifndef .float { + !by $ff, $ff, $ff, $ff, $ff, $ff ; six place holder bytes + } else { + ; value is defined, so split up into sign and non-negative value + !if .float < 0 { + !set .sign = $80 + !set .float = -.float + } else { + !set .sign = $00 + } + !if .float = 0 { + !by 0, 0, 0, 0, 0, 0 ; six zeroes (zero is represented by all bits zero) + } else { + ; split up into exponent and mantissa + !set .exponent = 128 + 32 ; 128 is cbm's bias, 32 is this algo's bias + ; if mantissa is too large, shift right and adjust exponent + !do while .float >= (2.0 ^ 32.0) { + !set .float = .float >> 1 + !set .exponent = .exponent + 1 + } + ; if mantissa is too small, shift left and adjust exponent + !do while .float < (2.0 ^ 31.0) { + !set .float = .float << 1 + !set .exponent = .exponent - 1 + } + !if .exponent < 1 { + !warn "FLPT underflow, using zero instead" + !set .float = 0 + !set .exponent = 0 + !set .sign = 0 + } + !if .exponent > 255 { + !error "FLPT overflow" + } + !by .exponent + !by 255 & int(.float >> 24) + !by 255 & int(.float >> 16) + !by 255 & int(.float >> 8) + !by 255 & int(.float) + !by .sign + } + } +} diff --git a/ACME_Lib/cbm/mflpt.a b/ACME_Lib/cbm/mflpt.a index f9f9685..330f67c 100644 --- a/ACME_Lib/cbm/mflpt.a +++ b/ACME_Lib/cbm/mflpt.a @@ -3,20 +3,28 @@ !ifdef lib_cbm_mflpt_a !eof lib_cbm_mflpt_a = 1 -; here's a macro for writing floating point numbers in the "mflpt" format used by BASIC. -; "mflpt" stands for "memory floating point", where the sign bit is packed into the mantissa. +; CAUTION! The Commodore BASIC interpreter uses two different formats for +; handling floating-point values, so do not confuse them: +; The "float registers" fac1 and fac2 (actually structures in zero page) use a +; six-byte format commonly known as "flpt" (floating point). +; When storing values in variables (or reading values from ROM), a compressed +; five-byte format is used, commonly known as "mflpt" (memory floating point). -; to use it, write: +; This file contains a macro for writing floating point numbers in the five-byte +; "mflpt" format, where the sign bit is packed into the mantissa. +; Several interpreter functions use this format (see ). + +; Use the macro like this: ; +mflpt 3.1415926 ; each use will take up five bytes of memory ; now for the technical stuff (stop reading right now if you value your sanity) ; five-byte layout in memory: -; eeeeeeee smmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm ; eight bits exponent, 32 bits mantissa with sign bit overlay +; eeeeeeee smmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm ; eight bits exponent, 32 bits mantissa with sign bit overlay ; exponent byte: -; exponent has a bias of 128 (128 means the decimal point is right before the mantissa's leading zero) +; exponent has a bias of 128 (128 means the decimal point is right before the mantissa's leading digit) ; if exponent is zero, number value is considered to be zero, regardless of mantissa ; exponents 1..128 are for values < 1 ; exponents 129..255 are for values >= 1 @@ -36,7 +44,7 @@ lib_cbm_mflpt_a = 1 !macro mflpt .value { !set .float = float(.value) ; make sure to do passes until value is defined !ifndef .float { - !by $ff, $ff, $ff, $ff, $ff ; place holder + !by $ff, $ff, $ff, $ff, $ff ; five place holder bytes } else { ; value is defined, so split up into sign and non-negative value !if .float < 0 { @@ -46,7 +54,7 @@ lib_cbm_mflpt_a = 1 !set .sign = $00 } !if .float = 0 { - !by 0, 0, 0, 0, 0 ; zero is represented as all bits zero + !by 0, 0, 0, 0, 0 ; five zeroes (zero is represented by all bits zero) } else { ; split up into exponent and mantissa !set .exponent = 128 + 32 ; 128 is cbm's bias, 32 is this algo's bias