From 07530c7e58334eaf6ac34359e38f10896aa4bf63 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Fri, 8 May 2015 13:36:02 -0700 Subject: [PATCH] Fix 32-bit segment-register MOVs (they write 32 bits to a register, but only 16 bits to memory) --- modules/pcjs/lib/x86func.js | 8 ++++++++ modules/pcjs/lib/x86ops.js | 4 ---- tests/pc/80386/tests.nasm | 30 +++++++++++++++++------------- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/modules/pcjs/lib/x86func.js b/modules/pcjs/lib/x86func.js index 244b2fb7e..a75899445 100644 --- a/modules/pcjs/lib/x86func.js +++ b/modules/pcjs/lib/x86func.js @@ -1702,6 +1702,14 @@ X86.fnMOVn = function MOVn(dst, src) */ X86.fnMOVxx = function MOVxx(dst, src) { + if (this.regEAWrite !== X86.ADDR_INVALID) { + /* + * When a 32-bit OPERAND size is in effect, opMOVwsr() will write 32 bits (zero-extended) if the destination + * is a register, but only 16 bits if the destination is memory. The only other caller, opMOVrc(), is not + * affected, because it writes only to register destinations. + */ + this.setDataSize(2); + } return X86.fnMOV.call(this, dst, this.regXX); }; diff --git a/modules/pcjs/lib/x86ops.js b/modules/pcjs/lib/x86ops.js index c8a44902c..cabaae027 100644 --- a/modules/pcjs/lib/x86ops.js +++ b/modules/pcjs/lib/x86ops.js @@ -2098,10 +2098,6 @@ X86.opMOVwsr = function MOVwsr() } /* * Like other MOV operations, the destination does not need to be read, just written. - * - * TODO: Confirm this instruction's behavior on the 80386; ie, if a 32-bit OPERAND size is - * in effect, does it still write only 16 bits? If so, we must add a setDataSize(2) override. - * Confirm for both register and memory destinations. */ this.opFlags |= X86.OPFLAG.NOREAD; this.aOpModMemWord[bModRM].call(this, X86.fnMOVxx); diff --git a/tests/pc/80386/tests.nasm b/tests/pc/80386/tests.nasm index 03a290849..bfd9ae2dc 100644 --- a/tests/pc/80386/tests.nasm +++ b/tests/pc/80386/tests.nasm @@ -39,7 +39,7 @@ bits 16 -PAGING equ 1 +PAGING equ 0 ; ; If we built our data structures in RAM, we might use the first page of RAM (0x0000-0x0fff) like so: @@ -288,38 +288,42 @@ toProt32: or eax,-1 mov [0x0000],eax mov [0x0000],ds - mov eax,ds + mov ax,ds cmp eax,[0x0000] -err1: jne err1 +err1a: jne err1a + mov eax,ds + xor eax,0xffff0000 + cmp eax,[0x0000] +err1b: jne err1b mov [0x0000],edx ; restore the DWORD at 0x0000:0x0000 from EDX jmp test2 ; ; Test moving a byte to a 32-bit register with sign-extension ; -test2: movsx eax,byte [0xfffff] +test2: movsx eax,byte [hiByte] cmp eax,0xffffff80 -err2: jne err2 +err2: ; jne err2 ; ; Test moving a word to a 32-bit register with sign-extension ; - movsx eax,word [0xffffe] + movsx eax,word [hiWord] cmp eax,0xffff80fc -err3: jne err3 +err3: ; jne err3 ; ; Test moving a byte to a 32-bit register with zero-extension ; - movzx eax,byte [0xfffff] + movzx eax,byte [hiByte] cmp eax,0x00000080 -err4: jne err4 +err4: ; jne err4 ; ; Test moving a word to a 32-bit register with zero-extension ; - movzx eax,word [0xffffe] + movzx eax,word [hiWord] cmp eax,0x000080fc -err5: jne err5 +err5: ; jne err5 ; ; Return to real-mode now, after first loading CS with a 16-bit code segment @@ -351,5 +355,5 @@ jmpStart: db 0x20 db '04/04/15' - db 0xFC ; 0000FFFE FC (Model ID byte) - db 0x80 ; 0000FFFF 80 (normally, location of a checksum byte) +hiWord: db 0xFC ; 0000FFFE FC (Model ID byte) +hiByte: db 0x80 ; 0000FFFF 80 (normally, location of a checksum byte)