-
Notifications
You must be signed in to change notification settings - Fork 172
Classic Maths Libraries
The classic library provides a Q8.8 fixed point ( 1 sign bit, 7 bits integer, 8 bits fraction) maths library that is defined via <math/math_fix16.h>
. A full range of mathematical functions are available, however due to the limited size of the data type accuracy may be limited.
The Q8.8 is defined as type Accum
and is natively supported by sccz80 as the _Accum
type but not by sdcc. As a result, with sccz80 the regular arithmetical operators can be used, but with sdcc, mulk
, divk
functions need to be called explicitly. Due to the properties of the data type, addition and subtraction can be performed using the +/- operators, though addk
and subk
are provided for completeness.
Mathematical operations are provided and can be accessed by suffixing k
to the usual floating point function name, for example to call the sin function, use sink()
.
Conversions are provided to convert from Q8.8 to integer FIX16_TO_INT(x)
and floating point FIX16_TO_FLOAT()
formats. Conversion from an integer is available via FIX16_FROM_INT(x)
and from a floating point number with FIX16_FROM_FLOAT(x)
. These conversions are constant operations and can be evaluated at compile time if necessary.
If you need to print fixed point numbers, the Accum
value should be converted to a floating point value (using any floating point library described below) using the FIX16_TO_FLOAT(x)
macro.
No additional compiler options are needed to use fixed point maths.
The classic library supports applications being compiled with different floating point maths libraries. Selecting a different library will have implications regarding the size, performance and which machine configuration an application can run in.
When compiling with zsdcc a float in C code is always allocated 4 bytes, and is represented in IEEE 754 single-precision format. However with sccz80, the size of a float depends on which maths library is being used. Traditionally, sccz80 has always allocated a 6 byte (48 bit) block for representing floats, but it also supports maths libraries that use a 4 byte (32 bit) or an 8 byte (64 bit) floating point number.
Generally the 4 byte floating point libraries are substantially faster than the more accurate 6 byte libraries, as handling the additional mantissa resolution does not come for free. For non-critical applications, such as graphics and games, single-precision 4 byte floating point libraries will provide sufficient accuracy with either compiler.
To obtain the maximum floating point granularity the combination of sccz80 and math48 should be preferred, as sccz80 preserves the full resolution generated by the math48 library.
When using sdcc the additional granularity of the 6 byte floating point libraries is not useful, as the compiler internal IEEE 754 single-precision 4 byte floating point format abandons the least significant 16 bits of the floating point mantissa returned by each library function call.
Genmath is z88dk's traditional maths library. It uses a 6 byte (48 bit) floating point format, with an 8 bit exponent and a 40 bit mantissa. It utilises a single index register and runs on all of classic's targets (subject to memory). It should be noted that the library makes extensive use of the undocumented ixh
and ixy
register instructions and as such cannot be used on the 8080, 8085, gbz80, z180 or clones that do not support them.
Genmath can only be used with the sccz80 compiler.
math48 is the default newlib floating point library, and it has been imported into classic from the newlib. It uses a 6 byte (48 bit) floating point format, with an 8 bit exponent and a 40 bit mantissa. It utilises the z80 alternate register set and therefore can't run on all classic targets.
math48 can be used with both sccz80 and (with precision loss) zsdcc compilers, and it is marginally faster than genmath.
The BBC maths library provides a 32 bit mantissa and 8 bit exponent. It's the same library as the native maths library on the z88. The library makes extensive use of the alternate register set. It can be linked with the alias: --math-bbc
.
BBC Maths can only be used with the sccz80 compiler.
The CPC maths library provides a 32 bit mantissa and 8 bit exponent. It's the same library as the native maths library on the CPC. It can be linked with the alias: --math-cpc
. It utilises both index registers so care must be taken when using it.
CPC Maths can only be used with the sccz80 compiler.
MBF32 - (32 bit maths extracted from Microsoft BASIC) - 8080/8085/gbz80/z80/z180/z80n/ez80_z80/kc160/Rabbit
Support has been added for the 4 byte (32 bit, 8 bit exponent, 24 bit mantissa) Microsoft single-precision library.
This library can be used in two ways. As a self-contained maths library that can run on any of the supported processors and as stub library that utilises the ROM code for targets that run Microsoft BASIC and the appropriate entry points have been located. To date, the following machines are supported for this use case:
- VTech Laser 500
- Mitsubishi Multi 8 (10k mode only)
- Mattel Aquarius
- TRS80/Color Genie
- CCE MC-1000
The library can be linked with the following alias: --math-mbf32
.
Some basic optimisation for the 8085 (using undocumented instructions) and z80 has been undertaken. Mainly this involves more effective load and store routines, and improved register shift processes.
MBF32 can only be used with the sccz80 compiler.
DAI32 Maths - (32 bit maths extracted from the DAI target ROM) - 8080/z80/z180/z80n/ez80_z80/kc160/Rabbit
This maths library was extracted from the DAI computer, it offers, a 4 byte, 7 bit exponent, 24 bit mantissa floating point number. It's of particular interest since the floating point format is compatible with the AM9511.
The library can be linked with the following alias: --math-dai32
.
DAI maths can only be used with the sccz80 compiler.
Support has been added for the (8 byte, 8 bit exponent, 56 bit mantissa) Microsoft double precision library. This is available for machines that run Microsoft BASIC and the appropriate entry points have been located. To date, the following machines are supported:
- VTech Laser 500
- TRS80/Color Genie
mbf64 can only be used with the sccz80 compiler.
math32 provides a 32 bit floating point format that is mostly compliant with IEEE-754, which is also the native floating point format of zsdcc. The library can be used with both sccz80 and zsdcc.
math32
supports the z180 (ez80_z80) and ZX Spectrum Next z80n unsigned 16_8x8
hardware multiply instructions, providing accelerated performance for these platforms. The r2ka (Rabbit) signed 32_16x16
hardware multiply and 16-bit register shift instructions are supported, providing very good accelerated performance. The z80 CPU is supported through 24_16x8
and 32_16x16
unrolled mantissa multiply routines which provide good performance.
The intrinsic functions are written in assembler. The higher level functions (trigonometric, exp, pow) are implemented by C functions extracted from the Cephes Maths Library and the Hi-Tech C Floating point library.
More details on the library can be found within the repository.
math16 provides a 16 bit floating point format that is mostly compliant with IEEE-754. The library can be used with both sccz80 and zsdcc.
math16
supports the z180 (ez80) and ZX Spectrum Next z80n unsigned 16_8x8
hardware multiply instructions, providing accelerated performance for both these platforms. The r2ka (Rabbit) signed 32_16x16
hardware multiply and 16-bit register shift instructions are supported, providing very good accelerated performance. The z80 CPU is supported through 32_16x16
unrolled mantissa multiply routines which provide good performance.
The IEEE 16 bit floating point standard supports a maximum of 3.5 significant digits of accuracy, but it is very fast. It is useful for graphics, as per this Cambridge Z88 example comparing the IEEE16 library with the standard maths library.
The intrinsic functions are written in assembler. The intrinsic type is _Float16
for sccz80, or half_t
for both sccz80 or sdcc.
The sccz80 compiler supports _Float16
as a native type, and therefore arithmetic or comparison operations on variables defined as _Float16
or half_t
will be done without conversion. The sdcc compiler doesn't support intrinsic 16 bit floating point operations, but functions can still be called as needed.
The math16
library is considered an adjunct library. When printing format conversion and other facilities are required, it is linked together with a main maths library (which provides the conversion routines). The invocation command will typically include --math32 --math16
, or -lm --math16
to provide both main and adjunct maths libraries.
More details on the library can be found within the repository.
The following machines have maths libraries that utilise the ROM routines which can result in a compact binary. Link with -lmz
to use these libraries:
- Cambridge z88
- ZX Spectrum
- ZX 81
- Amstrad CPC
Additionally, various machines that run Microsoft BASIC can use --math-mbf32
and the ROM routines will be automatically used.
These libraries can only be used with the sccz80 compiler.
Aliases are provided to make usage of maths libraries straight forward. Including the alias in the zcc invocation will provide all necessary configuration options relevant for each maths library.
-
--math-mbf32
is alias for-Cc-fp-mode=mbf32 -lmbf32@{ZCC_LIBCPU} -pragma-define:CLIB_32BIT_FLOATS=1 -Cc-D__MATH_MBF32 -Ca-D__MATH_MBF32 -D__MATH_MBF32
-
--math-mbf64
is alias for-Cc-fp-mode=mbf64 -pragma-define:CLIB_64BIT_FLOATS=1 --lmbf64
-
--math-bbc
is alias for-Cc-fp-mode=z88 -lbbc_math@{ZCC_LIBCPU}
-
--math-dai32
is alias for-Cc-fp-mode=am9511 -ldaimath32@{ZCC_LIBCPU} -pragma-define:CLIB_32BIT_FLOATS=1 -Cc-D__MATH_DAI32 -Ca-D__MATH_DAI32 -D__MATH_DAI32
-
--math-am9511
is alias for-Cc-fp-mode=ieee -lam9511@{ZCC_LIBCPU} -pragma-define:CLIB_32BIT_FLOATS=1 -Cc-D__MATH_AM9511 -Ca-D__MATH_AM9511 -D__MATH_AM9511
-
--math-cpc
is alias for-Cc-fp-exponent-bias=128 -Cc-fp-mantissa-size=5 -lcpcz80_math -D__MATH_CPC
Where @{ZCC_LIBCPU}
is replaced with the appropriate library for the selected CPU type.
The --math16
and --math32
aliases are supported across z80, z180, and z80n (SpectrumNext) architectures, and automatically provides each target with the correct hardware multiply opcodes (or for z80 emulation code) to enable best performance.
The math16
library uses 16-bit (integer) memory moves extensively, and therefore optimising code by in-lining memory get and put subroutines has a positive impact on performance, without increasing program size substantially.
-
--math16
is alias for-lmath16@{ZCC_LIBCPU} --opt-code-speed=inlineints -Cc-D__MATH_MATH16 -Ca-D__MATH_MATH16 -D__MATH_MATH16
-
--math32
is alias for-Cc-fp-mode=ieee -lmath32@{ZCC_LIBCPU} -pragma-define:CLIB_32BIT_FLOATS=1 -Cc-D__MATH_MATH32 -Ca-D__MATH_MATH32 -D__MATH_MATH32
-
--am9511
is alias for-Cc-fp-mode=ieee -lam9511 -pragma-define:CLIB_32BIT_FLOATS=1 -Cc-D__MATH_AM9511 -Ca-D__MATH_AM9511 -D__MATH_AM9511
Where @{ZCC_LIBCPU}
is replaced with the appropriate CPU for classic, and with an empty string for newlib.
The maths libraries have been lightly benchmarked using a couple of test programs within the repository. These were tested using the classic library and the following compilation line:
zcc +test -DPRINTF [file.c] [maths flags]
As a result, the numbers include the time spent printing, however this isn't particularly time consuming in the overall scheme:
Library | Compiler | Value 1 | Value 2 | Ticks |
---|---|---|---|---|
correct values | --> | -0.169075164 | -0.169087605 | |
genmath | sccz80 | -0.169075164 | -0.169087605 | 3_652_736_949 |
mbf32 (gbz80) | sccz80 | -0.169075083 | -0.169086337 | 2_555_855_304 |
math48 | sccz80 | -0.169075164 | -0.169087605 | 2_377_856_525 |
cpcmath | sccz80 | -0.16907516 | -0.16908760 | 2_110_177_022 |
mbf32 (z80) | sccz80 | -0.169075083 | -0.169086337 | 1_936_249_932 |
daimath32 | sccz80 | -0.1690751 | -0.1690863 | 1_899_271_269 |
bbcmath | sccz80 | -0.16907516 | -0.16908760 | 1_655_789_776 |
math32 | sccz80 | -0.1690752 | -0.1690867 | 0_993_265_277 * |
math32_z80n | sccz80 | -0.1690752 | -0.1690867 | 0_576_942_516 * |
math32_z180 (ez80) | sccz80 | -0.1690752 | -0.1690867 | 0_563_700_933 * |
Library | Compiler | Value | Ticks |
---|---|---|---|
correct value | --> | 1.274219991 | |
genmath | sccz80 | 1.274219989 | 14_817_735_124 |
math32 | zsdcc | 1.274219 | 10_003_973_822 |
math32 | sccz80 | 1.274219 | 09_718_997_187 |
math48 | sccz80 | 1.274219989 | 09_035_519_932 |
bbcmath | sccz80 | 1.27421999 | 08_017_859_189 |
mbf32 (gbz80) | sccz80 | 1.274220 | 07_941_220_888 |
daimath32 | sccz80 | 1.274220 | 07_483_466_471 |
cpcmath | sccz80 | 1.27421998 | 06_834_032_841 |
mbf32 (z80) | sccz80 | 1.274220 | 06_754_491_551 |
math32_z80n | sccz80 | 1.274219 | 06_396_544_633 |
math32_z180 (ez80) | sccz80 | 1.274219 | 06_120_760_761 |
Library | Compiler | Ticks |
---|---|---|
genmath | sccz80 | 3_589_992_847 |
math48 | zsdcc | 3_766_086_833 |
math48 | sccz80 | 3_266_168_305 |
math32 | zsdcc | 1_410_662_416 |
math32 | sccz80 | 1_142_045_217 * |
math16 | sccz80 | 1_103_113_465 |
math32_z80n | sccz80 | 0_922_658_537 * |
math32_z180 (ez80) | sccz80 | 0_892_842_610 * |
- Overview
- Platform List
- Unsupported Platforms
- i8080/5 Support
- Homebrew hardware quickstart
- Retargetting
- Building the libraries
- Clang support
- Pragmas
- Adding to Classic
- Introduction
- Library Configuration
- CRT
- Header Files
- Assembly Language
- Library in Depth
- Embedded Platform
- Adding to NewLib
- Benchmarks
- Datatypes
- Debugging
- Decompression
- More than 64k
- Deficiencies
- Compiling Larger Applications
- Importing routines written in 8080 assembly mnemonics
- Using CP/M libraries in REL format with z88dk
- Writing optimal code
- Speeding up Compilation
- CMake usage