The opcode 0Fh 55h is just an arbitrary opcode byte combination that is not implemented in the Nx586 by hardware or microcode. When encountering this byte combination, the Nx586 CPU raises an undefined opcode exception. But all exceptions are handled by hypercode, and hypercode treats this exception with these opcode bytes in a special way. Depending on register values, it does some work and if successful, returns to normal operation after these bytes, quenching the exception. So from the outside, it looks like a very special Opcode, but it is only emulated by hypercode and is in fact an interface into hypercode.
There are two calling conventions associated with NXOP. The first expects ESI=0FFFF0000h and the second expects SI=0B0xxh on entry, where xx enumerates the desired function. If ESI isn't 0FFFF0000h and SI isn't 0B0xxh or xx isn't in the supported range, an "illegal instruction" exception occurs.
Some functions do work differently or not at all on different hypercode versions. If not mentioned otherwise, it works for all of the hypercode versions known to me (VL: 033s, 033v and 033w; PCI: 034i, 034n, 034p and 034q).
Note: "E:" means "on entry" and "R:" means "on return"
Seems this function was the only one supported in very early hypercode versions and was retained for backward compatibility, and the SI=0B0xxh calling convention was introduced later. Works in all privilege levels.
E:-
R: EAX AH=15h, AL=system type: 03h=VL, 04h=PCI, 05h=??, 06h=??
EBX BL=second level cache size (in 64K): 04h=256K, 10h=1M
ECX result of hypermode instruction which reads in system type
EDX hypercode version as 4-char string, e.g. 71343330h = "034q"
The system type seems to originate from the mainboard. It must be from some pins on the socket. It seems that VL boards always return 0 on the hypercode instruction. Hypercode then uses the constants ECX=03000000h and EAX=00001503h (or, on 033s if some bits in an internal register are set (don't know what that is) ECX=05000000h and EAX=00001505h) instead. PCI boards return a value, which will be returned complemented in ECX. The uppermost byte of ECX will be used as lowbyte of system type. The rest of EAX is a constant (000015xxh). CPUID implementation uses the value read in by said hypermode instruction, takes the uppermost byte, shifts it right by 24 bits, inverts it, and uses the constant 000005xxh for the other 3 bytes. Thus, on a PCI system, the lowbyte of level 1 EAX (the model/stepping value) returned by CPUID is the same as the system type byte of API function 00h, while on a VL system, the model/stepping value of CPUID is 0FFh but the system type is constant 03h.
On entry, the low byte of SI selects the desired function. Depending on function and hypercode version, the following privilege level checks are done:
If a privilege level check fails, a "general protection" exception occurs.
On return (marked with R: below), if successful, register AH is 0 and the carry flag (CF) is clear. On error, register AH contains an error code and CF is set. All error codes have the uppermost bit set. Apart from values explicitely returned in registers, no other (user visible) registers are modified.
Error codes:
81h invalid argument
83h selftest failed
Some functions use AL to select a subfunction. Generally, unsupported subfunctions are rejected with error code 81h, but because of a bug in the check code, subfunction numbers 80h-0FFh are not rejected. Please don't try these, because results are unpredictable. Hypercode does:
cmp al,maximum allowed subfunction jg
Instead of:
cmp al,maximum allowed subfunction ja
It's a signed/unsigned comparison pitfall.
This is the successor of the function with calling convention ESI=0FFFF0000h.
E:-
R: AH=0 and CF clear
EBX see calling convention ESI=0FFFF0000h
ECX see EAX on calling convention ESI=0FFFF0000h
EDX see calling convention ESI=0FFFF0000h
NexGen's flash update programs use this function. VL update checks for CL=03h (VL system), PCI update checks for CL=04h (PCI system). PCI update also checks for CL=06h (is that a newer PCI system with P120/P130 CPUs and 035 series hypercode?) and if so tells user "no update needed".
E:-
R: AH=0 and CF clear
E:-
R: AH=0 and CF clear
E:-
R: AH=0 and CF clear
AL cache state (0=off or 1=on)
NexGen's flash update programs use this function.
E:-
R: AH=0 and CF clear
E:-
R: AH=0 and CF clear
Don't use this function to control/check caches, use function 01h instead. My NexGen crashes if I want to switch off caches via this function. Both functions have a common subroutine, but this function does not change internal configuration register bits. I don't know yet for what this is useful.
These registers can't be read back, so hypercode keeps a copy in memory which is also written.
E:-
R: AH=0 and CF clear
Write mask 0FFFFF000h to register at 1E400000h and 40000000h to register at 1C400000h.
E: EBX address
R: AH=0 and CF clear if EBX was ok, else AH=81h and CF set
Compute mask as 0FFFFF800h << AL and check that EBX has at least one bit set in that mask but no bits outside of that mask. Write that mask to register at 1E400000h and write EBX to register at 1C400000h.
E:-
R: AL=00h if memory copy of register 1E400000h is 0FFFFF000h and memory copy of register 1C400000h is 40000000h.
AL=01h-0Ch depending on mask in memory copy of register 1E400000h and
EBX address
I don't know yet what it does, but I think it could be some kind of memory type range register or it controls cacheability of memory areas.
Same as function 03h, but operates on registers 1E800000h and 1C800000h instead.
Has been same as function 03h, but operates on registers 1E000000h and 1C000000h instead, but is now defunct, always returns error 81h.
These registers can't be read back, so hypercode keeps a copy in memory which is also written.
E: EBX
R: AH=0 and CF clear
Writes EBX & 0FFE00000h to register at 1D000000h.
E: EBX
R: AH=0 and CF clear
If bit 21 of EBX is clear, writes EBX & 0FFE00000h to register at 1D000000h.
If bit 21 of EBX is set, writes (EBX & 0FFC00000h)+00400000h to register at 1D000000h and also writes mask 0FFE00000h to register at 1E000000h and EBX & 0FFE00000h to register at 1C000000h (similar to function 03h).
E:-
R: EBX, AH=0 and CF clear
Return memory copy of register 1D000000h in EBX.
(similar to function 03h)
These registers can't be read back, so hypercode keeps a copy in memory which is also written.
E:-
R: AH=0 and CF clear
Write mask 0FFFFE000h to register at 1EC00000h and 00008C00h to register at 1CC00000h.
E:-
R: AH=0 and CF clear
Write mask 0FFFFE000h to register at 1EC00000h and 00008000h to register at 1CC00000h.
E:-
R: AH=0 and CF clear
AL=00h if memory copy of register 1CC00000h is 00008C00h.
AL=01h if memory copy of register 1CC00000h is 00008000h.
These registers can't be read back, so hypercode keeps a copy in memory which is also written.
E: EBX, ECX
R: AH=0 and CF clear
If bit 12 is set, 0F000h is or'd to both EBX and ECX (that means, a 13-bit wide signed value is sign-extended to 16 bits). Then EBX is or'd to ECX and both values are <<16 (shifted into the high word). Then EBX is written to register at 18000000h and ECX is written to register at 1A000000h.
E:-
R: EBX, ECX, AH=0 and CF clear
The memory copies of registers at 18000000h and 1A000000h are >>16 (shifted into the low word), & 1FFFh (truncated to 13 bits) and then returned in EBX and ECX respectively.
E:-
R: AH=0 and CF clear if ok, else AH=83h and CF set
Only works on VL, because test routine is broken (willingly?) on PCI and always detects first level cache error.
E:-
R: if both caches are ok:
AH=0 and CF clear
if first level cache ok but second level cache faulty:
AH=83h and CF set
DX=some counter (don't know exactly)
EBX=test pattern written, ECX=faulty value read back, EDI=error location
if first level cache faulty:
no return! outputs 0FFh/0CAh ("CA" stands for "cache") cyclically on diagnostic port (80h)
E: CX=new lowword of h_mode
only bit 7 of lowword of h_mode has some effect, the rest is ignored
0= alternate instructions off (386 instructions only)
1= alternate instructions on (all 386 + user mode 486 instructions)
R: AH=0 and CF clear
Note: If hypercode version supports CPUID at all, it is always supported independent of this setting.
E:-
R: AH=0 and CF clear, ECX=h_mode
Bit 7 of h_mode is alternate instructions
Highword of h_mode is used differently in various contexts of hypercode.
E: CL=offset, CH=x (preferrably 0)
R: AH=0 and CF clear, CH=old CH or'd with CMOS-value
Version 034i requires CPL0 while versions 034n, 034p and 034q allow all privilege levels.
E:-
R: AH=0 and CF clear,
EBX=CFG0, ECX=CFG1 (configuration register 0 and 1),
EDX=FCFG (floating point coprocessor configuration register)
EDI=CCFG (cache configuration register)
E:-
R: AH=0 and CF clear,
EBX, ECX, EDX, and EDI=opcode mask register (2x64 bits)
E:-
R: AH=0 and CF clear,
EBX=memory copy of register at 12000000h
ECX=memory copy of register at 12400000h
EDX=memory copy of register at 12800000h
EDI=memory copy of register at 12C00000h
E:-
R: AH=0 and CF clear
Enables EFL.AC toggle and sets bit 7 of h_mode (see function 0Bh).
E:-
R: AH=0 and CF clear
Disables EFL.AC toggle and clears bit 7 of h_mode (see function 0Bh).
Note: NexGen system tools WINID20 und IDON/IDOFF use subfunctions 03h and 04h.
E: CL=0 MOV reg/mem to/from segreg emulation off
CL<>0 MOV reg/mem to/from segreg emulation on
R: AH=0 and CF clear
Note: NexGen VL system tools EXTON/EXTOFF use this subfunc.
Author: Herbert Oppmann (![]() |
updated: 2022-11-13 |