Write to word general-purpose registers
(wr16 reg val x86) → x86
Note Intel Vol. 1 Sec. 3.4.1.1 p. 3-17, which says the following about 64-bit mode:
8-bit and 16-bit operands generate an 8-bit or 16-bit result. The upper 56 or 48 bits (respectively) of the destination general-purpose register are not modified by the operation.
This is also confirmed by AMD manual, Jun'15, Vol. 3, App. B.1, under ‘No Extension of 8-Bit and 16-Bit Results’.
In 32-bit mode, the upper 32 bits are undefined, as specified by the following quote from the same page as above:
Because the upper 32 bits of 64-bit general-purpose registers are undefined in 32-bit modes, the upper 32 bits of any general-purpose register are not preserved when switching from 64-bit mode to a 32-bit mode (to protected mode or compatibility mode). Software must not depend on these bits to maintain a value after a 64-bit to 32-bit mode switch.
This function is used both in 64-bit mode and in 32-bit mode. Since in 32-bit mode the high 32 bits of general-purpose registers are not accessible, it is fine for this function to leave those bits unchanged, as opposed to, for example, setting them to undefined values as done by the semantic functions of certain instructions for certain flags. The switching from 32-bit mode to 64-bit mode (when modeled) will set the high 32 bits of general-purpose registers to undefined values.
Function:
(defun wr16$inline (reg val x86) (declare (xargs :stobjs (x86))) (declare (type (unsigned-byte 4) reg) (type (unsigned-byte 16) val)) (let ((qword (the (signed-byte 64) (rgfi reg x86)))) (!rgfi reg (n64-to-i64 (mbe :logic (part-install val (part-select qword :low 0 :width 64) :low 0 :width 16) :exec (the (unsigned-byte 64) (logior (the (unsigned-byte 64) (logand qword 18446744073709486080)) val)))) x86)))
Theorem:
(defthm x86p-wr16 (implies (x86p x86) (x86p (wr16 reg val x86))))