diff --git a/docs/pcjs/demos/components.xsl b/docs/pcjs/demos/components.xsl
index a9b53c287..37a2600b6 100644
--- a/docs/pcjs/demos/components.xsl
+++ b/docs/pcjs/demos/components.xsl
@@ -454,47 +454,45 @@
-
-
-
- :
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- desc:''
-
- ,href:''
-
+ *
+
+ :
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ desc:''
+
+ ,href:''
-
-
-
-
-
-
-
-
-
- ;
-
-
+
+
+
-
-
+
+
+
+
+
+ ;
+
+
+
+
+
diff --git a/modules/pcjs/lib/x86func.js b/modules/pcjs/lib/x86func.js
index 5ec885bfa..48ffe82c0 100644
--- a/modules/pcjs/lib/x86func.js
+++ b/modules/pcjs/lib/x86func.js
@@ -2883,57 +2883,77 @@ X86.fnSGDT = function(dst, src)
X86.opInvalid.call(this);
} else {
/*
- * We don't need to setShort() the first word of the operand, because the ModRM group decoder that
- * calls us does that automatically with the value we return (dst).
+ * We don't need to set the first word of the operand, because the ModRM group decoder that calls us
+ * does that automatically with the value we return (dst).
*/
dst = this.addrGDTLimit - this.addrGDT;
this.assert(!(dst & ~0xffff));
- /*
- * We previously left the 6th byte of the target operand "undefined". But it turns out we have to set
- * it to *something*, because there's processor detection in PC-DOS 7.0 (at least in the SETUP portion)
- * that looks like this:
- *
- * 145E:4B84 9C PUSHF
- * 145E:4B85 55 PUSH BP
- * 145E:4B86 8BEC MOV BP,SP
- * 145E:4B88 B80000 MOV AX,0000
- * 145E:4B8B 50 PUSH AX
- * 145E:4B8C 9D POPF
- * 145E:4B8D 9C PUSHF
- * 145E:4B8E 58 POP AX
- * 145E:4B8F 2500F0 AND AX,F000
- * 145E:4B92 3D00F0 CMP AX,F000
- * 145E:4B95 7511 JNZ 4BA8
- * 145E:4BA8 C8060000 ENTER 0006,00
- * 145E:4BAC 0F0146FA SGDT [BP-06]
- * 145E:4BB0 807EFFFF CMP [BP-01],FF
- * 145E:4BB4 C9 LEAVE
- * 145E:4BB5 BA8603 MOV DX,0386
- * 145E:4BB8 7503 JNZ 4BBD
- * 145E:4BBA BA8602 MOV DX,0286
- * 145E:4BBD 89163004 MOV [0430],DX
- * 145E:4BC1 5D POP BP
- * 145E:4BC2 9D POPF
- * 145E:4BC3 CB RETF
- *
- * This code is expecting SGDT on an 80286 to set the 6th "undefined" byte to 0xFF.
- *
- * The 80386 adds an additional wrinkle: the 6th byte must be 0x00 if the OPERAND size is 2, whereas
- * it must passed through if the OPERAND size is 4.
- *
- * In addition, when the OPERAND size is 4, the ModRM group decoder will call setLong(dst) rather than
- * setShort(dst); we could fix that by forcing the dataSize to 2, but it seems simpler to set the high
- * bits (16-31) of dst to match the low bits (0-15) of addr, so that the caller will harmlessly rewrite
- * what we already wrote with the setLong() below.
- */
+
var addr = this.addrGDT;
if (this.model == X86.MODEL_80286) {
+ /*
+ * We previously left the 6th byte of the target operand "undefined". But it turns out we have to set
+ * it to *something*, because there's processor detection in PC-DOS 7.0 (at least in the SETUP portion)
+ * that looks like this:
+ *
+ * 145E:4B84 9C PUSHF
+ * 145E:4B85 55 PUSH BP
+ * 145E:4B86 8BEC MOV BP,SP
+ * 145E:4B88 B80000 MOV AX,0000
+ * 145E:4B8B 50 PUSH AX
+ * 145E:4B8C 9D POPF
+ * 145E:4B8D 9C PUSHF
+ * 145E:4B8E 58 POP AX
+ * 145E:4B8F 2500F0 AND AX,F000
+ * 145E:4B92 3D00F0 CMP AX,F000
+ * 145E:4B95 7511 JNZ 4BA8
+ * 145E:4BA8 C8060000 ENTER 0006,00
+ * 145E:4BAC 0F0146FA SGDT [BP-06]
+ * 145E:4BB0 807EFFFF CMP [BP-01],FF
+ * 145E:4BB4 C9 LEAVE
+ * 145E:4BB5 BA8603 MOV DX,0386
+ * 145E:4BB8 7503 JNZ 4BBD
+ * 145E:4BBA BA8602 MOV DX,0286
+ * 145E:4BBD 89163004 MOV [0430],DX
+ * 145E:4BC1 5D POP BP
+ * 145E:4BC2 9D POPF
+ * 145E:4BC3 CB RETF
+ *
+ * This code is expecting SGDT on an 80286 to set the 6th "undefined" byte to 0xFF, so that's what we do.
+ */
addr |= (0xff000000|0);
}
else if (this.model >= X86.MODEL_80386) {
+ /*
+ * The 80386 added another wrinkle: Intel's documentation claimed that the 6th byte is either set to zero
+ * or the high byte of the BASE field, depending on the OPERAND size; from the "INTEL 80386 PROGRAMMER'S
+ * REFERENCE MANUAL 1986":
+ *
+ * The LIMIT field of the [GDTR or IDTR] register is assigned to the first word at the effective address.
+ * If the operand-size attribute is 32 bits, the next three bytes are assigned the BASE field of the
+ * register, and the fourth byte is written with zero. The last byte is undefined. Otherwise, if the
+ * operand-size attribute is 16 bits, the next 4 bytes are assigned the 32-bit BASE field of the register.
+ *
+ * However, Intel obviously meant the reverse (ie, that the BASE field is truncated when using a 16-bit
+ * OPERAND size, not when using a 32-bit OPERAND size).
+ *
+ * UPDATE: Thanks to Michal Necasek, we now know that the: "386 in reality does not pay attention to the
+ * operand size (despite Intel's claims to the contrary). In fact Windows 3.11/Win32s relies on it -- at least
+ * in some configurations, it will execute SGDT in 16-bit code and will crash if all 6 bytes aren't stored."
+ */
if (this.sizeData == 2) {
- addr &= 0x00ffffff;
+ /*
+ * Based on the above information, we no longer mask the 6th byte on the 80386 when the OPERAND size is 2.
+ *
+ * addr &= 0x00ffffff;
+ */
} else {
+ /*
+ * When the OPERAND size is 4, our ModRM group decoder will call setLong(dst) rather than setShort(dst);
+ * we could fix that by calling setDataSize(2), but it seems safer/simpler to set the high bits (16-31)
+ * of dst to match the low bits (0-15) of addr, so that the caller will harmlessly rewrite what we are
+ * already writing with the setLong() below.
+ */
dst |= (addr << 16);
}
}
@@ -3277,8 +3297,8 @@ X86.fnSIDT = function(dst, src)
X86.opInvalid.call(this);
} else {
/*
- * We don't need to setShort() the first word of the operand, because the ModRM group decoder that calls
- * us does that automatically with the value we return (dst).
+ * We don't need to set the first word of the operand, because the ModRM group decoder that calls us
+ * does that automatically with the value we return (dst).
*/
dst = this.addrIDTLimit - this.addrIDT;
this.assert(!(dst & ~0xffff));
@@ -3292,7 +3312,11 @@ X86.fnSIDT = function(dst, src)
}
else if (this.model >= X86.MODEL_80386) {
if (this.sizeData == 2) {
- addr &= 0x00ffffff;
+ /*
+ * Based on the SGDT information above, we no longer mask the 6th byte when the OPERAND size is 2.
+ *
+ * addr &= 0x00ffffff;
+ */
} else {
dst |= (addr << 16);
}