From 9a2f62c47922564adc06fe72704e5ea989065740 Mon Sep 17 00:00:00 2001 From: Paulo Matos Date: Mon, 7 Jul 2025 15:44:50 +0200 Subject: [PATCH] asm_tests: Implement x87 invalid operation bit on F80 mode --- unittests/32Bit_ASM/X87/invalid_div_zero.asm | 18 ++++++++++ .../32Bit_ASM/X87/invalid_fcos_infinity.asm | 26 ++++++++++++++ unittests/32Bit_ASM/X87/invalid_fist_nan.asm | 26 ++++++++++++++ .../32Bit_ASM/X87/invalid_fist_overflow.asm | 27 ++++++++++++++ .../X87/invalid_fist_overflow_16bit.asm | 28 +++++++++++++++ .../X87/invalid_fist_overflow_32bit.asm | 28 +++++++++++++++ .../X87/invalid_fist_overflow_64bit.asm | 28 +++++++++++++++ .../32Bit_ASM/X87/invalid_fprem_infinity.asm | 24 +++++++++++++ .../32Bit_ASM/X87/invalid_fptan_infinity.asm | 29 +++++++++++++++ .../32Bit_ASM/X87/invalid_fsin_infinity.asm | 29 +++++++++++++++ .../X87/invalid_fsincos_infinity.asm | 29 +++++++++++++++ .../X87/invalid_infinity_fsub_memory.asm | 31 ++++++++++++++++ .../X87/invalid_infinity_fsubr_infinity.asm | 24 +++++++++++++ .../X87/invalid_infinity_mul_zero.asm | 22 ++++++++++++ .../32Bit_ASM/X87/invalid_infinity_ops.asm | 24 +++++++++++++ .../X87/invalid_infinity_sub_infinity.asm | 24 +++++++++++++ .../invalid_neg_infinity_sub_neg_infinity.asm | 26 ++++++++++++++ .../X87/invalid_reduced_precision.asm | 33 +++++++++++++++++ .../32Bit_ASM/X87/invalid_simple_test.asm | 18 ++++++++++ .../32Bit_ASM/X87/invalid_sqrt_negative.asm | 18 ++++++++++ unittests/32Bit_ASM/X87/valid_fist_16bit.asm | 29 +++++++++++++++ unittests/32Bit_ASM/X87/valid_operation.asm | 18 ++++++++++ unittests/ASM/X87/invalid_div_zero.asm | 17 +++++++++ unittests/ASM/X87/invalid_fcos_infinity.asm | 26 ++++++++++++++ unittests/ASM/X87/invalid_fist_nan.asm | 26 ++++++++++++++ unittests/ASM/X87/invalid_fist_overflow.asm | 27 ++++++++++++++ .../ASM/X87/invalid_fist_overflow_16bit.asm | 35 ++++++++++++++++++ .../ASM/X87/invalid_fist_overflow_32bit.asm | 35 ++++++++++++++++++ .../ASM/X87/invalid_fist_overflow_64bit.asm | 35 ++++++++++++++++++ unittests/ASM/X87/invalid_fprem_infinity.asm | 23 ++++++++++++ unittests/ASM/X87/invalid_fptan_infinity.asm | 26 ++++++++++++++ unittests/ASM/X87/invalid_fsin_infinity.asm | 26 ++++++++++++++ .../ASM/X87/invalid_fsin_neg_infinity.asm | 26 ++++++++++++++ .../ASM/X87/invalid_fsincos_infinity.asm | 26 ++++++++++++++ .../X87/invalid_infinity_fsubr_infinity.asm | 23 ++++++++++++ .../ASM/X87/invalid_infinity_mul_zero.asm | 23 ++++++++++++ unittests/ASM/X87/invalid_infinity_ops.asm | 26 ++++++++++++++ .../ASM/X87/invalid_infinity_sub_infinity.asm | 26 ++++++++++++++ .../invalid_neg_infinity_sub_neg_infinity.asm | 24 +++++++++++++ .../ASM/X87/invalid_reduced_precision.asm | 33 +++++++++++++++++ unittests/ASM/X87/invalid_simple_test.asm | 17 +++++++++ unittests/ASM/X87/invalid_sqrt_negative.asm | 17 +++++++++ unittests/ASM/X87/valid_fist_16bit.asm | 36 +++++++++++++++++++ unittests/ASM/X87/valid_operation.asm | 27 ++++++++++++++ 44 files changed, 1139 insertions(+) create mode 100644 unittests/32Bit_ASM/X87/invalid_div_zero.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_fcos_infinity.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_fist_nan.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_fist_overflow.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_fist_overflow_16bit.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_fist_overflow_32bit.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_fist_overflow_64bit.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_fprem_infinity.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_fptan_infinity.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_fsin_infinity.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_fsincos_infinity.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_infinity_fsub_memory.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_infinity_fsubr_infinity.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_infinity_mul_zero.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_infinity_ops.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_infinity_sub_infinity.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_neg_infinity_sub_neg_infinity.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_reduced_precision.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_simple_test.asm create mode 100644 unittests/32Bit_ASM/X87/invalid_sqrt_negative.asm create mode 100644 unittests/32Bit_ASM/X87/valid_fist_16bit.asm create mode 100644 unittests/32Bit_ASM/X87/valid_operation.asm create mode 100644 unittests/ASM/X87/invalid_div_zero.asm create mode 100644 unittests/ASM/X87/invalid_fcos_infinity.asm create mode 100644 unittests/ASM/X87/invalid_fist_nan.asm create mode 100644 unittests/ASM/X87/invalid_fist_overflow.asm create mode 100644 unittests/ASM/X87/invalid_fist_overflow_16bit.asm create mode 100644 unittests/ASM/X87/invalid_fist_overflow_32bit.asm create mode 100644 unittests/ASM/X87/invalid_fist_overflow_64bit.asm create mode 100644 unittests/ASM/X87/invalid_fprem_infinity.asm create mode 100644 unittests/ASM/X87/invalid_fptan_infinity.asm create mode 100644 unittests/ASM/X87/invalid_fsin_infinity.asm create mode 100644 unittests/ASM/X87/invalid_fsin_neg_infinity.asm create mode 100644 unittests/ASM/X87/invalid_fsincos_infinity.asm create mode 100644 unittests/ASM/X87/invalid_infinity_fsubr_infinity.asm create mode 100644 unittests/ASM/X87/invalid_infinity_mul_zero.asm create mode 100644 unittests/ASM/X87/invalid_infinity_ops.asm create mode 100644 unittests/ASM/X87/invalid_infinity_sub_infinity.asm create mode 100644 unittests/ASM/X87/invalid_neg_infinity_sub_neg_infinity.asm create mode 100644 unittests/ASM/X87/invalid_reduced_precision.asm create mode 100644 unittests/ASM/X87/invalid_simple_test.asm create mode 100644 unittests/ASM/X87/invalid_sqrt_negative.asm create mode 100644 unittests/ASM/X87/valid_fist_16bit.asm create mode 100644 unittests/ASM/X87/valid_operation.asm diff --git a/unittests/32Bit_ASM/X87/invalid_div_zero.asm b/unittests/32Bit_ASM/X87/invalid_div_zero.asm new file mode 100644 index 000000000..096928fb2 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_div_zero.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_fcos_infinity.asm b/unittests/32Bit_ASM/X87/invalid_fcos_infinity.asm new file mode 100644 index 000000000..b9440d434 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_fcos_infinity.asm @@ -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 + diff --git a/unittests/32Bit_ASM/X87/invalid_fist_nan.asm b/unittests/32Bit_ASM/X87/invalid_fist_nan.asm new file mode 100644 index 000000000..5623f3d69 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_fist_nan.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_fist_overflow.asm b/unittests/32Bit_ASM/X87/invalid_fist_overflow.asm new file mode 100644 index 000000000..4e279f390 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_fist_overflow.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_fist_overflow_16bit.asm b/unittests/32Bit_ASM/X87/invalid_fist_overflow_16bit.asm new file mode 100644 index 000000000..218708720 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_fist_overflow_16bit.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_fist_overflow_32bit.asm b/unittests/32Bit_ASM/X87/invalid_fist_overflow_32bit.asm new file mode 100644 index 000000000..b3e369e2f --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_fist_overflow_32bit.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_fist_overflow_64bit.asm b/unittests/32Bit_ASM/X87/invalid_fist_overflow_64bit.asm new file mode 100644 index 000000000..0b1b1e526 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_fist_overflow_64bit.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_fprem_infinity.asm b/unittests/32Bit_ASM/X87/invalid_fprem_infinity.asm new file mode 100644 index 000000000..08650d7b6 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_fprem_infinity.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_fptan_infinity.asm b/unittests/32Bit_ASM/X87/invalid_fptan_infinity.asm new file mode 100644 index 000000000..27cb5ef8b --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_fptan_infinity.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_fsin_infinity.asm b/unittests/32Bit_ASM/X87/invalid_fsin_infinity.asm new file mode 100644 index 000000000..432ca7fea --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_fsin_infinity.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_fsincos_infinity.asm b/unittests/32Bit_ASM/X87/invalid_fsincos_infinity.asm new file mode 100644 index 000000000..253287761 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_fsincos_infinity.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_infinity_fsub_memory.asm b/unittests/32Bit_ASM/X87/invalid_infinity_fsub_memory.asm new file mode 100644 index 000000000..cf11974fd --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_infinity_fsub_memory.asm @@ -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 \ No newline at end of file diff --git a/unittests/32Bit_ASM/X87/invalid_infinity_fsubr_infinity.asm b/unittests/32Bit_ASM/X87/invalid_infinity_fsubr_infinity.asm new file mode 100644 index 000000000..b29b48098 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_infinity_fsubr_infinity.asm @@ -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 \ No newline at end of file diff --git a/unittests/32Bit_ASM/X87/invalid_infinity_mul_zero.asm b/unittests/32Bit_ASM/X87/invalid_infinity_mul_zero.asm new file mode 100644 index 000000000..76a4648d1 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_infinity_mul_zero.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_infinity_ops.asm b/unittests/32Bit_ASM/X87/invalid_infinity_ops.asm new file mode 100644 index 000000000..c4ec61bdb --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_infinity_ops.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_infinity_sub_infinity.asm b/unittests/32Bit_ASM/X87/invalid_infinity_sub_infinity.asm new file mode 100644 index 000000000..6323635c7 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_infinity_sub_infinity.asm @@ -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 \ No newline at end of file diff --git a/unittests/32Bit_ASM/X87/invalid_neg_infinity_sub_neg_infinity.asm b/unittests/32Bit_ASM/X87/invalid_neg_infinity_sub_neg_infinity.asm new file mode 100644 index 000000000..a33886df0 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_neg_infinity_sub_neg_infinity.asm @@ -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 \ No newline at end of file diff --git a/unittests/32Bit_ASM/X87/invalid_reduced_precision.asm b/unittests/32Bit_ASM/X87/invalid_reduced_precision.asm new file mode 100644 index 000000000..0a1a6599a --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_reduced_precision.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_simple_test.asm b/unittests/32Bit_ASM/X87/invalid_simple_test.asm new file mode 100644 index 000000000..5d87723b8 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_simple_test.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/invalid_sqrt_negative.asm b/unittests/32Bit_ASM/X87/invalid_sqrt_negative.asm new file mode 100644 index 000000000..86fa37437 --- /dev/null +++ b/unittests/32Bit_ASM/X87/invalid_sqrt_negative.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/valid_fist_16bit.asm b/unittests/32Bit_ASM/X87/valid_fist_16bit.asm new file mode 100644 index 000000000..a62388e88 --- /dev/null +++ b/unittests/32Bit_ASM/X87/valid_fist_16bit.asm @@ -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 diff --git a/unittests/32Bit_ASM/X87/valid_operation.asm b/unittests/32Bit_ASM/X87/valid_operation.asm new file mode 100644 index 000000000..5bb2489b4 --- /dev/null +++ b/unittests/32Bit_ASM/X87/valid_operation.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_div_zero.asm b/unittests/ASM/X87/invalid_div_zero.asm new file mode 100644 index 000000000..e5e2610f3 --- /dev/null +++ b/unittests/ASM/X87/invalid_div_zero.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fcos_infinity.asm b/unittests/ASM/X87/invalid_fcos_infinity.asm new file mode 100644 index 000000000..42b5c7af3 --- /dev/null +++ b/unittests/ASM/X87/invalid_fcos_infinity.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fist_nan.asm b/unittests/ASM/X87/invalid_fist_nan.asm new file mode 100644 index 000000000..395d37333 --- /dev/null +++ b/unittests/ASM/X87/invalid_fist_nan.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fist_overflow.asm b/unittests/ASM/X87/invalid_fist_overflow.asm new file mode 100644 index 000000000..9c7418b12 --- /dev/null +++ b/unittests/ASM/X87/invalid_fist_overflow.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fist_overflow_16bit.asm b/unittests/ASM/X87/invalid_fist_overflow_16bit.asm new file mode 100644 index 000000000..45f20b172 --- /dev/null +++ b/unittests/ASM/X87/invalid_fist_overflow_16bit.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fist_overflow_32bit.asm b/unittests/ASM/X87/invalid_fist_overflow_32bit.asm new file mode 100644 index 000000000..55c4d3dc0 --- /dev/null +++ b/unittests/ASM/X87/invalid_fist_overflow_32bit.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fist_overflow_64bit.asm b/unittests/ASM/X87/invalid_fist_overflow_64bit.asm new file mode 100644 index 000000000..b7f1dec87 --- /dev/null +++ b/unittests/ASM/X87/invalid_fist_overflow_64bit.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fprem_infinity.asm b/unittests/ASM/X87/invalid_fprem_infinity.asm new file mode 100644 index 000000000..959da8ec8 --- /dev/null +++ b/unittests/ASM/X87/invalid_fprem_infinity.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fptan_infinity.asm b/unittests/ASM/X87/invalid_fptan_infinity.asm new file mode 100644 index 000000000..56c88ef9b --- /dev/null +++ b/unittests/ASM/X87/invalid_fptan_infinity.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fsin_infinity.asm b/unittests/ASM/X87/invalid_fsin_infinity.asm new file mode 100644 index 000000000..1df33e2da --- /dev/null +++ b/unittests/ASM/X87/invalid_fsin_infinity.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fsin_neg_infinity.asm b/unittests/ASM/X87/invalid_fsin_neg_infinity.asm new file mode 100644 index 000000000..9e8550728 --- /dev/null +++ b/unittests/ASM/X87/invalid_fsin_neg_infinity.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_fsincos_infinity.asm b/unittests/ASM/X87/invalid_fsincos_infinity.asm new file mode 100644 index 000000000..533cdbd39 --- /dev/null +++ b/unittests/ASM/X87/invalid_fsincos_infinity.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_infinity_fsubr_infinity.asm b/unittests/ASM/X87/invalid_infinity_fsubr_infinity.asm new file mode 100644 index 000000000..b0958d987 --- /dev/null +++ b/unittests/ASM/X87/invalid_infinity_fsubr_infinity.asm @@ -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 \ No newline at end of file diff --git a/unittests/ASM/X87/invalid_infinity_mul_zero.asm b/unittests/ASM/X87/invalid_infinity_mul_zero.asm new file mode 100644 index 000000000..3175436a5 --- /dev/null +++ b/unittests/ASM/X87/invalid_infinity_mul_zero.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_infinity_ops.asm b/unittests/ASM/X87/invalid_infinity_ops.asm new file mode 100644 index 000000000..0752d0d56 --- /dev/null +++ b/unittests/ASM/X87/invalid_infinity_ops.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_infinity_sub_infinity.asm b/unittests/ASM/X87/invalid_infinity_sub_infinity.asm new file mode 100644 index 000000000..472e6a45f --- /dev/null +++ b/unittests/ASM/X87/invalid_infinity_sub_infinity.asm @@ -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 \ No newline at end of file diff --git a/unittests/ASM/X87/invalid_neg_infinity_sub_neg_infinity.asm b/unittests/ASM/X87/invalid_neg_infinity_sub_neg_infinity.asm new file mode 100644 index 000000000..09b645377 --- /dev/null +++ b/unittests/ASM/X87/invalid_neg_infinity_sub_neg_infinity.asm @@ -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 \ No newline at end of file diff --git a/unittests/ASM/X87/invalid_reduced_precision.asm b/unittests/ASM/X87/invalid_reduced_precision.asm new file mode 100644 index 000000000..dbadfbe18 --- /dev/null +++ b/unittests/ASM/X87/invalid_reduced_precision.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_simple_test.asm b/unittests/ASM/X87/invalid_simple_test.asm new file mode 100644 index 000000000..154dba371 --- /dev/null +++ b/unittests/ASM/X87/invalid_simple_test.asm @@ -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 diff --git a/unittests/ASM/X87/invalid_sqrt_negative.asm b/unittests/ASM/X87/invalid_sqrt_negative.asm new file mode 100644 index 000000000..cc993d495 --- /dev/null +++ b/unittests/ASM/X87/invalid_sqrt_negative.asm @@ -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 diff --git a/unittests/ASM/X87/valid_fist_16bit.asm b/unittests/ASM/X87/valid_fist_16bit.asm new file mode 100644 index 000000000..e0645ead1 --- /dev/null +++ b/unittests/ASM/X87/valid_fist_16bit.asm @@ -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 diff --git a/unittests/ASM/X87/valid_operation.asm b/unittests/ASM/X87/valid_operation.asm new file mode 100644 index 000000000..c9ea0ff32 --- /dev/null +++ b/unittests/ASM/X87/valid_operation.asm @@ -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