[Main | NexGen]

NXOP (Opcode 0Fh 55h)

NXOP is a hypercode interface

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"

Calling convention ESI=0FFFF0000h

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.

function: identification

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.

Calling convention SI=0B0xxh

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.

function 00h: identification

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".

function 01h: switch first and second level caches on/off

subfunc 00h: switch caches off

E:-
R: AH=0 and CF clear

subfunc 01h: switch caches on

E:-
R: AH=0 and CF clear

subfunc 0FFh: read back current setting (not supported with 033s and 033v)

E:-
R: AH=0 and CF clear
    AL cache state (0=off or 1=on)

NexGen's flash update programs use this function.

function 02h: switch first and second level caches on/off

subfunc 00h: switch caches off

E:-
R: AH=0 and CF clear

subfunc 01h: switch caches on

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.

function 03h: ?? (write internal registers)

These registers can't be read back, so hypercode keeps a copy in memory which is also written.

subfunc 00h:

E:-
R: AH=0 and CF clear

Write mask 0FFFFF000h to register at 1E400000h and 40000000h to register at 1C400000h.

subfunc 01h-0Ch:

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.

subfunc 0FFh: read back current setting (not supported on VL)

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.

function 04h: ?? (write internal registers)

Same as function 03h, but operates on registers 1E800000h and 1C800000h instead.

function 05h: ?? (write internal registers)

Has been same as function 03h, but operates on registers 1E000000h and 1C000000h instead, but is now defunct, always returns error 81h.

function 06h: ?? (write internal registers)

These registers can't be read back, so hypercode keeps a copy in memory which is also written.

VL system:

E: EBX
R: AH=0 and CF clear

Writes EBX & 0FFE00000h to register at 1D000000h.

PCI system:

subfunc <>0FFh:

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).

subfunc 0FFh: read back current setting (not supported on VL)

E:-
R: EBX, AH=0 and CF clear

Return memory copy of register 1D000000h in EBX.

function 07h: ?? (write internal registers)

(similar to function 03h)

These registers can't be read back, so hypercode keeps a copy in memory which is also written.

subfunc 00h:

E:-
R: AH=0 and CF clear

Write mask 0FFFFE000h to register at 1EC00000h and 00008C00h to register at 1CC00000h.

subfunc 01h:

E:-
R: AH=0 and CF clear

Write mask 0FFFFE000h to register at 1EC00000h and 00008000h to register at 1CC00000h.

subfunc 0FFh: read back current setting (not supported on VL)

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.

function 08h: ?? (write internal registers)

These registers can't be read back, so hypercode keeps a copy in memory which is also written.

subfunc <>0FFh (and 0FFh on VL):

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.

subfunc 0FFh: read back current setting (not supported on VL)

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.

function 09h: test hypercode checksum

E:-
R: AH=0 and CF clear if ok, else AH=83h and CF set

function 0Ah: test caches

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)

function 0Bh: set h_mode lowword (alternate instruction set)

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.

function 0Ch: read back h_mode

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.

function 0Dh: read CMOS value

E: CL=offset, CH=x (preferrably 0)
R: AH=0 and CF clear, CH=old CH or'd with CMOS-value

function 0Eh: misc (not supported on 033s and 033v)

Version 034i requires CPL0 while versions 034n, 034p and 034q allow all privilege levels.

subfunc 00h: read configuration registers

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)

subfunc 01h: get opcode mask register

E:-
R: AH=0 and CF clear,
    EBX, ECX, EDX, and EDI=opcode mask register (2x64 bits)

subfunc 02h: ?? (read internal registers)

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

subfunc 03h: EFL.AC toggle and alternate instructions on (not supported on 034i)

E:-
R: AH=0 and CF clear

Enables EFL.AC toggle and sets bit 7 of h_mode (see function 0Bh).

subfunc 04h: EFL.AC toggle and alternate instructions off (not supported on 034i)

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.

subfunc 05h: "Game assistant" (minor conflict with implementing DOS extenders) (only on 033w)

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 (email adress) updated: 2022-11-13