asm_tests: Implement x87 invalid operation bit on F80 mode

This commit is contained in:
Paulo Matos committed 2025-07-23 16:01:16 +02:00
1 parent 726656d0bf
commit 9a2f62c479
44 files changed
+1139

No files matched your search

@@ -0,0 +1,18 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test 0.0 / 0.0 = Invalid Operation (should set bit 0 of status word)
fldz
fldz
fdiv
fstsw ax
and eax, 1
hlt
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
section .rodata
; Define the 80-bit (10-byte) constant for positive infinity.
positive_infinity: dt __Infinity__
section .text
global _start
_start:
finit ; Initialize the FPU
fld tword [rel positive_infinity] ; Load the constant directly
fcos
fstsw ax
and eax, 1
hlt
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test FIST with NaN input = Invalid Operation (should set bit 0 of status word)
; Create NaN by computing 0.0 / 0.0
fldz
fldz
fdiv
; Try to convert NaN to integer - this should set Invalid Operation
lea ebx, [.data]
fist dword [ebx]
fstsw ax
and eax, 1
hlt
.data:
dd 0
@@ -0,0 +1,27 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test FIST with value too large for 32-bit integer = Invalid Operation
; Load a large floating point value that exceeds INT32_MAX
lea edx, [.large_value]
fld tword [edx]
; Try to convert to 32-bit integer - should set Invalid Operation
lea ebx, [.data]
fist dword [ebx]
fstsw ax
and eax, 1
hlt
.large_value:
dt 1e20
.data:
dd 0
@@ -0,0 +1,28 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test FIST with 16-bit overflow = Invalid Operation (should set bit 0 of status word)
; Create a large number that will overflow int16
; Load 2^30 (larger than int16 range: max int16 = 32767, 2^30 = 1073741824)
finit
fild dword [.thirty]
fld1
fscale
; Try to convert to int16 - this should overflow and be invalid
fistp word [.dummy]
fstsw ax
and eax, 1
hlt
.thirty: dd 30
.dummy: dw 0
@@ -0,0 +1,28 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test FIST with 32-bit overflow = Invalid Operation (should set bit 0 of status word)
; Create a large number that will overflow int32
; Load 2^40 (larger than int32 range: max int32 = 2147483647, 2^40 = 1099511627776)
finit
fild dword [.forty]
fld1
fscale
; Try to convert to int32 - this should overflow and be invalid
fistp dword [.dummy]
fstsw ax
and eax, 1
hlt
.forty: dd 40
.dummy: dd 0
@@ -0,0 +1,28 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test FIST with 64-bit overflow = Invalid Operation (should set bit 0 of status word)
; Create a very large number that will overflow int64
; Load 2^75 (larger than int64 range)
finit
fild dword [.seventyfive]
fld1
fscale
; Try to convert to int64 - this should overflow and be invalid
fistp qword [.dummy]
fstsw ax
and eax, 1
hlt
.seventyfive: dd 75
.dummy: dq 0
@@ -0,0 +1,24 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test FPREM with simple operands first
finit
; Load simple operands: fprem(0, 1) should be valid and return 0
fldz
fld1
; Do FPREM: ST(0) = fprem(ST(0), ST(1)) = fprem(1.0, 0.0)
; fprem(1.0, 0.0) should set Invalid Operation because divisor is zero
fprem
fstsw ax
and eax, 1
hlt
@@ -0,0 +1,29 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test fptan(+infinity) in 32-bit mode = Invalid Operation (should set bit 0 of status word)
; Load positive infinity: exponent all 1s, mantissa 0x8000000000000000
mov eax, 0x00000000
mov [rel .pos_inf], eax
mov eax, 0x80000000
mov [rel .pos_inf + 4], eax
mov ax, 0x7FFF
mov [rel .pos_inf + 8], ax
fld tword [rel .pos_inf]
fptan
fstsw ax
and eax, 1
hlt
.pos_inf:
dq 0
dw 0
@@ -0,0 +1,29 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test fsin(+infinity) in 32-bit mode = Invalid Operation (should set bit 0 of status word)
; Load positive infinity: exponent all 1s, mantissa 0x8000000000000000
mov eax, 0x00000000
mov [rel .pos_inf], eax
mov eax, 0x80000000
mov [rel .pos_inf + 4], eax
mov ax, 0x7FFF
mov [rel .pos_inf + 8], ax
fld tword [rel .pos_inf]
fsin
fstsw ax
and eax, 1
hlt
.pos_inf:
dq 0
dw 0
@@ -0,0 +1,29 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test fsincos(+infinity) in 32-bit mode = Invalid Operation (should set bit 0 of status word)
; Load positive infinity: exponent all 1s, mantissa 0x8000000000000000
mov eax, 0x00000000
mov [rel .pos_inf], eax
mov eax, 0x80000000
mov [rel .pos_inf + 4], eax
mov ax, 0x7FFF
mov [rel .pos_inf + 8], ax
fld tword [rel .pos_inf]
fsincos
fstsw ax
and eax, 1
hlt
.pos_inf:
dq 0
dw 0
@@ -0,0 +1,31 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test ∞ - ∞ using FSUB with memory operand = Invalid Operation (should set bit 0 of status word) - 32bit mode
; Setup memory with +infinity (0x7FF0000000000000 for double precision +infinity)
; In 32-bit mode, we need to store the double in two parts
mov dword [.data], 0x00000000 ; Low 32 bits
mov dword [.data+4], 0x7FF00000 ; High 32 bits
; Create +infinity by dividing 1.0 by 0.0
fld1
fldz
fdiv
; Subtract ∞ - ∞ using memory operand - this should be invalid
fsub qword [.data]
fstsw ax
and eax, 1
hlt
section .data
.data: dq 0
@@ -0,0 +1,24 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test ∞ - ∞ using FSUBR = Invalid Operation (should set bit 0 of status word) - 32bit mode
fld1
fldz
fdiv ; st0 = +∞
; duplicate +infinity
fld st0
; Reverse subtract ∞ - ∞ using FSUBR - this should be invalid
fsubr
fstsw ax
and eax, 1
hlt
@@ -0,0 +1,22 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test ∞ × 0 = Invalid Operation (should set bit 0 of status word)
fld1
fldz
fdiv ; st0 = +∞
; Load 0.0 and multiply with infinity
fldz
fmul
fstsw ax
and eax, 1
hlt
@@ -0,0 +1,24 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test ∞ - ∞ = Invalid Operation (should set bit 0 of status word)
fld1
fldz
fdiv ; st0 = +∞
; Duplicate +infinity on stack
fld st0
; Subtract: +∞ - +∞ -> Invalid Operation
fsub
fstsw ax
and eax, 1
hlt
@@ -0,0 +1,24 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test ∞ - ∞ = Invalid Operation (should set bit 0 of status word) - 32bit mode
fld1
fldz
fdiv ; st0 = +∞
; Duplicate +infinity on stack
fld st0
; Subtract +∞ - ∞ - this should be invalid
fsub
fstsw ax
and eax, 1
hlt
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test (-∞) - (-∞) = Invalid Operation (should set bit 0 of status word) - 32bit mode
; Create -infinity by dividing -1.0 by 0.0
fld1
fchs
fldz
fdiv
; duplicate -infinity on stack
fld st0
; Subtract (-∞) - (-∞) - this should be invalid
fsub
fstsw ax
and eax, 1
hlt
@@ -0,0 +1,33 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test Invalid Operation with reduced precision (64-bit)
; Set precision control to 64-bit (PC = 10b)
fnstcw [.saved_cw]
mov ax, [.saved_cw]
and ax, 0xFCFF
or ax, 0x0200
mov [.new_cw], ax
fldcw [.new_cw]
; Perform invalid operation: 0.0 / 0.0
fldz
fldz
fdiv
fstsw ax
and eax, 1
; Restore original control word
fldcw [.saved_cw]
hlt
.saved_cw: dw 0
.new_cw: dw 0
@@ -0,0 +1,18 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test with a simple 0/0 that we know works
fldz
fldz
fdiv
fstsw ax
and eax, 1
hlt
@@ -0,0 +1,18 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
},
"Mode": "32BIT"
}
%endif
; Test sqrt(-1.0) = Invalid Operation (should set bit 0 of status word)
fld1
fchs
fsqrt
fstsw ax
and eax, 1
hlt
@@ -0,0 +1,29 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "0",
"RBX": "12346"
},
"Mode": "32BIT"
}
%endif
; Test FIST with valid 16-bit conversion
; Load a value that fits in int16 range
finit
fld qword [.value]
; Convert to int16 - this should work without overflow
fistp word [.result]
fstsw ax
and eax, 1
; Load the result to verify conversion worked
movzx ebx, word [.result]
hlt
.value: dq 12345.75
.result: dw 0
@@ -0,0 +1,18 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "0"
},
"Mode": "32BIT"
}
%endif
; Test a valid operation that should NOT set Invalid Operation bit
fld1
fld1
fadd
fstsw ax
and eax, 1
hlt
+17
View File
@@ -0,0 +1,17 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test 0.0 / 0.0 = Invalid Operation (should set bit 0 of status word)
fldz
fldz
fdiv
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test fcos(+infinity) = Invalid Operation (should set bit 0 of status word)
; Load positive infinity: exponent all 1s, mantissa 0x8000000000000000
mov rax, 0x8000000000000000
mov [rel .pos_inf], rax
mov ax, 0x7FFF
mov [rel .pos_inf + 8], ax
fld tword [rel .pos_inf]
fcos
fstsw ax
and rax, 1
hlt
.pos_inf:
dq 0
dw 0
+26
View File
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test FIST with NaN input = Invalid Operation (should set bit 0 of status word)
; Create NaN by computing 0.0 / 0.0
fldz
fldz
fdiv
; Try to convert NaN to integer - this should set Invalid Operation
lea rbx, [rel data]
fist dword [rbx]
fstsw ax
and rax, 1
hlt
align 8
data:
dd 0
@@ -0,0 +1,27 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test FIST with value too large for 32-bit integer = Invalid Operation
; Load a large floating point value that exceeds INT32_MAX
lea rdx, [rel large_value]
fld tword [rdx]
; Try to convert to 32-bit integer - should set Invalid Operation
lea rbx, [rel data]
fist dword [rbx]
fstsw ax
and rax, 1
hlt
align 8
large_value:
dt 1e20
data:
dd 0
@@ -0,0 +1,35 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
section .rodata
.thirty: dq 30
section .bss
.dummy: resw 1
section .text
global _start
_start:
; Test FIST with 16-bit overflow = Invalid Operation (should set bit 0 of status word)
; Create a large number that will overflow int16
; Load 2^30 (larger than int16 range: max int16 = 32767, 2^30 = 1073741824)
finit
fild dword [rel .thirty]
fld1
fscale
; Try to convert to int16 - this should overflow and be invalid
fistp word [rel .dummy]
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,35 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
section .rodata
.fifty: dq 50
section .bss
.dummy: resd 1
section .text
global _start
_start:
; Test FIST with 32-bit overflow = Invalid Operation (should set bit 0 of status word)
; Create a very large number that will overflow int32
; Load 2^50 (larger than int32 range)
finit
fild dword [rel .fifty]
fld1
fscale
; Try to convert to int32 - this should overflow and be invalid
fistp dword [rel .dummy]
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,35 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
section .rodata
.seventyfive: dq 75
section .bss
.dummy: resq 1
section .text
global _start
_start:
; Test FIST with 64-bit overflow = Invalid Operation (should set bit 0 of status word)
; Create a very large number that will overflow int64
; Load 2^75 (larger than int64 range)
finit
fild dword [rel .seventyfive]
fld1
fscale
; Try to convert to int64 - this should overflow and be invalid
fistp qword [rel .dummy]
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,23 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test FPREM with simple operands first
finit
; Load simple operands: fprem(0, 1) should be valid and return 0
fldz
fld1
; Do FPREM: ST(0) = fprem(ST(0), ST(1)) = fprem(1.0, 0.0)
; fprem(1.0, 0.0) should set Invalid Operation because divisor is zero
fprem
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test fptan(+infinity) = Invalid Operation (should set bit 0 of status word)
; Load positive infinity: exponent all 1s, mantissa 0x8000000000000000
mov rax, 0x8000000000000000
mov [rel .pos_inf], rax
mov ax, 0x7FFF
mov [rel .pos_inf + 8], ax
fld tword [rel .pos_inf]
fptan
fstsw ax
and rax, 1
hlt
.pos_inf:
dq 0
dw 0
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test fsin(+infinity) = Invalid Operation (should set bit 0 of status word)
; Load positive infinity: exponent all 1s, mantissa 0x8000000000000000
mov rax, 0x8000000000000000
mov [rel .pos_inf], rax
mov ax, 0x7FFF
mov [rel .pos_inf + 8], ax
fld tword [rel .pos_inf]
fsin
fstsw ax
and rax, 1
hlt
.pos_inf:
dq 0
dw 0
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test fsin(-infinity) = Invalid Operation (should set bit 0 of status word)
; Load negative infinity: exponent all 1s, mantissa 0x8000000000000000, sign bit set
mov rax, 0x8000000000000000
mov [rel .neg_inf], rax
mov ax, 0xFFFF
mov [rel .neg_inf + 8], ax
fld tword [rel .neg_inf]
fsin
fstsw ax
and rax, 1
hlt
.neg_inf:
dq 0
dw 0
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test fsincos(+infinity) = Invalid Operation (should set bit 0 of status word)
; Load positive infinity: exponent all 1s, mantissa 0x8000000000000000
mov rax, 0x8000000000000000
mov [rel .pos_inf], rax
mov ax, 0x7FFF
mov [rel .pos_inf + 8], ax
fld tword [rel .pos_inf]
fsincos
fstsw ax
and rax, 1
hlt
.pos_inf:
dq 0
dw 0
@@ -0,0 +1,23 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test ∞ - ∞ using FSUB
fld1
fldz
fdiv ; st0 = +∞
; duplicate +infinity
fld st0
; Reverse subtract ∞ - ∞ using FSUBR - this should be invalid
fsubr
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,23 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test ∞ × 0 = Invalid Operation (should set bit 0 of status word)
fld1
fldz
fdiv ; st0 = +∞
; Load zero for multiplication
fldz
; Multiply infinity by zero - this should be invalid
fmul
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test ∞ - ∞ = Invalid Operation (should set bit 0 of status word)
fld1
fldz
fdiv ; st0 = +∞
; Duplicate infinity on stack
fld st0
; Create -infinity by changing sign
fchs
; Now compute +∞ + (-∞) which should be invalid
fadd
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,26 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test ∞ - ∞ = Invalid Operation (should set bit 0 of status word)
; Create +infinity by dividing 1.0 by 0.0
fld1
fldz
fdiv
; Create +infinity by dividing 1.0 by 0.0
fld1
fldz
fdiv
; Subtract +∞ - ∞ - this should be invalid
fsub
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,24 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test (-∞) - (-∞) = Invalid Operation (should set bit 0 of status word)
fld1
fchs
fldz
fdiv ; st0 = -∞
; Duplicate -infinity on stack
fld st0
; Subtract (-∞) - (-∞) - this should be invalid
fsub
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,33 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test Invalid Operation with reduced precision (64-bit)
; Set precision control to 64-bit (PC = 10b)
fnstcw [rel saved_cw]
mov ax, [rel saved_cw]
and ax, 0xFCFF
or ax, 0x0200
mov [rel new_cw], ax
fldcw [rel new_cw]
; Perform invalid operation: 0.0 / 0.0
fldz
fldz
fdiv
fstsw ax
and rax, 1
; Restore original control word
fldcw [rel saved_cw]
hlt
align 8
saved_cw: dw 0
new_cw: dw 0
+17
View File
@@ -0,0 +1,17 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test with a simple 0/0 that we know works
fldz
fldz
fdiv
fstsw ax
and rax, 1
hlt
@@ -0,0 +1,17 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1"
}
}
%endif
; Test sqrt(-1.0) = Invalid Operation (should set bit 0 of status word)
fld1
fchs
fsqrt
fstsw ax
and rax, 1
hlt
+36
View File
@@ -0,0 +1,36 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "0",
"RBX": "12346"
}
}
%endif
section .rodata
.value: dq 12345.75
section .bss
.result: resw 1
section .text
global _start
_start:
; Test FIST with valid 16-bit conversion
; Load a value that fits in int16 range
finit
fld qword [rel .value]
; Convert to int16 - this should work without overflow
fistp word [rel .result]
fstsw ax
and rax, 1
; Load the result to verify conversion worked
movzx rbx, word [rel .result]
hlt
+27
View File
@@ -0,0 +1,27 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "0"
}
}
%endif
; Test valid operation should NOT set Invalid Operation bit
; Clear any existing exception flags first
finit
; Perform valid operations
fld1
fld1
fadd
fld1
fdiv
fld1
fsqrt
fstsw ax
and rax, 1
hlt