[Main | NexGen]

Inside the NexGen Nx586 System BIOS

VL BIOSPCI BIOS

Overview

The system BIOS of the NexGen Nx586 consists of two parts:

The hyper code runs in a special mode of the processor, hyper mode, which is described in detail in US patent 6,212,629. The usual modes of a 80386-compatible processor (real, protected, virtual 8086) are called mortal mode.
Hyper code handles processor startup and soft-reset, and features of x86 architecture which are seldom used and / or very complex. Implementation in hyper code allows corrections and additions to the behaviour of the processor with just a BIOS update, while an implementation in hardware would need a costly re-design. On serious bugs, a BIOS update can be applied to machines already sold by their users, but having to change the processor in the field is really expensive, as Intel had to find out with their Pentium FDIV bug.

The actual system BIOS can be further divided into the core BIOS code and the board specific code. The core BIOS code is produced by a BIOS company and bought by the motherboard manufacturer (OEM) in source or (more often) binary form. The OEM then writes the board specific code and links together his code with the core BIOS. Usually, a tool from the BIOS company is used to configure the BIOS for the board, compress some parts of the BIOS to save space and glue it all together to get the BIOS image.

The NexGen BIOS numbering scheme reflects all these parts mentioned above. The first four characters refer to the actual system BIOS and the following four characters refer to the hyper code:

  char position description possible values
actual system BIOS 1 board (bus) 0 or v = VL, p = PCI
2-3 AMI WINBIOS core BIOS version (see below) 05 = 11/11/92, 06 = 10/10/94
4 board specific code version some letter
hyper code 5-7 board (bus) 033 = VL, 034 = PCI
8 hyper code version some letter

The NexGen BIOS version is displayed on the screen for a short time while booting.

I have copies of the following NexGen BIOSes:

If you have any other NexGen BIOS on your board or as a file (e.g. if you did a flash EPROM update and told the update program to make a backup copy of the old BIOS), please contact me! I am especially looking for the PCI version p06y035f, because I found it via Google Groups search for the keyword NexGen.

AMI WINBIOS

For the NexGen boards, the core BIOS is the WINBIOS produced by AMI (American Megatrends, Inc.). AMI distinguished its early core BIOS versions by their respective release dates. I know of the following releases:
After 7/15/95, AMI commenced a BIOS version numbering system.

The configuration tool is called AMIBCP (AMI BIOS Configuration Program). I know of the following versions:

If you have the WBCP511 program (not the WBCP511E = the evaluation version), please contact me!

While booting, the AMI BIOS displays a version string. Here is the one for a NexGen PCI system BIOS:

51-0100-000000-00101111-101094-NXPCI-H
|| | | | | | |
|| | | | | | Keyb. BIOS Revision Level
|| | | | | BIOS type (chipset id.)
|| | | | BIOS release date
|| | | AMIBCP settings (see below)
|| | reference number (customer number)
|| version number (major/minor)
|BIOS size (128 KiB)
CPU type (586)

AMIBCP settings (0=no, 1=yes):
0  Halt on error during POST
0  Initialise CMOS RAM at every boot
1  Keyboard controller output pin 23, 24  blocked
0  Mouse support in BIOS and keyboard controller
1  Wait for in case of POST error
1  Display floppy error during POST
1  Display video error during POST
1  Display keyboard error during POST

When <Ins> (that's <Einfg> on a german keyboard) is pressed while booting, the CMOS data are ignored and three additional version information lines are displayed:

000-0-0000-00-00-0000-00-00-000
| | | | | | | | |
| | | | | | | | keyboard controller pin for
| | | | | | | | turbo switch input pin
| | | | | | | mask value to switch clock low
| | | | | | data value to switch clock low
| | | | | port address to switch clock low
| | | | mask value to switch clock high
| | | data value to switch clock high
| | port address to switch clock high
| clock switching through chipset registers (0 = no, 1 = yes)
keyboard controller pin for clock switching
000-0-0000-00-00-0000-00-00-00-0
| | | | | | | | | |
| | | | | | | | | BIOS modification number
| | | | | | | | keyboard controller pin for 82335 reset
| | | | | | | mask value for cache control (disable)
| | | | | | data value for cache control (disable)
| | | | | port address for cache control (disable)
| | | | mask value for cache control (enable)
| | | data value for cache control (enable)
| | port address for cache control (enable)
| cache control through chipset registers (0 = no, 1 = yes)
keyboard controller pin for cache control
CPU-1.01 DIM-1.70

The keyboard controller pin number (for clock switching, turbo switch input pin, and cache control) is followed by a letter (H or L) which indicates that a high signal on the pin is used to switch to H(igh) or L(ow).

As you see, a lot of the fields are not used the way AMI meant them to be by NexGen!

Layout

The following BIOS image layouts use offsets from the start of the BIOS (Flash) EPROM because this is the only scheme that works over all the BIOS image. The actual addresses at which the BIOS contents are accessed depend on the current processor mode and are mentioned in the content description.
Mode (only indicated for uncompressed code): H = hyper mode, U = unreal mode, R = real mode

BIOS image layout for VL (v06e033w)

Mode Address range Content
- 00000h - 03FFFh unused (0FFh)
H 04000h - 0FFF9h hyper code (uncompressed), unused space at end filled with 0FFh
jump to x86 reset address 0FFFF000h:0FFF0h (unreal mode) = offset 1FFF0h
  0FFFAh - 0FFFBh checksum
  0FFFCh - 0FFFFh hypercode version string ('033w')
H 10000h - 100004h jump to address 0FFFE4000h = offset 04000h (patched over AMIBIOS header)
  10004h - 1002Fh rest of AMIBIOS header, includes module table
  10030h - 12E57h module POST (Power-On Self Test, compressed)
  12E58h - 17F2Dh module Runtime (compressed)
  17F2Eh - 1C3F4h module Setup (compressed)
  1C3F5h - 1E05Ah unused (00h)
R 1E05Bh - 1E06Ah core BIOS release date, jump to address 0FE98h:005Bh = offset 1E9DBh
R/U 1E980h - 1FFFFh module Init (uncompressed)

Inside module Init

Mode Address range Content
R 1E980h - decompression code
R - real / protected mode test
R - keyboard, A20, CMOS test
R - 1FFEFh Nx586-specific: hypercode checksum, CPU signature, cache on / off, NxVL, detect speed
U 1FFF0h - 1FFFFh core BIOS release date, far jump to address 0F000h:0E05Bh = offset 1E05Bh

BIOS image layout for PCI (p06y034q)

Mode Address range Content
H 00000h - 07FFDh hyper code (most of it compressed), unused space at end filled with 0FFh
jump to x86 reset address 0FFFF000h:0FFF0h (unreal mode) = offset 1FFF0h
  07FFEh - 07FFFh word 0C34h. What for?
  08000h - 0B139h module DIM (Device Initialization Manager)
  0B13Ah - 0CA0Fh unused (00h)
  0CA10h - 0DFFFh unused (0FFh)
  0E000h - 0FFFFh ESCD (Enhanced System Configuration Data, is initially 0FFh)
H 10000h - 10004h jump to address 0FFFFFFD6h = offset 1FFD6h (patched over AMIBIOS header)
  10004h - 1002Fh rest of AMIBIOS header, includes module table
  10030h - 13779h module POST (Power-On Self Test, compressed)
  1377Ah - 1945Eh module Runtime (compressed)
  1945Fh - 1DF89h module Setup (compressed)
  1DF8Ah - 1E05Ah unused (00h)
R 1E05Bh - 1E06Ah core BIOS release date, jump to address 0FE43h:005Bh = offset 1E48Bh
  1E06Bh - 1E42Fh unused (00h)
R/U 1E430h - 1FFFFh module Init (uncompressed)

Inside module Init

Mode Address range Content
R 1E430h - 1E48Fh AMI header
R 1E490h-1EE0Fh decompression code
R 1EE10h - 1EE99h real / protected mode test
R 1EE9Ah - 1F00Fh keyboard, A20, CMOS test
R 1F010h - 1FFD5h Nx586-specific: hypercode checksum, CPU signature, cache on / off, NxMC, init i82378, detect speed
H 1FFD6h - 1FFEFh i82378: enable lower 64K of BIOS, jump to address 0FFFE0000h = offset 00000h
U 1FFF0h - 1FFFFh core BIOS release date, far jump to address 0F000h:0E05Bh = offset 1E05Bh

Nx586 Startup

After reset, the Nx586 processor starts in hyper mode at physical address 0FFFF0000h. At this address, the upper 64 KiB of the BIOS (offset 10000h) is enabled. Unfortunately, the AMI WINBIOS uses this 64 KiB bank for its own purpose, so only a single jump instruction is patched over the AMI header here and the actual hyper code is situated in the other bank.
On a VL system, the whole 128 KiB are decoded into addresses 0E0000h-0FFFFFh (top of 1 MiB) and 0FFFE0000h-0FFFFFFFFh (top of 4 GiB). On a PCI system, only the upper 64 KiB are decoded into addresses 0F0000h-0FFFFFh (top of 1 MiB), 0FFEF0000h-0FFEFFFFFh (top of 4 GiB - 1 MiB) and 0FFFF0000h-0FFFFFFFFh (top of 4 GiB). The lower 64 KiB are only mapped after some register of the Intel i82378 has been properly set up.

Therefore, on a VL system, the first instruction is a direct jump into the hyper code at address 0FFFE4000h = offset 04000h. On the PCI system instead, there is a detour to address 0FFFFFFD6h = offset 1FFD6h where the i82378 is programmed to map the lower 64 KiB of the BIOS into the address space before a jump to 0FFFE0000h = offset 00000h can be finally done.

After some tests have succeeded, hyper code copies (VL) or copies / decompresses (PCI) itself into the second level cache, bank 3. After enabling the second level cache, the copy of the hyper code gets visible at physical address 0FFFF0000h-0FFFFBFFFh (up to 48 KiB). From now on, in hyper mode, the processor can't see most of the upper 64 KiB of the BIOS (Flash) EPROM anymore! But this is no problem because in hyper mode only hyper code matters and the AMI BIOS is never looked at.

Setting up the different invisible and visible x86 registers, the Nx586 resumes to mortal mode to the x86 unreal mode reset address 0FFFF000h:0FFF0h = offset 1FFF0h. Note the BIOS EPROM is still visible in mortal mode. The first far jump reloads the CS segment descriptor cache with proper real mode values and thus ends unreal mode. Execution continues in real mode at address 0F000h:0E05Bh = offset 1E05Bh. There we find a far jump into the Init module and there a short jump which skips the decompression routine. After some basic tests and chipset initialisations, modules are decompressed into main memory as needed and excuted and we are deep inside the BIOS.

Dissecting the BIOS images

As I didn't find WBCP511.EXE for analyzing / building an 10/10/94 AMI WINBIOS, I started to write my own tool. Currently, it can display the BIOS image structure of 10/10/94 BIOSes (not only from Nx586 BIOSes) and can extract the different modules in compressed or uncompressed form. It can't build a new image now. It was written with Borland C/C++ 5.0, the executable and the sources can be downloaded here (MyBCP.zip, 46 KiB). AMI uses the LZH (Lempel Ziv Huffman) algorithm for compressing the modules.
NexGen uses a simple RLE (Run-Length Encoding) algorithm for compressing hyper code on a PCI system. Up to 48 KiB must be sized down to fit into a maximum of 32 KiB available. I also wrote a tool for this in PERL, which can be downloaded here (HYPACK.PL, 13 KiB).

Here are the textual results of these tools, the dissected files can be downloaded here (Dissected.zip, 3396 KiB).

11/11/92 AMI WINBIOS

To be done: dissect 11/11/92 AMI WINBIOS.
Looks like everything is uncompressed. Offset 00000h-03FFFh is used by ??

005q033s
005r033s
hyper code is the same as from 005q033s, 00000h-03FFFh is different from 005q033s

10/10/94 AMI WINBIOS

v06c033v
Module  Source   Dest   Comp  Uncmp  Content
--------------------------------------------
1 17F5Ch 0000h 44FCh 5D7Ah Setup
0 10030h 0000h 2DFCh 3D7Ch POST
2 12E2Ch 7500h 5130h 8B00h Runtime
3 1E980h 0000h ----- 1680h INIT
v06d033w
Module  Source   Dest   Comp  Uncmp  Content
--------------------------------------------
1 17F2Ah 0000h 44C7h 5D7Ah Setup
0 10030h 0000h 2E24h 3DA2h POST
2 12E54h 7500h 50D6h 8B00h Runtime
3 1E980h 0000h ----- 1680h INIT
v06e033w
Module  Source   Dest   Comp  Uncmp  Content
--------------------------------------------
1 17F2Eh 0000h 44C7h 5D7Ah Setup
0 10030h 0000h 2E28h 3DA8h POST
2 12E58h 7500h 50D6h 8B00h Runtime
3 1E980h 0000h ----- 1680h INIT
p06s034i
Module  Source   Dest   Comp  Uncmp  Content
--------------------------------------------
1 193AAh 0000h 4AE8h 67B8h Setup
0 10030h 0000h 3616h 4898h POST
2 13646h 6F00h 5D64h 9100h Runtime
3 1E350h 0000h ----- 1CB0h INIT
4 08000h 8000h 314Eh 49F0h DIM
p06w034n
Module  Source   Dest   Comp  Uncmp  Content
--------------------------------------------
1 193A3h 0000h 4AF2h 67C4h Setup
0 10030h 0000h 35ECh 48B8h POST
2 1361Ch 6F00h 5D87h 9100h Runtime
3 1E350h 0000h ----- 1CB0h INIT
4 08000h 8000h 313Bh 4A10h DIM
p06w034n.mc3
Module  Source   Dest   Comp  Uncmp  Content
--------------------------------------------
1 193DFh 0000h 4B02h 67D0h Setup
0 10030h 0000h 35CFh 486Eh POST
2 135FFh 6F00h 5DE0h 9100h Runtime
3 1E350h 0000h ----- 1CB0h INIT
4 08000h 8000h 313Bh 4A10h DIM
p06x034n
Module  Source   Dest   Comp  Uncmp  Content
--------------------------------------------
1 19464h 0000h 4B27h 6808h Setup
0 10030h 0000h 3745h 4B30h POST
2 13775h 6F00h 5CEFh 9100h Runtime
3 1E430h 0000h ----- 1BD0h INIT
4 08000h 8000h 313Bh 4A10h DIM
p06y034p
Module  Source   Dest   Comp  Uncmp  Content
--------------------------------------------
1 1945Fh 0000h 4B2Ah 6808h Setup
0 10030h 0000h 374Ah 4B3Ah POST
2 1377Ah 6F00h 5CE5h 9100h Runtime
3 1E430h 0000h ----- 1BD0h INIT
4 08000h 8000h 313Bh 4A10h DIM
p06y034q
Module  Source   Dest   Comp  Uncmp  Content
--------------------------------------------
1 1945Fh 0000h 4B2Ah 6808h Setup
0 10030h 0000h 374Ah 4B3Ah POST
2 1377Ah 6F00h 5CE5h 9100h Runtime
3 1E430h 0000h ----- 1BD0h INIT
4 08000h 8000h 313Bh 4A10h DIM

Dissecting hyper code

Hyper code is built from a lot of modules written in x86 assembly language and then linked together. Linking usually glues the modules tightly together so that only small traces remain in the object code that indicate a module border. If alignment to paragraph (16 Byte) or page (256 Byte) was set for a module, chances are better to identify a module border, but you still don't know their names and purpose.
Fortunately for me, NexGen included an ID in each module that contains the original assembler filename plus a version number of that file! That ID is a 0-terminated ASCII string and looks like this: first, the characters @(#), then the filename, then a white space, and at last the version. That kind of ID is automatically created by some source code control systems and there are tools to scan for those IDs. Especially SCCS (source code control system) has a "what" command that does this. There are some variations to this: sometimes, the filename includes the extension .ASM and sometimes not. Sometimes, the white space is a tab character and sometimes a sequence of space characters. Sometimes the file version is present and sometimes it is omitted. So a little bit of guesswork is needed.

As I don't have SCCS, I wrote a small tool in PERL again, which can be downloaded here (HYVERS.PL, 1 KiB). For example, its output on the hypercode of the 005Q033S BIOS is:

00521 "@(#) hcode sb.00"
00532 "@(#)hypres.asm b.03"
00F7C "@(#)033s"
01800 "@(#)retf.asm\t3.4"
01D00 "@(#)iret.asm\t3.2"
01F00 "@(#)int.asm\t3.4"
02500 "@(#)call.asm\t3.3"
02900 "@(#)excph.asm\t3.1"
02C00 "@(#)task.asm\t3.5"
03600 "@(#)iobm.asm\t2.2"
03A00 "@(#)into.asm\t3.4"
03F00 "@(#)invop.asm\t3.29"
04B00 "@(#)cache.asm\t3.7"
04E00 "@(#)decode.asm\t3.19"
06200 "@(#)sofres.asm\t2.3"
06300 "@(#)hdeb.asm\t2.11"
06C00 "@(#)io_em.asm\t2.5"
06D00 "@(#)undoc.asm\t2.3"
06E00 "@(#)emul.asm\t3.11"
07500 "@(#)emsubs.asm\t3.2"
07900 "@(#)movcr.asm\t3.1"
079A0 "@(#)nphcode.asm\t3.10"
07DA0 "@(#)fixupnp.asm\t3.4"
080E0 "@(#)fst.asm\t3.5"
08600 "@(#)fsincos.asm\t3.2"
08A80 "@(#)fpatan.asm\t3.3"
08FF0 "@(#)f2xm1.asm\t3.4"
09250 "@(#)fyl2x.asm\t3.2"
098A0 "@(#)fptan.asm\t3.2"
09B20 "@(#)fbld.asm\t3.4"
09D10 "@(#)fbstp.asm\t3.5"
09FB0 "@(#)fscale.asm\t3.3"
0A400 "@(#)fxtract.asm\t3.2"
0A580 "@(#)np_sub.asm\t3.3"
0A6A0 "@(#)np_xcp.asm\t3.3"
0A870 "@(#)np_em.asm\t3.2"
0A900 "@(#)cpustub.asm\t3.3"

Using this tool on all available hyper code versions, I created the following table that shows the progress of the hyper code source files over the different hyper code versions:

File \ Version 033s 033v 033w 034i 034n 034p 034q
CACHE 3.7 3.7 3.8 ?3.9 ?3.9 ?3.9 ?3.9
CALL 3.3 =3.4 3.4 3.4 3.4 3.4 3.4
CPUSTUB 3.3 3.3 3.3 3.3 3.3 3.4 3.4
DECODE 3.19 ?3.20 3.22 ?3.22 3.22 3.22 3.22
EMSUBS 3.2 3.2 3.2 3.2 3.2 3.2 3.2
EMUL 3.11 3.11 ?3.12 ?3.12 ?3.12 ?3.12 ?3.12
EXCPH 3.1 =3.2 3.2 3.2 3.2 3.2 3.2
F2XM1 3.4 3.4 3.4 - - - -
FBLD 3.4 3.4 3.6 3.6 3.6 3.6 3.6
FBSTP 3.5 3.5 3.12 3.11 3.11 3.12 3.12
FIXUPNP 3.4 3.4 3.7 3.6 3.7 3.8 3.8
FPATAN 3.3 3.3 3.3 - - - -
FPTAN 3.2 3.2 3.2 - - - -
FSCALE 3.3 3.3 3.3 3.3 3.3 3.3 3.3
FSINCOS 3.2 3.2 3.2 - - - -
FST 3.5 3.5 3.6 3.6 3.6 3.6 3.6
FXTRACT 3.2 3.2 3.2 - - - -
FYL2X 3.2 3.2 3.2 - - - -
HDEB 2.11 ?2.12 ?2.12 - - - -
HYPRES ?1 ?2 ?2 ?3 ?4 ?5 ?5
INT 3.4 =3.5 3.5 ?3.6 ?3.6 ?3.6 ?3.6
INTO 3.4 =3.5 3.5 =3.5 3.5 3.5 3.5
INVOP 3.29 ?3.3 ?3.4 3.5 ?3.6 ?3.6 ?3.6
IO_EM 2.5 2.5 2.5 2.5 3.8 3.8 3.8
IOBM 2.2 2.2 2.2 2.2 2.2 2.2 2.2
IRET 3.2 =3.3 ?3.4 3.3 3.3 3.3 3.3
MOVCR 3.1 ?3.3 ?3.3 3.2 3.2 3.2 3.2
NP_EM 3.2 =3.3 3.3 - - - -
NP_SUB 3.3 3.3 3.3 3.3 3.3 3.3 3.3
NP_XCP 3.3 3.3 3.4 3.3 3.3 3.4 3.4
NPHCODE 3.10 =3.11 3.11 ?3.12 3.16 3.16 3.16
RETF 3.4 =3.5 3.5 ?3.6 ?3.6 ?3.6 ?3.6
SOFRES 2.3 2.3 2.3 2.3 2.3 2.3 2.3
TASK 3.5 =3.6 3.6 ?3.7 ?3.7 ?3.7 ?3.7
UNDOC 2.3 2.3 2.3 2.3 2.3 2.3 2.3
XESC - ?1 ?2 - - - -

Legend:
= A file version is not included in the file ID, but content is the same as in another hyper code version and the file ID there does contain this file version.
? Unknown, version number is guessed (incremented for each change).
- This module is not used in this hyper code version.

Peculiarities:
DECODE: Version 3.22 develops from 033w to 034i and throughout the other PCI versions. Seems it was forgotten to increment the version number.
INTO: Differences between VL and PCI on same file version.
IO_EM: 033v has file version 2.5 which is different from the 2.5 of the other VL versions, also 034n has file version 3.8 which is different from 3.8 of the other PCI versions.
NPHCODE: 034q has 3.16 which is different from the 3.16 of the other PCI versions.

Slight differences between VL and PCI can't be avoided, and may be accounted for by conditional assembly. You don't want to have two versions of the same file when they differ only a little bit. Thus the case with the file INTO.ASM can be easily explained. But the other cases remain unclear. That is why I always use the hyper code version to refer to a version and not file versions because they are not reliable.

further topics (not yet done):
Diagnostic port
CMOS RAM


Author: Herbert Oppmann (email adress) updated: 2022-11-13