Browse Source

Implement instructions commiss & ucomiss

David Bullado 5 years ago
parent
commit
700bd0e6e7
4 changed files with 172 additions and 27 deletions
  1. 29 0
      src/cpu.js
  2. 41 7
      src/instructions.js
  3. 59 0
      tests/nasm/comiss.asm
  4. 43 20
      tests/nasm/ucomiss.asm

+ 29 - 0
src/cpu.js

@@ -10,6 +10,21 @@ var CPU_LOG_VERBOSE = false;
 // http://ref.x86asm.net/geek32.html
 
 
+// exception bits in the MXCSR Register
+var
+    /** @const */
+    CPU_EX_P = 1 << 5,
+    /** @const */
+    CPU_EX_U = 1 << 4,
+    /** @const */
+    CPU_EX_O = 1 << 3,
+    /** @const */
+    CPU_EX_Z = 1 << 2,
+    /** @const */
+    CPU_EX_D = 1 << 1,
+    /** @const */
+    CPU_EX_I = 1 << 0;
+
 /** @constructor */
 function CPU(bus)
 {
@@ -4761,6 +4776,20 @@ CPU.prototype.decr_ecx_asize = function()
     return this.is_asize_32() ? --this.reg32s[reg_ecx] : --this.reg16[reg_cx];
 };
 
+CPU.prototype.invalid_arithmatic = function()
+{
+    this.mxcsr |= CPU_EX_I;
+};
+
+CPU.prototype.is_SNaN32 = function(value)
+{
+    let exponent = (value >>> 23) & 0xFF;
+    let most_significand = (value >>> 22) & 1;
+    let less_significand = (value >>> 0) & 0x3FFFFF;
+
+    return exponent === 0xFF && most_significand === 0 && less_significand > 0;
+};
+
 // Closure Compiler's way of exporting
 if(typeof window !== "undefined")
 {

+ 41 - 7
src/instructions.js

@@ -2197,13 +2197,11 @@ t[0x2E] = cpu => {
     cpu.task_switch_test_mmx();
     cpu.read_modrm_byte();
 
-    let source = cpu.read_xmm128s();
-    let dest = cpu.read_xmm_mem128s();
-    let source1 = new Float32Array(source.buffer);
-    let source2 = new Float32Array(dest.buffer);
+    let source1 = cpu.read_xmm128s();
+    let source2 = cpu.read_xmm_mem128s();
 
-    let x = source1[0];
-    let y = source2[0];
+    let x = (new Float32Array(source1.buffer))[0];
+    let y = (new Float32Array(source2.buffer))[0];
 
     cpu.flags_changed &= ~(1 | flag_parity | flag_zero);
     cpu.flags &= ~(1 | flag_parity | flag_zero);
@@ -2222,9 +2220,45 @@ t[0x2E] = cpu => {
     else
     {
         cpu.flags |= 1 | flag_parity | flag_zero;
+
+        if (cpu.is_SNaN32(source1[0]) || cpu.is_SNaN32(source2[0])) {
+            cpu.invalid_arithmatic();
+        }
+    }
+};
+
+t[0x2F] = cpu => {
+    // comiss xmm1, xmm2/m32
+    dbg_assert((cpu.prefixes & (PREFIX_MASK_REP | PREFIX_MASK_OPSIZE)) === 0);
+    cpu.task_switch_test_mmx();
+    cpu.read_modrm_byte();
+
+    let source1 = cpu.read_xmm128s();
+    let source2 = cpu.read_xmm_mem128s();
+
+    let x = (new Float32Array(source1.buffer))[0];
+    let y = (new Float32Array(source2.buffer))[0];
+
+    cpu.flags_changed &= ~(1 | flag_parity | flag_zero);
+    cpu.flags &= ~(1 | flag_parity | flag_zero);
+
+    if(x > y)
+    {
+    }
+    else if(y > x)
+    {
+        cpu.flags |= 1;
+    }
+    else if(x === y)
+    {
+        cpu.flags |= flag_zero;
+    }
+    else
+    {
+        cpu.flags |= 1 | flag_parity | flag_zero;
+        cpu.invalid_arithmatic();
     }
 };
-t[0x2F] = cpu => { cpu.unimplemented_sse(); };
 
 // wrmsr
 t[0x30] = cpu => {

+ 59 - 0
tests/nasm/comiss.asm

@@ -0,0 +1,59 @@
+global _start
+
+section .data
+	align 16
+controlword:
+	dw	0
+dwordmxcsr:
+	dw	0
+dword0:
+	dd	1000.0
+dword1:
+	dd	5.0
+dword2:
+	dd	3000.0
+dwSNaN:
+	dd	__SNaN__
+dwQNaN:
+	dd	__QNaN__
+maskEFLAGS:
+	dd	0x45
+
+; Moves EFLAGS into specified register
+%macro moveflags 1
+	pushf
+	pop			eax
+	and			eax, [maskEFLAGS]
+	movd		%1, eax
+%endmacro
+
+%include "header.inc"
+
+	movd		xmm0, [dword0]
+	; Equal
+	comiss		xmm0, [dword0]
+	moveflags	mm0				; [ZF] = 100000
+	; Less than
+	comiss		xmm0, [dword1]
+	moveflags	mm1				; [CF] = 000001
+	; Greater than
+	comiss		xmm0, [dword2]
+	moveflags	mm2				; [] = 000000
+
+	; Unordered: Quiet NaN
+	movd		xmm1, [dwQNaN]
+	ucomiss		xmm0, xmm1
+	moveflags	mm3				; [ZF][PF][CF] = 100101
+	; Check #I exception
+	stmxcsr		[dwordmxcsr]
+	movd		mm4, [dwordmxcsr]
+
+	; Unordered: Signaling NaN
+	movd		xmm1,[dwSNaN]
+	ucomiss		xmm0, xmm1
+	moveflags	mm5				; [ZF][PF][CF] = 100101
+	; Check #I exception
+	stmxcsr		[dwordmxcsr]
+	movd		mm6, [dwordmxcsr]
+
+%include "footer.inc"

+ 43 - 20
tests/nasm/ucomiss.asm

@@ -2,35 +2,58 @@ global _start
 
 section .data
 	align 16
+controlword:
+	dw 0
+dwordmxcsr:
+	dw 0
 dword0:
 	dd	1000.0
 dword1:
 	dd	5.0
 dword2:
 	dd	3000.0
-dwNaN:
-	dd	__NaN__
-maskeflags
-    dd  0x45
+dwSNaN:
+	dd	__SNaN__
+dwQNaN:
+	dd	__QNaN__
+maskEFLAGS:
+	dd  0x45
 
-%macro  moveflags 1
-    pushf
-    mov         eax, [esp]
-    and         eax, [maskeflags]
-    movd        %1, eax
+; Moves EFLAGS into specified register
+%macro moveflags 1
+	pushf
+	pop			eax
+	and			eax, [maskEFLAGS]
+	movd		%1, eax
 %endmacro
 
 %include "header.inc"
-    
-    movd        xmm0, [dword0]
-    ucomiss     xmm0, [dword0]
-    moveflags   mm0
-    ucomiss     xmm0, [dword1]
-    moveflags   mm1
-    ucomiss     xmm0, [dword2]
-    moveflags   mm2
-    movd        xmm1, [dwNaN]
-    ucomiss     xmm1, xmm0
-    moveflags   mm3
+
+	movd		xmm0, [dword0]
+	; Equal
+	ucomiss		xmm0, [dword0]
+	moveflags	mm0				; [ZF] = 100000
+	; Less than
+	ucomiss		xmm0, [dword1]
+	moveflags	mm1				; [CF] = 000001
+	; Greater than
+	ucomiss		xmm0, [dword2]
+	moveflags	mm2				; [] = 000000
+
+	; Unordered: Quiet NaN
+	movd		xmm1, [dwQNaN]
+	ucomiss		xmm0, xmm1
+	moveflags	mm3				; [ZF][PF][CF] = 100101
+	; Check #I exception
+	stmxcsr		[dwordmxcsr]
+	movd		mm4, [dwordmxcsr]
+
+	; Unordered: Signaling NaN
+	movd		xmm1, [dwSNaN]
+	ucomiss		xmm0, xmm1
+	moveflags	mm5				; [ZF][PF][CF] = 100101
+	; Check #I exception
+	stmxcsr		[dwordmxcsr]
+	movd		mm6, [dwordmxcsr]
 
 %include "footer.inc"