DemiEngine includes a full-featured Floating Point Unit (FPU) based on the x87 architecture, supporting both 32-bit (float) and 64-bit (double) precision floating-point operations.
The FPU uses a stack-based register architecture:
- ST(0) through ST(7): 8 floating-point registers organized as a stack
- ST(0): Top of stack (TOS) - primary register for operations
- Operations typically work with ST(0) and either another stack register or memory
- 32-bit Float: Single precision (float)
- 64-bit Double: Double precision (double)
- Integer Support: Can load/store integers and convert to floating-point
FADD <source> ; ST(0) = ST(0) + sourceOperand Types:
- Memory Address: Adds value at address to ST(0).
- Immediate Value: Adds immediate value to ST(0).
Example:
FLD 0x100 ; Load float from memory
FADD 3.14 ; Add immediate 3.14
FADD 0x200 ; Add value at memory address 0x200FSUB <source> ; ST(0) = ST(0) - sourceExample:
FLD 0x200
FSUB 0x204 ; Subtract float at memory address 0x204
FSUB 1.5 ; Subtract immediate 1.5FMUL <source> ; ST(0) = ST(0) * sourceExample:
FLD 0x300
FMUL 0x308 ; Multiply by value at memory address 0x308
FMUL 2.0 ; Multiply by immediate 2.0FDIV <source> ; ST(0) = ST(0) / sourceExample:
FLD 0x400
FDIV 2.0 ; Divide by immediate 2.0
FDIV 0x404 ; Divide by value at memory address 0x404FSIN ; ST(0) = sin(ST(0))Example:
FLD 0x03, 1.5708 ; Load π/2
FSIN ; Result = 1.0FCOS ; ST(0) = cos(ST(0))Example:
FLD 0x03, 3.14159 ; Load π
FCOS ; Result = -1.0FTAN ; ST(0) = tan(ST(0))FSQRT ; ST(0) = sqrt(ST(0))Example:
FLD 0x03, 16.0
FSQRT ; Result = 4.0FABS ; ST(0) = |ST(0)|Example:
FLD 0x03, -5.5
FABS ; Result = 5.5FCHS ; ST(0) = -ST(0)Example:
FLD 0x03, 3.14
FCHS ; Result = -3.14FLD [source] ; Push source onto FPU stackOperand Types:
- Memory (32-bit):
FLD 0x01 <address> - Memory (64-bit):
FLD 0x02 <address> - Immediate (64-bit):
FLD 0x03 <8-byte-value> - Stack register:
FLD 0x04 <ST(i)>
Examples:
FLD 0x01 0x1000 ; Load 32-bit float from 0x1000
FLD 0x02 0x2000 ; Load 64-bit double from 0x2000
FLD 0x03, 2.71828 ; Load immediate value (e)
FLD 0x04 0x02 ; Push copy of ST(2)FST [dest] ; Store ST(0) to destination (keep on stack)Operand Types:
- Memory (32-bit):
FST 0x01 <address> - Memory (64-bit):
FST 0x02 <address> - Stack register:
FST 0x04 <ST(i)>
Examples:
FST 0x01 0x3000 ; Store as 32-bit float to 0x3000
FST 0x02 0x4000 ; Store as 64-bit double to 0x4000
FST 0x04 0x01 ; Copy ST(0) to ST(1)FSTP [dest] ; Store ST(0) to destination and popExample:
FSTP 0x02 0x5000 ; Store double and remove from stackFILD [source] ; Load integer and convert to floatOperand Types:
- Memory (16-bit):
FILD 0x01 <address> - Memory (32-bit):
FILD 0x02 <address> - Memory (64-bit):
FILD 0x03 <address>
Example:
FILD 0x02 0x6000 ; Load 32-bit integer, convert to floatFIST [dest] ; Convert ST(0) to integer and storeOperand Types:
- Memory (16-bit):
FIST 0x01 <address> - Memory (32-bit):
FIST 0x02 <address>
Example:
FIST 0x02 0x7000 ; Round to 32-bit integer and storeFISTP [dest] ; Convert, store, and popOperand Types:
- Memory (16-bit):
FISTP 0x01 <address> - Memory (32-bit):
FISTP 0x02 <address> - Memory (64-bit):
FISTP 0x03 <address>
FCOMPP ; Compare ST(0) with ST(1), pop bothSets FPU status flags based on comparison:
- ST(0) > ST(1): C3=0, C2=0, C0=0
- ST(0) < ST(1): C3=0, C2=0, C0=1
- ST(0) = ST(1): C3=1, C2=0, C0=0
FUCOMPP ; Unordered compare ST(0) with ST(1), pop bothSimilar to FCOMPP but handles NaN differently.
FINIT ; Reset FPU to initial stateResets:
- Control word to default
- Status word to 0
- Tag word to empty
- Clears exceptions
FCLEX ; Clear exception flagsFLDCW <address> ; Load FPU control word from memoryExample:
FLDCW 0x8000 ; Load control word from addressFSTCW <address> ; Store FPU control word to memoryExample:
FSTCW 0x8004 ; Store control word to addressFSTSW <dest> ; Store FPU status wordDestinations:
- Memory:
FSTSW 0x01 <address> - AX register:
FSTSW 0x02
Example:
FSTSW 0x01 0x9000 ; Store status to memory
FSTSW 0x02 ; Store status to AX (R0)Note: The FPU opcodes are currently mapped to the 0xA0-0xB6 range in the implementation.
| Opcode | Mnemonic | Description |
|---|---|---|
| 0xA0 | FLD | Load floating point value |
| 0xA1 | FST | Store floating point value |
| 0xA2 | FSTP | Store and pop |
| 0xA3 | FILD | Integer load |
| 0xA4 | FIST | Integer store |
| 0xA5 | FISTP | Integer store and pop |
| 0xA6 | FADD | Floating point addition |
| 0xA7 | FSUB | Floating point subtraction |
| 0xA8 | FMUL | Floating point multiplication |
| 0xA9 | FDIV | Floating point division |
| 0xAA | FSIN | Sine |
| 0xAB | FCOS | Cosine |
| 0xAC | FTAN | Tangent |
| 0xAD | FSQRT | Square root |
| 0xAE | FABS | Absolute value |
| 0xAF | FCHS | Change sign |
| 0xB0 | FINIT | Initialize FPU |
| 0xB1 | FCLEX | Clear exceptions |
| 0xB2 | FSTCW | Store control word |
| 0xB3 | FLDCW | Load control word |
| 0xB4 | FSTSW | Store status word |
| 0xB5 | FCOMPP | Compare and pop twice |
| 0xB6 | FUCOMPP | Unordered compare and pop twice |
; Calculate (a + b) * c
FLD 0x02 0x1000 ; Load a (double)
FADD 0x02 0x1008 ; Add b
FMUL 0x02 0x1010 ; Multiply by c
FSTP 0x02 0x1018 ; Store result; F = C * 9/5 + 32
FLD 0x02 0x2000 ; Load Celsius
FMUL 0x03, 1.8 ; Multiply by 9/5 (1.8)
FADD 0x03, 32.0 ; Add 32
FSTP 0x02 0x2008 ; Store Fahrenheit; Area = π * r²
FLD 0x02 0x3000 ; Load radius
FMUL 0x04 0x00 ; Square it (ST(0) * ST(0))
FLD 0x03, 3.14159 ; Load π
FMUL ; Multiply
FSTP 0x02 0x3008 ; Store area; distance = sqrt((x2-x1)² + (y2-y1)²)
FLD 0x02 0x4000 ; Load x2
FSUB 0x02 0x4008 ; Subtract x1
FMUL 0x04 0x00 ; Square (dx²)
FLD 0x02 0x4010 ; Load y2
FSUB 0x02 0x4018 ; Subtract y1
FMUL 0x04 0x00 ; Square (dy²)
FADD ; Add dx² + dy²
FSQRT ; Take square root
FSTP 0x02 0x4020 ; Store distanceBit Layout:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
B C3 ST ST ST C2 C1 C0 ES SF PE UE OE ZE DE IE
Flags:
- B: Busy flag
- C3, C2, C1, C0: Condition codes
- ST: Stack top pointer (3 bits)
- ES: Exception summary
- SF: Stack fault
- PE: Precision exception
- UE: Underflow exception
- OE: Overflow exception
- ZE: Divide-by-zero exception
- DE: Denormalized operand exception
- IE: Invalid operation exception
- Always initialize: Use
FINITat program start - Check for errors: Read status word with
FSTSWafter operations - Manage stack: Balance pushes/pops to avoid stack overflow/underflow
- Use appropriate precision: 32-bit for speed, 64-bit for accuracy
- Handle exceptions: Check and clear exception flags as needed
DemiEngine includes comprehensive FPU testing:
- 10 FPU tests in
tests/fpu.test.asm - All arithmetic operations tested
- Transcendental functions verified
- Load/store operations validated
- Integer conversion tested
- 100% FPU instruction coverage
See tests/fpu.test.asm for complete examples and test cases.