Index: trunk/Assembly_Library/Inc/AssemblyLibrary.inc
===================================================================
--- trunk/Assembly_Library/Inc/AssemblyLibrary.inc	(revision 592)
+++ trunk/Assembly_Library/Inc/AssemblyLibrary.inc	(revision 593)
@@ -9,8 +9,10 @@
 %include "BiosData.inc"
 %include "BiosFunctions.inc"
+%include "CMOS.inc"
 %include "CgaSnow.inc"
 %include "Debug.inc"
 %include "Delay.inc"
 %include "DosFunctions.inc"
+%include "CMOS.inc"
 %include "File.inc"
 %include "Math.inc"
@@ -20,15 +22,15 @@
 
 ; Library dependencies
-%ifdef INCLUDE_MENU_DIALOGS
-	%include "Dialog.inc"
-	%define INCLUDE_MENU_LIBRARY
-	%define INCLUDE_FILE_LIBRARY
-%endif
-
-%ifdef INCLUDE_MENU_LIBRARY
+%ifdef INCLUDE_MENU_LIBRARY or INCLUDE_MENU_DIALOGS	; To prevent warnings with Nasm 2.13.xx
 	%include "Menu.inc"
 	%include "MenuEvents.inc"
 	%define INCLUDE_KEYBOARD_LIBRARY
 	%define INCLUDE_TIME_LIBRARY
+	
+	%ifdef INCLUDE_MENU_DIALOGS
+		%include "Dialog.inc"
+		%define INCLUDE_MENU_LIBRARY
+		%define INCLUDE_FILE_LIBRARY
+	%endif
 %endif
 
Index: trunk/Assembly_Library/Inc/BiosFunctions.inc
===================================================================
--- trunk/Assembly_Library/Inc/BiosFunctions.inc	(revision 592)
+++ trunk/Assembly_Library/Inc/BiosFunctions.inc	(revision 593)
@@ -12,4 +12,5 @@
 BIOS_BOOT_FAILURE_INTERRUPT_18h	EQU		18h
 BIOS_BOOT_LOADER_INTERRUPT_19h	EQU		19h
+BIOS_TIME_PCI_PNP_1Ah			EQU		1Ah
 BIOS_DISKETTE_INTERRUPT_40h		EQU		40h
 HD0_DPT_POINTER_41h				EQU		41h
@@ -64,4 +65,7 @@
 EVENT_WAIT						EQU		86h
 
+; BIOS PCI 2.0+ functions
+PCI_INSTALLATION_CHECK				EQU		0B101h
+
 
 %endif ; BIOS_FUNCTIONS_INC
Index: trunk/Assembly_Library/Inc/CMOS.inc
===================================================================
--- trunk/Assembly_Library/Inc/CMOS.inc	(revision 593)
+++ trunk/Assembly_Library/Inc/CMOS.inc	(revision 593)
@@ -0,0 +1,42 @@
+; Project name	:	Assembly Library
+; Description	:	Defines for accessing CMOS.
+
+;
+; XTIDE Universal BIOS and Associated Tools
+; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2018 by XTIDE Universal BIOS Team.
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+;
+
+%ifndef CMOS_INC
+%define CMOS_INC
+
+; CMOS Ports
+; Note that a data register read or write must follow every write to the address register
+CMOS_INDEX_REGISTER				EQU		70h		; Is this write only?
+CMOS_DATA_REGISTER				EQU		71h
+
+FLG_CMOS_INDEX_NMI_DISABLE		EQU		(1<<7)	; CMOS Index Register bit 7 is NMI disable/enable bit
+
+
+; Almost all of the CMOS locations are vendor specific and
+; there is very little standardation
+HARD_DISK_TYPES					EQU		12h		; Windows 95 reads this to check if IDE drives
+												; are present so it should be safe to access this.
+												; Bits 0...3 Hard Disk 1 type (Primary Slave)
+												; Bits 4...7 Hard Disk 0 type (Primary Master)
+												; Fh = Types 16...47 (defined elsewhere in CMOS)
+CHECKSUM_OF_BYTES_10hTo2Dh_LOW	EQU		2Fh		; Most BIOSes store checksum of bytes 10h to 2Dh here
+CHECKSUM_OF_BYTES_10hTo2Dh_HIGH	EQU		2Eh		; High byte of the checksum
+
+
+%endif ; CMOS_INC
Index: trunk/Assembly_Library/Inc/Dialog.inc
===================================================================
--- trunk/Assembly_Library/Inc/Dialog.inc	(revision 592)
+++ trunk/Assembly_Library/Inc/Dialog.inc	(revision 593)
@@ -46,4 +46,9 @@
 endstruc
 
+
+; Progress bar dialog
+PROGRESS_COMPLETE_CHARACTER			EQU		BLOCK_FULL_FOREGROUND
+PROGRESS_INCOMPLETE_CHARACTER		EQU		BLOCK_MOSTLY_BACKGROUND
+
 struc PROGRESS_DIALOG_IO
 	.dialogInput					resb	DIALOG_INPUT_size
@@ -67,4 +72,16 @@
 endstruc
 
+
+; File dialog
+FILENAME_BUFFER_SIZE				EQU		14	; 8+1+3+NULL+alignment
+MAX_FILE_DIALOG_INFO_LINES			EQU		3
+FLG_FILEDIALOG_DRIVES				EQU		(1<<0)	; Allow changing drive
+FLG_FILEDIALOG_DIRECTORY			EQU		(1<<1)	; Select directory instead of file
+FLG_FILEDIALOG_NEW					EQU		(1<<2)	; Allow creating new file or directory
+
+KEY_FILEDIALOG_CHANGE_DRIVE			EQU		3Ch		; F2
+KEY_FILEDIALOG_SELECT_DIRECTORY		EQU		3Dh		; F3
+KEY_FILEDIALOG_NEW_FILE_OR_DIR		EQU		3Eh		; F4
+
 struc FILE_DIALOG_IO
 	; DIALOG_INPUT adjusted for File Dialog
@@ -83,19 +100,3 @@
 
 
-; Progress bar dialog
-PROGRESS_COMPLETE_CHARACTER			EQU		BLOCK_FULL_FOREGROUND
-PROGRESS_INCOMPLETE_CHARACTER		EQU		BLOCK_MOSTLY_BACKGROUND
-
-; File dialog
-FILENAME_BUFFER_SIZE				EQU		14	; 8+1+3+NULL+alignment
-MAX_FILE_DIALOG_INFO_LINES			EQU		3
-FLG_FILEDIALOG_DRIVES				EQU		(1<<0)	; Allow changing drive
-FLG_FILEDIALOG_DIRECTORY			EQU		(1<<1)	; Select directory instead of file
-FLG_FILEDIALOG_NEW					EQU		(1<<2)	; Allow creating new file or directory
-
-KEY_FILEDIALOG_CHANGE_DRIVE			EQU		3Ch		; F2
-KEY_FILEDIALOG_SELECT_DIRECTORY		EQU		3Dh		; F3
-KEY_FILEDIALOG_NEW_FILE_OR_DIR		EQU		3Eh		; F4
-
-
 %endif ; DIALOG_INC
Index: trunk/Assembly_Library/Inc/Macros.inc
===================================================================
--- trunk/Assembly_Library/Inc/Macros.inc	(revision 592)
+++ trunk/Assembly_Library/Inc/Macros.inc	(revision 593)
@@ -124,3 +124,20 @@
 
 
+;--------------------------------------------------------------------
+; Small delay between I/O port accessess if needed.
+;
+; IO_DELAY
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro IO_DELAY 0
+	jmp		SHORT %%ClearPrefetchQueue
+%%ClearPrefetchQueue:
+%endmacro
+
+
 %endif ; MACROS_INC
Index: trunk/Assembly_Library/Inc/NEC_V.inc
===================================================================
--- trunk/Assembly_Library/Inc/NEC_V.inc	(revision 593)
+++ trunk/Assembly_Library/Inc/NEC_V.inc	(revision 593)
@@ -0,0 +1,1081 @@
+; Project name	:	Assembly Library
+; Description	:	Macros for using NEC V20/V30 specific instructions.
+
+;
+; XTIDE Universal BIOS and Associated Tools
+; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+;
+
+%ifndef NEC_V_INC
+%define NEC_V_INC
+
+	regAL		equ		000b
+	regCL		equ		001b
+	regDL		equ		010b
+	regBL		equ		011b
+	regAH		equ		100b
+	regCH		equ		101b
+	regDH		equ		110b
+	regBH		equ		111b
+
+	regAX		equ		regAL
+	regCX		equ		regCL
+	regDX		equ		regDL
+	regBX		equ		regBL
+	regSP		equ		regAH
+	regBP		equ		regCH
+	regSI		equ		regDH
+	regDI		equ		regBH
+
+
+;--------------------------------------------------------------------
+; The REPC string instruction prefix available on NEC V20/V30 CPUs.
+;
+; Repeats the following string instruction (CMPS or SCAS)
+; while CF=1 and CX<>0.
+;
+; eREPC
+;	Parameters:
+;		%1:		String instruction (optional for this macro)
+;		CX:		String length in BYTEs or WORDs
+;		xS:SI:	Pointer to source string. Default segment is DS but can be overridden
+;		ES:DI:	Pointer to destination string
+;	Returns:
+;		CF/CX:	Depends on the result from the string instruction.
+;				If CF clear, then CX contains the remaining number of
+;				BYTEs or WORDs in the string. If CF set, then CX=0.
+;		SI/DI:	Updated depending on the string instruction used and
+;				state of the direction flag.
+;	Corrupts registers:
+;		The string instruction corrupts FLAGS. The prefix corrupts nothing.
+;--------------------------------------------------------------------
+%macro eREPC 0-1.nolist
+	db	65h
+	%ifnempty %1
+		%1
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The REPNC string instruction prefix available on NEC V20/V30 CPUs.
+;
+; Repeats the following string instruction (CMPS or SCAS)
+; while CF=0 and CX<>0.
+;
+; eREPNC
+;	Parameters:
+;		%1:		String instruction (optional for this macro)
+;		CX:		String length in BYTEs or WORDs
+;		xS:SI:	Pointer to source string. Default segment is DS but can be overridden
+;		ES:DI:	Pointer to destination string
+;	Returns:
+;		CF/CX:	Depends on the result from the string instruction.
+;				If CF set, then CX contains the remaining number of
+;				BYTEs or WORDs in the string. If CF clear, then CX=0.
+;		SI/DI:	Updated depending on the string instruction used and
+;				state of the direction flag.
+;	Corrupts registers:
+;		The string instruction corrupts FLAGS. The prefix corrupts nothing.
+;--------------------------------------------------------------------
+%macro eREPNC 0-1.nolist
+	db	64h
+	%ifnempty %1
+		%1
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The CLR1 instruction available on NEC V20/V30 CPUs.
+;
+; Clears bit indexed by Source in Destination.
+;
+; eCLR1
+;	Parameters:
+;		%1:		Destination (register or memory location)
+;		%2:		Source (CL or immediate value)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing (not even FLAGS)
+;--------------------------------------------------------------------
+%macro eCLR1 2.nolist
+	%assign w 0
+	%assign i 0
+	%ifnidni %2, cl
+		%assign i (1 << 3)
+	%endif
+	FSIS	], %1
+	%if strpos
+		FSIS	BYTE, %1
+		%ifn strpos = 1
+			FSIS	WORD, %1
+			%if strpos = 1
+				%assign w 1
+			%elif i
+				%if %2 > 7
+					%assign w 1
+				%endif
+			%else
+				%error "Memory operand needs a size specifier!"
+			%endif
+		%endif
+		%assign m (00b << 6)
+		FSIS	[bx+si], %1
+		%if strpos
+			%assign rm 000b
+		%else
+			FSIS	[bx+di], %1
+			%if strpos
+				%assign rm 001b
+			%else
+				FSIS	[bp+si], %1
+				%if strpos
+					%assign rm 010b
+				%else
+					FSIS	[bp+di], %1
+					%if strpos
+						%assign rm 011b
+					%else
+						FSIS	[si], %1
+						%if strpos
+							%assign rm 100b
+						%else
+							FSIS	[di], %1
+							%if strpos
+								%assign rm 101b
+							%else
+								FSIS	[bx], %1
+								%if strpos
+									%assign rm 111b
+								%else
+									%error "Memory operands are not (yet) fully supported by the eCLR1 macro!"
+								%endif
+							%endif
+						%endif
+					%endif
+				%endif
+			%endif
+		%endif
+	%else
+		%assign m (11b << 6)
+		%ifidni %1, ax
+			%assign w 1
+			%assign rm regAX
+		%elifidni %1, bx
+			%assign w 1
+			%assign rm regBX
+		%elifidni %1, cx
+			%assign w 1
+			%assign rm regCX
+		%elifidni %1, dx
+			%assign w 1
+			%assign rm regDX
+		%elifidni %1, bp
+			%assign w 1
+			%assign rm regBP
+		%elifidni %1, sp
+			%assign w 1
+			%assign rm regSP
+		%elifidni %1, si
+			%assign w 1
+			%assign rm regSI
+		%elifidni %1, di
+			%assign w 1
+			%assign rm regDI
+		%elifidni %1, al
+			%assign rm regAL
+		%elifidni %1, ah
+			%assign rm regAH
+		%elifidni %1, bl
+			%assign rm regBL
+		%elifidni %1, bh
+			%assign rm regBH
+		%elifidni %1, cl
+			%assign rm regCL
+		%elifidni %1, ch
+			%assign rm regCH
+		%elifidni %1, dl
+			%assign rm regDL
+		%elifidni %1, dh
+			%assign rm regDH
+		%else
+			%error Invalid parameter passed to eCLR1! (%1)
+		%endif
+	%endif
+	db	0Fh, 12h | i | w, m | rm
+	%if i
+		db	%2
+		%if w
+			%if %2 > 15
+				%warning Possibly invalid parameter passed to eCLR1! (%2 > 15)
+			%endif
+		%else
+			%if %2 > 7
+				%warning Possibly invalid parameter passed to eCLR1! (%2 > 7)
+			%endif
+		%endif
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The SET1 instruction available on NEC V20/V30 CPUs.
+;
+; Sets bit indexed by Source in Destination.
+;
+; eSET1
+;	Parameters:
+;		%1:		Destination (register or memory location)
+;		%2:		Source (CL or immediate value)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing (not even FLAGS)
+;--------------------------------------------------------------------
+%macro eSET1 2.nolist
+	%assign w 0
+	%assign i 0
+	%ifnidni %2, cl
+		%assign i (1 << 3)
+	%endif
+	FSIS	], %1
+	%if strpos
+		FSIS	BYTE, %1
+		%ifn strpos = 1
+			FSIS	WORD, %1
+			%if strpos = 1
+				%assign w 1
+			%elif i
+				%if %2 > 7
+					%assign w 1
+				%endif
+			%else
+				%error "Memory operand needs a size specifier!"
+			%endif
+		%endif
+		%assign m (00b << 6)
+		FSIS	[bx+si], %1
+		%if strpos
+			%assign rm 000b
+		%else
+			FSIS	[bx+di], %1
+			%if strpos
+				%assign rm 001b
+			%else
+				FSIS	[bp+si], %1
+				%if strpos
+					%assign rm 010b
+				%else
+					FSIS	[bp+di], %1
+					%if strpos
+						%assign rm 011b
+					%else
+						FSIS	[si], %1
+						%if strpos
+							%assign rm 100b
+						%else
+							FSIS	[di], %1
+							%if strpos
+								%assign rm 101b
+							%else
+								FSIS	[bx], %1
+								%if strpos
+									%assign rm 111b
+								%else
+									%error "Memory operands are not (yet) fully supported by the eSET1 macro!"
+								%endif
+							%endif
+						%endif
+					%endif
+				%endif
+			%endif
+		%endif
+	%else
+		%assign m (11b << 6)
+		%ifidni %1, ax
+			%assign w 1
+			%assign rm regAX
+		%elifidni %1, bx
+			%assign w 1
+			%assign rm regBX
+		%elifidni %1, cx
+			%assign w 1
+			%assign rm regCX
+		%elifidni %1, dx
+			%assign w 1
+			%assign rm regDX
+		%elifidni %1, bp
+			%assign w 1
+			%assign rm regBP
+		%elifidni %1, sp
+			%assign w 1
+			%assign rm regSP
+		%elifidni %1, si
+			%assign w 1
+			%assign rm regSI
+		%elifidni %1, di
+			%assign w 1
+			%assign rm regDI
+		%elifidni %1, al
+			%assign rm regAL
+		%elifidni %1, ah
+			%assign rm regAH
+		%elifidni %1, bl
+			%assign rm regBL
+		%elifidni %1, bh
+			%assign rm regBH
+		%elifidni %1, cl
+			%assign rm regCL
+		%elifidni %1, ch
+			%assign rm regCH
+		%elifidni %1, dl
+			%assign rm regDL
+		%elifidni %1, dh
+			%assign rm regDH
+		%else
+			%error Invalid parameter passed to eSET1! (%1)
+		%endif
+	%endif
+	db	0Fh, 14h | i | w, m | rm
+	%if i
+		db	%2
+		%if w
+			%if %2 > 15
+				%warning Possibly invalid parameter passed to eSET1! (%2 > 15)
+			%endif
+		%else
+			%if %2 > 7
+				%warning Possibly invalid parameter passed to eSET1! (%2 > 7)
+			%endif
+		%endif
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The NOT1 instruction available on NEC V20/V30 CPUs.
+;
+; Inverts bit indexed by Source in Destination.
+;
+; eNOT1
+;	Parameters:
+;		%1:		Destination (register or memory location)
+;		%2:		Source (CL or immediate value)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing (not even FLAGS)
+;--------------------------------------------------------------------
+%macro eNOT1 2.nolist
+	%assign w 0
+	%assign i 0
+	%ifnidni %2, cl
+		%assign i (1 << 3)
+	%endif
+	FSIS	], %1
+	%if strpos
+		FSIS	BYTE, %1
+		%ifn strpos = 1
+			FSIS	WORD, %1
+			%if strpos = 1
+				%assign w 1
+			%elif i
+				%if %2 > 7
+					%assign w 1
+				%endif
+			%else
+				%error "Memory operand needs a size specifier!"
+			%endif
+		%endif
+		%assign m (00b << 6)
+		FSIS	[bx+si], %1
+		%if strpos
+			%assign rm 000b
+		%else
+			FSIS	[bx+di], %1
+			%if strpos
+				%assign rm 001b
+			%else
+				FSIS	[bp+si], %1
+				%if strpos
+					%assign rm 010b
+				%else
+					FSIS	[bp+di], %1
+					%if strpos
+						%assign rm 011b
+					%else
+						FSIS	[si], %1
+						%if strpos
+							%assign rm 100b
+						%else
+							FSIS	[di], %1
+							%if strpos
+								%assign rm 101b
+							%else
+								FSIS	[bx], %1
+								%if strpos
+									%assign rm 111b
+								%else
+									%error "Memory operands are not (yet) fully supported by the eNOT1 macro!"
+								%endif
+							%endif
+						%endif
+					%endif
+				%endif
+			%endif
+		%endif
+	%else
+		%assign m (11b << 6)
+		%ifidni %1, ax
+			%assign w 1
+			%assign rm regAX
+		%elifidni %1, bx
+			%assign w 1
+			%assign rm regBX
+		%elifidni %1, cx
+			%assign w 1
+			%assign rm regCX
+		%elifidni %1, dx
+			%assign w 1
+			%assign rm regDX
+		%elifidni %1, bp
+			%assign w 1
+			%assign rm regBP
+		%elifidni %1, sp
+			%assign w 1
+			%assign rm regSP
+		%elifidni %1, si
+			%assign w 1
+			%assign rm regSI
+		%elifidni %1, di
+			%assign w 1
+			%assign rm regDI
+		%elifidni %1, al
+			%assign rm regAL
+		%elifidni %1, ah
+			%assign rm regAH
+		%elifidni %1, bl
+			%assign rm regBL
+		%elifidni %1, bh
+			%assign rm regBH
+		%elifidni %1, cl
+			%assign rm regCL
+		%elifidni %1, ch
+			%assign rm regCH
+		%elifidni %1, dl
+			%assign rm regDL
+		%elifidni %1, dh
+			%assign rm regDH
+		%else
+			%error Invalid parameter passed to eNOT1! (%1)
+		%endif
+	%endif
+	db	0Fh, 16h | i | w, m | rm
+	%if i
+		db	%2
+		%if w
+			%if %2 > 15
+				%warning Possibly invalid parameter passed to eNOT1! (%2 > 15)
+			%endif
+		%else
+			%if %2 > 7
+				%warning Possibly invalid parameter passed to eNOT1! (%2 > 7)
+			%endif
+		%endif
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The TEST1 instruction available on NEC V20/V30 CPUs.
+;
+; Tests bit indexed by Source in Destination.
+;
+; eTEST1
+;	Parameters:
+;		%1:		Destination (register or memory location)
+;		%2:		Source (CL or immediate value)
+;	Returns:
+;		ZF:		Set if tested bit is zero
+;				Cleared if tested bit is not zero
+;		CF:		Cleared
+;		OF:		Cleared
+;	Corrupts registers:
+;		All other FLAGS
+;--------------------------------------------------------------------
+%macro eTEST1 2.nolist
+	%assign w 0
+	%assign i 0
+	%ifnidni %2, cl
+		%assign i (1 << 3)
+	%endif
+	FSIS	], %1
+	%if strpos
+		FSIS	BYTE, %1
+		%ifn strpos = 1
+			FSIS	WORD, %1
+			%if strpos = 1
+				%assign w 1
+			%elif i
+				%if %2 > 7
+					%assign w 1
+				%endif
+			%else
+				%error "Memory operand needs a size specifier!"
+			%endif
+		%endif
+		%assign m (00b << 6)
+		FSIS	[bx+si], %1
+		%if strpos
+			%assign rm 000b
+		%else
+			FSIS	[bx+di], %1
+			%if strpos
+				%assign rm 001b
+			%else
+				FSIS	[bp+si], %1
+				%if strpos
+					%assign rm 010b
+				%else
+					FSIS	[bp+di], %1
+					%if strpos
+						%assign rm 011b
+					%else
+						FSIS	[si], %1
+						%if strpos
+							%assign rm 100b
+						%else
+							FSIS	[di], %1
+							%if strpos
+								%assign rm 101b
+							%else
+								FSIS	[bx], %1
+								%if strpos
+									%assign rm 111b
+								%else
+									%error "Memory operands are not (yet) fully supported by the eTEST1 macro!"
+								%endif
+							%endif
+						%endif
+					%endif
+				%endif
+			%endif
+		%endif
+	%else
+		%assign m (11b << 6)
+		%ifidni %1, ax
+			%assign w 1
+			%assign rm regAX
+		%elifidni %1, bx
+			%assign w 1
+			%assign rm regBX
+		%elifidni %1, cx
+			%assign w 1
+			%assign rm regCX
+		%elifidni %1, dx
+			%assign w 1
+			%assign rm regDX
+		%elifidni %1, bp
+			%assign w 1
+			%assign rm regBP
+		%elifidni %1, sp
+			%assign w 1
+			%assign rm regSP
+		%elifidni %1, si
+			%assign w 1
+			%assign rm regSI
+		%elifidni %1, di
+			%assign w 1
+			%assign rm regDI
+		%elifidni %1, al
+			%assign rm regAL
+		%elifidni %1, ah
+			%assign rm regAH
+		%elifidni %1, bl
+			%assign rm regBL
+		%elifidni %1, bh
+			%assign rm regBH
+		%elifidni %1, cl
+			%assign rm regCL
+		%elifidni %1, ch
+			%assign rm regCH
+		%elifidni %1, dl
+			%assign rm regDL
+		%elifidni %1, dh
+			%assign rm regDH
+		%else
+			%error Invalid parameter passed to eTEST1! (%1)
+		%endif
+	%endif
+	db	0Fh, 10h | i | w, m | rm
+	%if i
+		db	%2
+		%if w
+			%if %2 > 15
+				%warning Possibly invalid parameter passed to eTEST1! (%2 > 15)
+			%endif
+		%else
+			%if %2 > 7
+				%warning Possibly invalid parameter passed to eTEST1! (%2 > 7)
+			%endif
+		%endif
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The EXT instruction available on NEC V20/V30 CPUs.
+;
+; Loads AX with a zero-extended bitfield, from [xS:SI] plus an additional
+; bit offset specified in Destination, with Source+1 number of bits.
+; Both Source and Destination must be at most 15.
+;
+; eEXT
+;	Parameters:
+;		xS:SI:	Pointer to bitfield. Default segment is DS but can be overridden
+;		%1:		Destination (8-bit register)
+;		%2:		Source (8-bit register or immediate value)
+;	Returns:
+;		AX:		Extracted bitfield
+;		%1:		(%1 + %2 + 1) MOD 16
+;		SI:		SI + 2 (but only if %1 wrapped around)
+;	Corrupts registers:
+;		FLAGS
+;--------------------------------------------------------------------
+%macro eEXT 2.nolist
+	%assign m (11b << 6)
+	%assign i 0
+	%assign r 0
+	%ifidni %2, al
+		%assign r (regAL << 3)
+	%elifidni %2, ah
+		%assign r (regAH << 3)
+	%elifidni %2, bl
+		%assign r (regBL << 3)
+	%elifidni %2, bh
+		%assign r (regBH << 3)
+	%elifidni %2, cl
+		%assign r (regCL << 3)
+	%elifidni %2, ch
+		%assign r (regCH << 3)
+	%elifidni %2, dl
+		%assign r (regDL << 3)
+	%elifidni %2, dh
+		%assign r (regDH << 3)
+	%else
+		%if %2 > 15
+			%error Invalid parameter passed to eEXT! (%2 > 15)
+		%endif
+		%assign i (1 << 3)
+	%endif
+	%ifidni %1, al
+		%assign rm regAL
+	%elifidni %1, ah
+		%assign rm regAH
+	%elifidni %1, bl
+		%assign rm regBL
+	%elifidni %1, bh
+		%assign rm regBH
+	%elifidni %1, cl
+		%assign rm regCL
+	%elifidni %1, ch
+		%assign rm regCH
+	%elifidni %1, dl
+		%assign rm regDL
+	%elifidni %1, dh
+		%assign rm regDH
+	%else
+		%error Invalid parameter passed to eEXT! (%1)
+	%endif
+	db	0Fh, 33h | i, m | r | rm
+	%if i
+		db	%2
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The INS instruction available on NEC V20/V30 CPUs.
+;
+; Stores the Source+1 least significant bits in AX to [xS:DI]
+; plus an additional bit offset specified in Destination.
+; Both Source and Destination must be at most 15.
+;
+; eINS
+;	Parameters:
+;		xS:DI:	Pointer to bitfield. Default segment is ES but can be overridden
+;		%1:		Destination (8-bit register)
+;		%2:		Source (8-bit register or immediate value)
+;	Returns:
+;		%1:		(%1 + %2 + 1) MOD 16
+;		DI:		DI + 2 (but only if %1 wrapped around)
+;	Corrupts registers:
+;		FLAGS
+;--------------------------------------------------------------------
+%macro eINS 2.nolist
+	%assign m (11b << 6)
+	%assign i 0
+	%assign r 0
+	%ifidni %2, al
+		%assign r (regAL << 3)
+	%elifidni %2, ah
+		%assign r (regAH << 3)
+	%elifidni %2, bl
+		%assign r (regBL << 3)
+	%elifidni %2, bh
+		%assign r (regBH << 3)
+	%elifidni %2, cl
+		%assign r (regCL << 3)
+	%elifidni %2, ch
+		%assign r (regCH << 3)
+	%elifidni %2, dl
+		%assign r (regDL << 3)
+	%elifidni %2, dh
+		%assign r (regDH << 3)
+	%else
+		%if %2 > 15
+			%error Invalid parameter passed to eINS! (%2 > 15)
+		%endif
+		%assign i (1 << 3)
+	%endif
+	%ifidni %1, al
+		%assign rm regAL
+	%elifidni %1, ah
+		%assign rm regAH
+	%elifidni %1, bl
+		%assign rm regBL
+	%elifidni %1, bh
+		%assign rm regBH
+	%elifidni %1, cl
+		%assign rm regCL
+	%elifidni %1, ch
+		%assign rm regCH
+	%elifidni %1, dl
+		%assign rm regDL
+	%elifidni %1, dh
+		%assign rm regDH
+	%else
+		%error Invalid parameter passed to eINS! (%1)
+	%endif
+	db	0Fh, 31h | i, m | r | rm
+	%if i
+		db	%2
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The ROL4 instruction available on NEC V20/V30 CPUs.
+;
+; Rotates the destination four bits to the left via the low nibble of AL.
+;
+; eROL4
+;	Parameters:
+;		%1:		8-bit destination (register or memory location)
+;	Returns:
+;		AL:		The high nibble of %1 in the low nibble of AL
+;		%1:		The low nibble of %1 in the high nibble of %1
+;				The low nibble of AL in the low nibble of %1
+;	Corrupts registers:
+;		Nothing (not even FLAGS)
+;--------------------------------------------------------------------
+%macro eROL4 1.nolist
+	FSIS	], %1
+	%if strpos
+		%assign m (00b << 6)
+		FSIS	[bx+si], %1
+		%if strpos
+			%assign rm 000b
+		%else
+			FSIS	[bx+di], %1
+			%if strpos
+				%assign rm 001b
+			%else
+				FSIS	[bp+si], %1
+				%if strpos
+					%assign rm 010b
+				%else
+					FSIS	[bp+di], %1
+					%if strpos
+						%assign rm 011b
+					%else
+						FSIS	[si], %1
+						%if strpos
+							%assign rm 100b
+						%else
+							FSIS	[di], %1
+							%if strpos
+								%assign rm 101b
+							%else
+								FSIS	[bx], %1
+								%if strpos
+									%assign rm 111b
+								%else
+									%error "Memory operands are not (yet) fully supported by the eROL4 macro!"
+								%endif
+							%endif
+						%endif
+					%endif
+				%endif
+			%endif
+		%endif
+	%else
+		%assign m (11b << 6)
+		%ifidni %1, al
+			%assign rm regAL
+		%elifidni %1, ah
+			%assign rm regAH
+		%elifidni %1, bl
+			%assign rm regBL
+		%elifidni %1, bh
+			%assign rm regBH
+		%elifidni %1, cl
+			%assign rm regCL
+		%elifidni %1, ch
+			%assign rm regCH
+		%elifidni %1, dl
+			%assign rm regDL
+		%elifidni %1, dh
+			%assign rm regDH
+		%else
+			%error Invalid parameter passed to eROL4! (%1)
+		%endif
+	%endif
+	db	0Fh, 28h, m | rm
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The ROR4 instruction available on NEC V20/V30 CPUs.
+;
+; Rotates the destination four bits to the right via the low nibble of AL.
+;
+; eROR4
+;	Parameters:
+;		%1:		8-bit destination (register or memory location)
+;	Returns:
+;		AL:		The low nibble of %1 in the low nibble of AL
+;		%1:		The high nibble of %1 in the low nibble of %1
+;				The low nibble of AL in the high nibble of %1
+;	Corrupts registers:
+;		Nothing (not even FLAGS)
+;--------------------------------------------------------------------
+%macro eROR4 1.nolist
+	FSIS	], %1
+	%if strpos
+		%assign m (00b << 6)
+		FSIS	[bx+si], %1
+		%if strpos
+			%assign rm 000b
+		%else
+			FSIS	[bx+di], %1
+			%if strpos
+				%assign rm 001b
+			%else
+				FSIS	[bp+si], %1
+				%if strpos
+					%assign rm 010b
+				%else
+					FSIS	[bp+di], %1
+					%if strpos
+						%assign rm 011b
+					%else
+						FSIS	[si], %1
+						%if strpos
+							%assign rm 100b
+						%else
+							FSIS	[di], %1
+							%if strpos
+								%assign rm 101b
+							%else
+								FSIS	[bx], %1
+								%if strpos
+									%assign rm 111b
+								%else
+									%error "Memory operands are not (yet) fully supported by the eROR4 macro!"
+								%endif
+							%endif
+						%endif
+					%endif
+				%endif
+			%endif
+		%endif
+	%else
+		%assign m (11b << 6)
+		%ifidni %1, al
+			%assign rm regAL
+		%elifidni %1, ah
+			%assign rm regAH
+		%elifidni %1, bl
+			%assign rm regBL
+		%elifidni %1, bh
+			%assign rm regBH
+		%elifidni %1, cl
+			%assign rm regCL
+		%elifidni %1, ch
+			%assign rm regCH
+		%elifidni %1, dl
+			%assign rm regDL
+		%elifidni %1, dh
+			%assign rm regDH
+		%else
+			%error Invalid parameter passed to eROR4! (%1)
+		%endif
+	%endif
+	db	0Fh, 2Ah, m | rm
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The ADD4S instruction available on NEC V20/V30 CPUs.
+;
+; Adds packed BCD string at xS:SI to packed BCD string at ES:DI
+; with (preferably even) nibble count in CL.
+;
+; eADD4S
+;	Parameters:
+;		CL:		Number of packed BCD digits (nibbles in string) ranging
+;				from 1 to 254. Should be an even number or the CPU will
+;				treat it as CL+1.
+;		xS:SI:	Pointer to source string. Default segment is DS but
+;				can be overridden.
+;		ES:DI:	Pointer to destination string.
+;	Returns:
+;		ES:DI:	Pointer to destination string.
+;		CF/ZF:	Set according to result.
+;	Corrupts registers:
+;		All other FLAGS
+;--------------------------------------------------------------------
+%macro eADD4S 0.nolist
+	db	0Fh, 20h
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The SUB4S instruction available on NEC V20/V30 CPUs.
+;
+; Subtracts packed BCD string at xS:SI from packed BCD string at ES:DI
+; with (preferably even) nibble count in CL.
+;
+; eSUB4S
+;	Parameters:
+;		CL:		Number of packed BCD digits (nibbles in string) ranging
+;				from 1 to 254. Should be an even number or the CPU will
+;				treat it as CL+1.
+;		xS:SI:	Pointer to source string. Default segment is DS but
+;				can be overridden.
+;		ES:DI:	Pointer to destination string.
+;	Returns:
+;		ES:DI:	Pointer to destination string.
+;		CF/ZF:	Set according to result.
+;	Corrupts registers:
+;		All other FLAGS
+;--------------------------------------------------------------------
+%macro eSUB4S 0.nolist
+	db	0Fh, 22h
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The CMP4S instruction available on NEC V20/V30 CPUs.
+;
+; Compares packed BCD string at xS:SI with packed BCD string at ES:DI
+; with (preferably even) nibble count in CL.
+;
+; eCMP4S
+;	Parameters:
+;		CL:		Number of packed BCD digits (nibbles in string) ranging
+;				from 1 to 254. Should be an even number or the CPU will
+;				treat it as CL+1.
+;		xS:SI:	Pointer to source string. Default segment is DS but
+;				can be overridden.
+;		ES:DI:	Pointer to destination string.
+;	Returns:
+;		CF/ZF:	Set according to result.
+;	Corrupts registers:
+;		All other FLAGS
+;--------------------------------------------------------------------
+%macro eCMP4S 0.nolist
+	db	0Fh, 26h
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The BRKEM instruction available on NEC V20/V30 CPUs.
+;
+; Starts 8080 CPU emulation mode by invoking the software interrupt in %1.
+;
+; eBRKEM
+;	Parameters:
+;		%1:		8-bit interrupt vector number
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro eBRKEM 1.nolist
+	%if %1 > 255
+		%error Invalid parameter passed to eBRKEM! (%1 > 255)
+	%else
+		db	0Fh, 0FFh, %1
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The CALLN instruction available on NEC V20/V30 CPUs.
+;
+; This instruction is used while in 8080 CPU emulation mode to invoke
+; the native (x86) software interrupt in %1.
+;
+; eCALLN
+;	Parameters:
+;		%1:		8-bit interrupt vector number
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro eCALLN 1.nolist
+	%if %1 > 255
+		%error Invalid parameter passed to eCALLN! (%1 > 255)
+	%else
+		db	0EDh, 0EDh, %1
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; The RETEM instruction available on NEC V20/V30 CPUs.
+;
+; Ends 8080 CPU emulation mode by returning from the software interrupt
+; invoked by BRKEM.
+;
+; eRETEM
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro eRETEM 0.nolist
+	db	0EDh, 0FDh
+%endmacro
+
+
+%endif ; NEC_V_INC
+
Index: trunk/Assembly_Library/Src/AssemblyLibrary.asm
===================================================================
--- trunk/Assembly_Library/Src/AssemblyLibrary.asm	(revision 592)
+++ trunk/Assembly_Library/Src/AssemblyLibrary.asm	(revision 593)
@@ -5,5 +5,5 @@
 ;
 ; XTIDE Universal BIOS and Associated Tools
-; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
+; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2018 by XTIDE Universal BIOS Team.
 ;
 ; This program is free software; you can redistribute it and/or modify
@@ -45,4 +45,5 @@
 	%include "Drive.asm"
 	%include "FileIO.asm"
+	%include "InterruptHandlers.asm"
 %endif
 
@@ -134,4 +135,8 @@
 		%include "Sort.asm"
 	%endif
+
+%ifdef INCLUDE_CMOS_LIBRARY
+	%include "CMOS.asm"
+%endif
 %endif
 
Index: trunk/Assembly_Library/Src/Display/CgaSnow.asm
===================================================================
--- trunk/Assembly_Library/Src/Display/CgaSnow.asm	(revision 592)
+++ trunk/Assembly_Library/Src/Display/CgaSnow.asm	(revision 593)
@@ -37,5 +37,5 @@
 
 	; All standard CGA modes use 25 rows but only EGA and later store it to BDA.
-	cmp		BYTE [BDA.bVidRows], 25		; *FIXME* Shouldn't this be 24 (rows - 1)?
+	cmp		BYTE [BDA.bVidRows], 24		; BDA contains rows - 1
 	jae		SHORT .CgaNotFound
 	ret
Index: trunk/Assembly_Library/Src/File/DosCritical.asm
===================================================================
--- trunk/Assembly_Library/Src/File/DosCritical.asm	(revision 592)
+++ trunk/Assembly_Library/Src/File/DosCritical.asm	(revision 593)
@@ -45,8 +45,6 @@
 	push	ds
 
-	push	cs
-	pop		ds
-	mov		ax, (SET_INTERRUPT_VECTOR<<8) | DOS_CRITICAL_ERROR_HANDLER_24h
-	int		DOS_INTERRUPT_21h
+	mov		al, DOS_CRITICAL_ERROR_HANDLER_24h
+	call	HookInterruptVectorInALwithHandlerInCSDX
 
 	pop		ds
Index: trunk/Assembly_Library/Src/File/Drive.asm
===================================================================
--- trunk/Assembly_Library/Src/File/Drive.asm	(revision 592)
+++ trunk/Assembly_Library/Src/File/Drive.asm	(revision 593)
@@ -131,6 +131,12 @@
 .IsValidDriveNumberInDL:
 	push	ds
+	push	ax
+	cmp		dl, 1
+	jbe		SHORT .FloppyDrive
+
+.MessageSuppressedByInt2FhHandler:
+.MoreThanOneFloppyDrive:
+.NoFloppyDrive:
 	push	bx
-	push	ax
 
 	inc		dx			; Default drive is 00h and first drive is 01h
@@ -152,8 +158,27 @@
 	test	al, al
 
+	pop		bx
+.ReturnFromFloppyDriveFiltering:
 	pop		ax
-	pop		bx
 	pop		ds
 	ret
+
+.FloppyDrive:
+; On single-floppy-drive systems, both A: and B: will point to the same physical drive. The problem is that DOS will print a message telling the user
+; to "insert a disk and press any key to continue" when swapping from one logical drive to the other. To avoid this mess we hook interrupt 2Fh/AX=4A00h
+; to signal to DOS that we will handle this ourselves. However, this only works on DOS 5+ so on older DOS versions we instead try to filter out
+; the "other" logical drive (the one that isn't the current drive) during drive enumeration so the user can't select the "phantom" drive to begin with.
+; This will have the somewhat strange effect of having a drive B: but no drive A: if B: happens to be the current logical floppy drive.
+
+	cmp		BYTE [bDosVersionMajor], 5		; bDosVersionMajor must be provided by the application as it's not part of the library
+	jae		SHORT .MessageSuppressedByInt2FhHandler
+	LOAD_BDA_SEGMENT_TO ds, ax
+	mov		al, [BDA.wEquipment]
+	test	al, 0C0h
+	jnz		SHORT .MoreThanOneFloppyDrive	; No phantom drive so no need for any filtering
+	test	al, 1							; Any floppy drive at all?
+	jz		SHORT .NoFloppyDrive			; A pre-DOS 5 machine with no FDD is indeed a strange beast. However, don't trust the BIOS - let DOS decide
+	cmp		dl, [504h]						; MS-DOS - LOGICAL DRIVE FOR SINGLE-FLOPPY SYSTEM (A: / B:)
+	jmp		SHORT .ReturnFromFloppyDriveFiltering
 
 ;--------------------------------------------------------------------
Index: trunk/Assembly_Library/Src/File/InterruptHandlers.asm
===================================================================
--- trunk/Assembly_Library/Src/File/InterruptHandlers.asm	(revision 593)
+++ trunk/Assembly_Library/Src/File/InterruptHandlers.asm	(revision 593)
@@ -0,0 +1,162 @@
+; Project name	:	Assembly Library
+; Description	:	Interrupt handlers and related functions.
+
+;
+; XTIDE Universal BIOS and Associated Tools
+; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+;
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int2Fh_Handler
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int2Fh_Handler:
+	cmp		ax, 4A00h			; DOS 5+ - FLOPPY-DISK LOGICAL DRIVE CHANGE NOTIFICATION
+	je		SHORT .CallMightBeForMe
+.CallIsNotForMe:
+	db		0EAh				; Far jump opcode
+.fpPreviousInt2FhHandler:
+	dd		0					; Pointer is filled in when handler is installed
+
+.CallMightBeForMe:
+	inc		cx
+	loop	.CallIsNotForMe
+	dec		cx
+ReturnFromNestedCall:
+	iret
+
+
+;--------------------------------------------------------------------
+; Int23h_Handler
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int23h_Handler:
+	cmp		BYTE [cs:Interrupt23hInProgress], 0
+	jne		SHORT ReturnFromNestedCall
+	inc		BYTE [cs:Interrupt23hInProgress]
+	push	ds
+	push	dx
+	push	ax
+	call	UnhookInterrupt2Fh
+	pop		ax
+	pop		dx
+	pop		ds
+	dec		BYTE [cs:Interrupt23hInProgress]	; Not really needed since we should not be called again
+	; Special return to terminate program - might not work under DR-DOS (see RBIL)
+	stc
+	retf
+
+Interrupt23hInProgress:		db		0
+
+
+;--------------------------------------------------------------------
+; HookInterrupt23h
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DX, DS
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HookInterrupt23h:
+	mov		al, DOS_CTRL_C_CTRL_BREAK_HANDLER_23h
+	mov		dx, Int23h_Handler
+	jmp		SHORT HookInterruptVectorInALwithHandlerInCSDX
+
+
+;--------------------------------------------------------------------
+; HookInterrupt2Fh
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX, DS, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+HookInterrupt2Fh:
+	mov		ax, GET_INTERRUPT_VECTOR << 8 | DOS_TSR_MULTIPLEX_INTERRUPT_2Fh
+	int		DOS_INTERRUPT_21h
+	mov		[cs:Int2Fh_Handler.fpPreviousInt2FhHandler], bx
+	mov		[cs:Int2Fh_Handler.fpPreviousInt2FhHandler+2], es
+	mov		dx, Int2Fh_Handler
+	jmp		SHORT HookInterruptVectorInALwithHandlerInCSDX
+
+
+;--------------------------------------------------------------------
+; UnhookInterrupt2Fh
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DX, DS
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+UnhookInterrupt2Fh:
+	lds		dx, [cs:Int2Fh_Handler.fpPreviousInt2FhHandler]
+	mov		ax, ds
+	or		ax, dx
+	jz		SHORT NotHooked		; Only hooked on DOS 5+
+	mov		al, DOS_TSR_MULTIPLEX_INTERRUPT_2Fh
+	SKIP2B	f
+
+;--------------------------------------------------------------------
+; HookInterruptVectorInALwithHandlerInCSDX
+;	Parameters:
+;		AL:		Interrupt vector to hook
+;		DX:		Offset to handler
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AH, DS
+;--------------------------------------------------------------------
+HookInterruptVectorInALwithHandlerInCSDX:
+	push	cs
+	pop		ds
+	; Fall to HookInterruptVectorInALwithHandlerInDSDX
+
+;--------------------------------------------------------------------
+; HookInterruptVectorInALwithHandlerInDSDX
+;	Parameters:
+;		AL:		Interrupt vector to hook
+;		DX:		Offset to handler
+;		DS:		Segment of handler
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AH
+;--------------------------------------------------------------------
+HookInterruptVectorInALwithHandlerInDSDX:
+	mov		ah, SET_INTERRUPT_VECTOR
+	int		DOS_INTERRUPT_21h
+NotHooked:
+	ret
+
Index: trunk/Assembly_Library/Src/Menu/Dialog/Dialog.asm
===================================================================
--- trunk/Assembly_Library/Src/Menu/Dialog/Dialog.asm	(revision 592)
+++ trunk/Assembly_Library/Src/Menu/Dialog/Dialog.asm	(revision 593)
@@ -32,5 +32,5 @@
 ;		AX:		Selected item
 ;	Corrupts registers:
-;		BX, CX, DX, SI, DI
+;		BX, CX, DX, DI
 ;--------------------------------------------------------------------
 ALIGN JUMP_ALIGN
@@ -38,5 +38,5 @@
 	push	es
 	push	ds
-	mov		di, bp								; Backup parent MENU
+	mov		di, bp							; Backup parent MENU
 	mov		cx, DIALOG_size
 	eENTER_STRUCT cx
@@ -52,4 +52,5 @@
 
 	mov		ax, [bp+MENUINIT.wHighlightedItem]
+	mov		si, [bp+DIALOG.fpDialogIO]		; Restore SI
 	eLEAVE_STRUCT DIALOG_size
 	pop		ds
Index: trunk/Assembly_Library/Src/Menu/Dialog/DialogFile.asm
===================================================================
--- trunk/Assembly_Library/Src/Menu/Dialog/DialogFile.asm	(revision 592)
+++ trunk/Assembly_Library/Src/Menu/Dialog/DialogFile.asm	(revision 593)
@@ -32,11 +32,23 @@
 ;		Nothing
 ;	Corrupts registers:
-;		AX, BX, CX, DX, SI, DI
+;		AX, BX, CX, DX, DI
 ;--------------------------------------------------------------------
 ALIGN JUMP_ALIGN
 DialogFile_GetFileNameWithIoInDSSI:
+	; We need to store default drive because user might change drive but
+	; then cancel the file selection. In that case the original default directory
+	; must be restored.
+	call	Drive_GetDefaultToAL
+	push	ax
+
 	mov		bx, FileEventHandler
 	mov		BYTE [si+FILE_DIALOG_IO.bUserCancellation], TRUE
-	jmp		Dialog_DisplayWithDialogInputInDSSIandHandlerInBX
+	call	Dialog_DisplayWithDialogInputInDSSIandHandlerInBX
+
+	; Now restore the default drive if user cancellation
+	pop		dx
+	cmp		BYTE [si+FILE_DIALOG_IO.bUserCancellation], TRUE
+	je		Drive_SetDefaultFromDL
+	ret
 
 
Index: trunk/Assembly_Library/Src/Util/Bit.asm
===================================================================
--- trunk/Assembly_Library/Src/Util/Bit.asm	(revision 592)
+++ trunk/Assembly_Library/Src/Util/Bit.asm	(revision 593)
@@ -86,4 +86,7 @@
 	jb		SHORT Bit_SetToAXfromIndexInCL
 
+%ifdef USE_NEC_V
+	eSET1	dx, cl				; SET1 ignores bits 7...4 in CL
+%else
 	sub		cl, 16
 	xchg	ax, dx
@@ -91,4 +94,5 @@
 	xchg	dx, ax
 	add		cl, 16
+%endif
 	ret
 
@@ -106,4 +110,7 @@
 ALIGN JUMP_ALIGN
 Bit_SetToAXfromIndexInCL:
+%ifdef USE_NEC_V
+	eSET1	ax, cl
+%else
 	push	dx
 
@@ -113,4 +120,5 @@
 
 	pop		dx
+%endif
 	ret
 
Index: trunk/Assembly_Library/Src/Util/CMOS.asm
===================================================================
--- trunk/Assembly_Library/Src/Util/CMOS.asm	(revision 593)
+++ trunk/Assembly_Library/Src/Util/CMOS.asm	(revision 593)
@@ -0,0 +1,142 @@
+; Project name	:	Assembly Library
+; Description	:	Functions for accessing CMOS.
+
+;
+; XTIDE Universal BIOS and Associated Tools
+; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2018 by XTIDE Universal BIOS Team.
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+;
+
+
+;--------------------------------------------------------------------
+; CMOS_WriteALtoIndexInDL
+;	Parameters:
+;		AL:		Byte to write
+;		DL:		CMOS address to write to
+;	Returns:
+;		Interrupts enabled and NMI disabled
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+CMOS_WriteALtoIndexInDL:
+	push	ax
+	call	SetDLtoIndexRegister
+	pop		ax
+	out		CMOS_DATA_REGISTER, al
+	sti
+	ret
+
+
+;--------------------------------------------------------------------
+; CMOS_ReadFromIndexInDLtoAL
+;	Parameters:
+;		DL:		CMOS address to read from
+;	Returns:
+;		AL:		Byte read from CMOS
+;		Interrupts enabled and NMI disabled
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+CMOS_ReadFromIndexInDLtoAL:
+	call	SetDLtoIndexRegister
+	in		al, CMOS_DATA_REGISTER
+	sti
+	ret
+
+
+;--------------------------------------------------------------------
+; SetDLtoIndexRegister
+;	Parameters:
+;		DL:		CMOS address to select
+;	Returns:
+;		Interrupts disabled and NMI disabled
+;	Corrupts registers:
+;		AL
+;--------------------------------------------------------------------
+SetDLtoIndexRegister:
+	mov		al, dl
+	or		al, FLG_CMOS_INDEX_NMI_DISABLE	; Disable NMI
+	cli
+	out		CMOS_INDEX_REGISTER, al
+	ret		; Return works as I/O delay
+
+
+;--------------------------------------------------------------------
+; CMOS_Verify10hTo2Dh
+;	Parameters:
+;		Nothing
+;	Returns:
+;		ZF:		Set if valid checksum
+;		Interrupts disabled and NMI disabled
+;	Corrupts registers:
+;		AX, CX, DX
+;--------------------------------------------------------------------
+CMOS_Verify10hTo2Dh:
+	; Get checksum WORD from CMOS
+	mov		dl, CHECKSUM_OF_BYTES_10hTo2Dh_HIGH
+	call	CMOS_ReadFromIndexInDLtoAL
+	xchg	ah, al
+	inc		dx			; CHECKSUM_OF_BYTES_10hTo2Dh_LOW
+	call	CMOS_ReadFromIndexInDLtoAL
+	push	ax			; Store checksum word
+
+	; Verify checksum
+	call	GetSumOfBytes10hto2DhtoCX
+	pop		ax
+	cmp		ax, cx		; ZF set if checksum verified
+	ret
+
+
+;--------------------------------------------------------------------
+; CMOS_StoreNewChecksumFor10hto2Dh
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Interrupts disabled and NMI disabled
+;	Corrupts registers:
+;		AX, CX, DX
+;--------------------------------------------------------------------
+CMOS_StoreNewChecksumFor10hto2Dh:
+	call	GetSumOfBytes10hto2DhtoCX
+
+	; Write it to CMOS
+	xchg	ax, cx
+	mov		dl, CHECKSUM_OF_BYTES_10hTo2Dh_LOW
+	call	CMOS_WriteALtoIndexInDL
+	xchg	al, ah
+	dec		dx			; CHECKSUM_OF_BYTES_10hTo2Dh_HIGH
+	jmp		SHORT CMOS_WriteALtoIndexInDL
+
+
+;--------------------------------------------------------------------
+; GetSumOfBytes10hto2DhtoCX
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CX:		Sum of CMOS bytes 10h to 2Dh
+;		Interrupts disabled and NMI disabled
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+GetSumOfBytes10hto2DhtoCX:
+	xor		cx, cx			; Sum
+	mov		dx, 10h			; First index
+
+.AddNextByte:
+	call	CMOS_ReadFromIndexInDLtoAL
+	xor		ah, ah
+	add		cx, ax
+	inc		dx
+	cmp		dl, 2Dh			; Last index
+	jbe		.AddNextByte
+	ret
Index: trunk/XTIDE_Universal_BIOS/Inc/ATA_ID.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS/Inc/ATA_ID.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Inc/ATA_ID.inc	(revision 593)
@@ -56,11 +56,13 @@
 PIO_6_MIN_ACTIVE_TIME_NS	EQU		55
 
-; PIO Minimum Recovery Times or Inactive Times (t2i) can be calculated
-; from Minimum Cycle Time (t0) - Minimum Active Time (t2) - Address Valid Time (t1).
-; I'm not sure about this calculation so correct me if I'm wrong!
-; Recovery time should be calculated at run time since Cycle Time t0 can be
-; read from ATA information (ATA2+) but most drives just report the
-; Min Cycle Times listed above.
-
+; PIO 0...2 Maximum Addr valid to IOCS16- released (t8)
+PIO_0_MAX_ADDR_VALID_TO_IOCS16_RELEASED		EQU		60
+PIO_1_MAX_ADDR_VALID_TO_IOCS16_RELEASED		EQU		45
+PIO_2_MAX_ADDR_VALID_TO_IOCS16_RELEASED		EQU		30
+
+; PIO DIOR-/DIOW- to address valid hold (t9)
+PIO_0_DIORW_TO_ADDR_VALID_HOLD				EQU		20
+PIO_1_DIORW_TO_ADDR_VALID_HOLD				EQU		15
+PIO_2_DIORW_TO_ADDR_VALID_HOLD				EQU		10
 
 
Index: trunk/XTIDE_Universal_BIOS/Inc/BootVars.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS/Inc/BootVars.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Inc/BootVars.inc	(revision 593)
@@ -29,19 +29,4 @@
 BOOT_READ_RETRY_TIMES		EQU		3
 
-; Pre-boot variables. These do not exist after successful boot to OS.
-; Segment is always 0000h, same as BDA segment
-struc BOOTVARS
-						resb	7C00h
-	.rgbAtaInfo:						; 7C00h, ATA Information for drive detection
-	.rgbBootSect		resb 	512		; 7C00h, Boot sector
-						resb	256		; Boot Menu stack
-	.rgbMnuStack:
-	.dwPostStack		resb	4		; POST stack pointer when entering INT 19h
-%ifdef MODULE_HOTKEYS
-	.hotkeyVars			resb	HOTKEYVARS_size
-%endif
-	.rgDrvDetectInfo:					; Array containing DRVDETECTINFO structs
-endstruc
-
 
 %ifdef MODULE_HOTKEYS
@@ -66,4 +51,21 @@
 
 %endif ; MODULE_HOTKEYS
+
+
+; Pre-boot variables. These do not exist after successful boot to OS.
+; Segment is always 0000h, same as BDA segment
+struc BOOTVARS
+						resb	7C00h
+	.rgbAtaInfo:						; 7C00h, ATA Information for drive detection
+	.rgbBootSect		resb 	512		; 7C00h, Boot sector
+						resb	256		; Boot Menu stack
+	.rgbMnuStack:
+	.dwPostStack		resb	4		; POST stack pointer when entering INT 19h
+%ifdef MODULE_HOTKEYS
+	.hotkeyVars			resb	HOTKEYVARS_size	; Must be located just before DRVDETECTINFO structs
+%endif
+	.rgDrvDetectInfo:					; Array containing DRVDETECTINFO structs
+endstruc
+
 
 ; MAX_HARD_DISK_NAME_LENGTH must be defined ahead of the DRVDETECTINFO structure to avoid problems with NASM
Index: trunk/XTIDE_Universal_BIOS/Inc/HotkeyBar.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS/Inc/HotkeyBar.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Inc/HotkeyBar.inc	(revision 593)
@@ -23,4 +23,6 @@
 MIN_TIME_TO_DISPLAY_HOTKEY_BAR			EQU	(4000/55)	; 4000 ms
 
+FIRST_FUNCTION_KEY_SCANCODE				EQU	3Bh	; F1 key
+
 ROM_BOOT_HOTKEY_SCANCODE				EQU	42h	; F8
 
Index: trunk/XTIDE_Universal_BIOS/Inc/RamVars.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS/Inc/RamVars.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Inc/RamVars.inc	(revision 593)
@@ -29,4 +29,30 @@
 %ifdef MODULE_SERIAL_FLOPPY OR MODULE_DRIVEXLATE
 	%define NEED_XLATEVARS
+%endif
+
+
+%ifdef NEED_XLATEVARS
+; Variables for translating drive numbers.
+	struc XLATEVARS
+	%ifdef MODULE_SERIAL_FLOPPY
+		.bFlopCreateCnt:
+		.bFlopCntAndFirst	resb	1	; Normally, packed starting floppy drive number (high order 7 bits)
+										; and number of drives (low order bit, max 2 drives supported).
+										; During initialization, until the end of DetectDrives_FromAllIDEControllers,
+										; this byte contains the raw number of floppy drives seen
+										; (using .bFlopCreateCnt)
+	%else
+							resb	1	; alignment
+	%endif
+
+	%ifdef MODULE_DRIVEXLATE
+		.bXlatedDrv			resb	1	; Drive number after translation
+		.wFDandHDswap:
+		.bFDSwap			resb	1	; Floppy Drive to swap to 00h and vice versa
+		.bHDSwap			resb	1	; Hard Drive to swap to 80h and vice versa
+	%else
+							resb	1	; alignment
+	%endif
+	endstruc
 %endif
 
@@ -66,29 +92,4 @@
 RAMVARS_DRV_DETECT_SIGNATURE	EQU	5A5Ah	; Signature when BIOS is in drive detection mode
 
-
-%ifdef NEED_XLATEVARS
-; Variables for translating drive numbers.
-	struc XLATEVARS
-	%ifdef MODULE_SERIAL_FLOPPY
-		.bFlopCreateCnt:
-		.bFlopCntAndFirst	resb	1	; Normally, packed starting floppy drive number (high order 7 bits)
-										; and number of drives (low order bit, max 2 drives supported).
-										; During initialization, until the end of DetectDrives_FromAllIDEControllers,
-										; this byte contains the raw number of floppy drives seen
-										; (using .bFlopCreateCnt)
-	%else
-							resb	1	; alignment
-	%endif
-
-	%ifdef MODULE_DRIVEXLATE
-		.bXlatedDrv			resb	1	; Drive number after translation
-		.wFDandHDswap:
-		.bFDSwap			resb	1	; Floppy Drive to swap to 00h and vice versa
-		.bHDSwap			resb	1	; Hard Drive to swap to 80h and vice versa
-	%else
-							resb	1	; alignment
-	%endif
-	endstruc
-%endif
 
 %ifdef MODULE_SERIAL_FLOPPY
Index: trunk/XTIDE_Universal_BIOS/Inc/RomVars.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS/Inc/RomVars.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Inc/RomVars.inc	(revision 593)
@@ -22,71 +22,33 @@
 %define ROMVARS_INC
 
-; ROM Variables. Written to the ROM image before flashing.
-struc ROMVARS
-	.wRomSign			resb	2	; ROM Signature (AA55h)
-	.bRomSize			resb	1	; ROM size in 512 byte blocks
-	.rgbJump			resb	3	; First instruction to ROM init (jmp)
-
-	.rgbSign			resb	8	; Signature for XTIDE Configurator Program
-	.szTitle			resb	31	; BIOS title string
-	.szVersion			resb	25	; BIOS version string
-
-	.wFlags				resb	2	; Word for ROM flags
-	.wDisplayMode		resb	2	; Display mode for boot menu
-	.wBootTimeout		resb	2	; Boot Menu selection timeout in system timer ticks
-	.pColorTheme		resb	2	; Ptr to the color attribute struc used by the boot menu and hotkey bar
-	.bIdeCnt			resb	1	; Number of available IDE controllers
-	.bBootDrv			resb	1	; Default drive to boot from
-	.bMinFddCnt			resb	1	; Minimum number of Floppy Drives
-	.bStealSize			resb	1	; Number of 1kB blocks stolen from 640kB base RAM
-	.bIdleTimeout		resb	1	; Standby timer value
-
-	.ideVarsBegin:
-	.ideVars0			resb	IDEVARS_size
-	.ideVars1			resb	IDEVARS_size
-	.ideVars2			resb	IDEVARS_size
-	.ideVars3			resb	IDEVARS_size
-
-%ifdef MODULE_SERIAL
-	.ideVarsSerialAuto	resb	IDEVARS_size
-%endif
-
-	.ideVarsEnd:
+
+; Master/Slave drive specific parameters
+struc DRVPARAMS
+	.wFlags			resb	2	; Drive flags
+	.dwMaximumLBA:				; User specified maximum number of sectors
+	.wCylinders		resb	2	; User specified cylinders (1...16383)
+	.wHeadsAndSectors:
+	.bHeads			resb	1	; User specified Heads (1...16)
+	.bSect			resb	1	; User specified Sectors per track (1...63)
 endstruc
 
-%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
-	%if ROMVARS.ideVarsEnd & 0xff00 <> 0
-		%error ".ideVars structures must fit within the first 256 bytes of the ROM image"
-	%endif
-	%if (ROMVARS.ideVarsEnd - ROMVARS.ideVarsBegin) = 0
-		%error "there must be at least one .ideVars structure, it would be bizarre if this were not true, but it is assumed in the ah0h reset code."
-	%endif
-%endif
-
-NUMBER_OF_IDEVARS					EQU	((ROMVARS.ideVarsEnd - ROMVARS.ideVarsBegin) / IDEVARS_size)
-
-; Bit defines for ROMVARS.wFlags
-FLG_ROMVARS_FULLMODE				EQU	(1<<0)	; Full operating mode (steals base RAM, supports EBIOS etc.)
-FLG_ROMVARS_SERIAL_SCANDETECT 		EQU	(1<<3)	; Scan COM ports at the end of drive detection.  Can also be invoked
-												; by holding down the ALT key at the end of drive detection.
-												; (Conveniently, this is 8, a fact we exploit when testing the bit)
-
-; Here in case the configuration needs to know functionality is present. Note! Changing the order/location of these flags
-; also requires changes elsewhere as they are usually tested using byte-accesses for efficiency.
-FLG_ROMVARS_MODULE_POWER_MANAGEMENT		EQU	(1<<5)
-FLG_ROMVARS_MODULE_8BIT_IDE				EQU	(1<<6)
-FLG_ROMVARS_MODULE_8BIT_IDE_ADVANCED	EQU (1<<7)
-FLG_ROMVARS_MODULE_ADVANCED_ATA			EQU	(1<<8)
-FLG_ROMVARS_MODULE_BOOT_MENU			EQU	(1<<9)
-FLG_ROMVARS_MODULE_EBIOS				EQU	(1<<10)
-FLG_ROMVARS_MODULE_HOTKEYS				EQU	(1<<11)
-FLG_ROMVARS_MODULE_IRQ					EQU	(1<<12)
-FLG_ROMVARS_MODULE_SERIAL				EQU (1<<13)
-FLG_ROMVARS_MODULE_SERIAL_FLOPPY		EQU (1<<14)
-FLG_ROMVARS_MODULE_STRINGS_COMPRESSED	EQU (1<<15)
-
-
-; Boot Menu Display Modes (see Assembly Library Display.inc for standard modes)
-DEFAULT_TEXT_MODE		EQU	4
+; Bit defines for DRVPARAMS.wFlags - these flags are accessed as bytes so changes here might require changes elsewhere
+MASK_DRVPARAMS_WRITECACHE		EQU	(3<<0)	; Bits 0...1, Drive internal write cache settings (must start at bit 0)
+	DEFAULT_WRITE_CACHE				EQU	0	; Must be 0
+	DISABLE_WRITE_CACHE				EQU	1
+	ENABLE_WRITE_CACHE				EQU	2
+MASK_DRVPARAMS_TRANSLATEMODE	EQU	(3<<TRANSLATEMODE_FIELD_POSITION)	; Bits 2...3, Position shared with DPT
+	TRANSLATEMODE_FIELD_POSITION	EQU	2
+	TRANSLATEMODE_NORMAL			EQU	0	; Must be zero
+	TRANSLATEMODE_LARGE				EQU	1
+	TRANSLATEMODE_ASSISTED_LBA		EQU	2	; 28-bit or 48-bit LBA
+	TRANSLATEMODE_AUTO				EQU	3	; Only available in ROMVARS, not in DPTs
+FLG_DRVPARAMS_BLOCKMODE			EQU	(1<<4)	; Enable Block mode transfers
+FLG_DRVPARAMS_USERCHS			EQU	(1<<5)	; User specified P-CHS values
+	MAX_PCHS_CYLINDERS				EQU	16383
+	MAX_PCHS_HEADS					EQU	16
+	MAX_PCHS_SECTORS_PER_TRACK		EQU	63
+	MAX_PCHS_TOTAL_SECTOR_COUNT		EQU	(MAX_PCHS_CYLINDERS * MAX_PCHS_HEADS * MAX_PCHS_SECTORS_PER_TRACK)	; 16,514,064
+FLG_DRVPARAMS_USERLBA			EQU	(1<<6)	; User specified LBA value
 
 
@@ -173,32 +135,79 @@
 XTCF_DEVICE_OFFSET						EQU	FIRST_XTCF_DEVICE						; Used for XT-CF device <--> mode conversion
 
-; Master/Slave drive specific parameters
-struc DRVPARAMS
-	.wFlags			resb	2	; Drive flags
-	.dwMaximumLBA:				; User specified maximum number of sectors
-	.wCylinders		resb	2	; User specified cylinders (1...16383)
-	.wHeadsAndSectors:
-	.bHeads			resb	1	; User specified Heads (1...16)
-	.bSect			resb	1	; User specified Sectors per track (1...63)
+
+; ROM Variables. Written to the ROM image before flashing.
+struc ROMVARS
+	.wRomSign			resb	2	; ROM Signature (AA55h)
+	.bRomSize			resb	1	; ROM size in 512 byte blocks
+	.rgbJump			resb	3	; First instruction to ROM init (jmp)
+
+	.rgbSign			resb	8	; Signature for XTIDE Configurator Program
+	.szTitle			resb	31	; BIOS title string
+	.szVersion			resb	25	; BIOS version string
+
+	.wFlags				resb	2	; Word for ROM flags
+	.wDisplayMode		resb	2	; Display mode for boot menu
+	.wBootTimeout		resb	2	; Boot Menu selection timeout in system timer ticks
+	.pColorTheme		resb	2	; Ptr to the color attribute struc used by the boot menu and hotkey bar
+	.bIdeCnt			resb	1	; Number of available IDE controllers
+	.bBootDrv			resb	1	; Default drive to boot from
+	.bMinFddCnt			resb	1	; Minimum number of Floppy Drives
+	.bStealSize			resb	1	; Number of 1kB blocks stolen from 640kB base RAM
+	.bIdleTimeout		resb	1	; Standby timer value
+
+	.ideVarsBegin:
+	.ideVars0			resb	IDEVARS_size
+	.ideVars1			resb	IDEVARS_size
+	.ideVars2			resb	IDEVARS_size
+	.ideVars3			resb	IDEVARS_size
+
+%ifdef MODULE_SERIAL
+	.ideVarsSerialAuto	resb	IDEVARS_size
+%endif
+
+	.ideVarsEnd:
 endstruc
 
-; Bit defines for DRVPARAMS.wFlags - these flags are accessed as bytes so changes here might require changes elsewhere
-MASK_DRVPARAMS_WRITECACHE		EQU	(3<<0)	; Bits 0...1, Drive internal write cache settings (must start at bit 0)
-	DEFAULT_WRITE_CACHE				EQU	0	; Must be 0
-	DISABLE_WRITE_CACHE				EQU	1
-	ENABLE_WRITE_CACHE				EQU	2
-MASK_DRVPARAMS_TRANSLATEMODE	EQU	(3<<TRANSLATEMODE_FIELD_POSITION)	; Bits 2...3, Position shared with DPT
-	TRANSLATEMODE_FIELD_POSITION	EQU	2
-	TRANSLATEMODE_NORMAL			EQU	0	; Must be zero
-	TRANSLATEMODE_LARGE				EQU	1
-	TRANSLATEMODE_ASSISTED_LBA		EQU	2	; 28-bit or 48-bit LBA
-	TRANSLATEMODE_AUTO				EQU	3	; Only available in ROMVARS, not in DPTs
-FLG_DRVPARAMS_BLOCKMODE			EQU	(1<<4)	; Enable Block mode transfers
-FLG_DRVPARAMS_USERCHS			EQU	(1<<5)	; User specified P-CHS values
-	MAX_PCHS_CYLINDERS				EQU	16383
-	MAX_PCHS_HEADS					EQU	16
-	MAX_PCHS_SECTORS_PER_TRACK		EQU	63
-	MAX_PCHS_TOTAL_SECTOR_COUNT		EQU	(MAX_PCHS_CYLINDERS * MAX_PCHS_HEADS * MAX_PCHS_SECTORS_PER_TRACK)	; 16,514,064
-FLG_DRVPARAMS_USERLBA			EQU	(1<<6)	; User specified LBA value
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if ROMVARS.ideVarsEnd & 0xff00 <> 0
+		%error ".ideVars structures must fit within the first 256 bytes of the ROM image"
+	%endif
+	%if (ROMVARS.ideVarsEnd - ROMVARS.ideVarsBegin) = 0
+		%error "there must be at least one .ideVars structure, it would be bizarre if this were not true, but it is assumed in the ah0h reset code."
+	%endif
+%endif
+
+NUMBER_OF_IDEVARS					EQU	((ROMVARS.ideVarsEnd - ROMVARS.ideVarsBegin) / IDEVARS_size)
+
+; Bit defines for ROMVARS.wFlags
+FLG_ROMVARS_FULLMODE					EQU	(1<<0)	; Full operating mode (steals base RAM, supports EBIOS etc.)
+FLG_ROMVARS_IGNORE_MOTHERBOARD_DRIVES	EQU	(1<<1)	; Ignores drives configured in motherboard BIOS setup.
+													; For now it is a hack to get Windows 95 IDE drivers working
+													; but it will be needed later when XTUB supports dynamic drive overlay.
+													; Because of that this must be included into AT builds and cannot be a
+													; module (any AT or 386 must be installable to the hard drive so
+													; there won't be need for even more different builds).
+FLG_ROMVARS_SERIAL_SCANDETECT 			EQU	(1<<3)	; Scan COM ports at the end of drive detection.  Can also be invoked
+													; by holding down the ALT key at the end of drive detection.
+													; (Conveniently, this is 8, a fact we exploit when testing the bit)
+
+; Here in case the configuration needs to know functionality is present. Note! Changing the order/location of these flags
+; also requires changes elsewhere as they are usually tested using byte-accesses for efficiency.
+FLG_ROMVARS_MODULE_POWER_MANAGEMENT		EQU	(1<<5)
+FLG_ROMVARS_MODULE_8BIT_IDE				EQU	(1<<6)
+FLG_ROMVARS_MODULE_8BIT_IDE_ADVANCED	EQU (1<<7)
+FLG_ROMVARS_MODULE_ADVANCED_ATA			EQU	(1<<8)
+FLG_ROMVARS_MODULE_BOOT_MENU			EQU	(1<<9)
+FLG_ROMVARS_MODULE_EBIOS				EQU	(1<<10)
+FLG_ROMVARS_MODULE_HOTKEYS				EQU	(1<<11)
+FLG_ROMVARS_MODULE_IRQ					EQU	(1<<12)
+FLG_ROMVARS_MODULE_SERIAL				EQU (1<<13)
+FLG_ROMVARS_MODULE_SERIAL_FLOPPY		EQU (1<<14)
+FLG_ROMVARS_MODULE_STRINGS_COMPRESSED	EQU (1<<15)
+
+
+; Boot Menu Display Modes (see Assembly Library Display.inc for standard modes)
+DEFAULT_TEXT_MODE		EQU	4
+
 
 %endif ; ROMVARS_INC
Index: trunk/XTIDE_Universal_BIOS/Src/Handlers/Int19h.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Handlers/Int19h.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Handlers/Int19h.asm	(revision 593)
@@ -90,9 +90,4 @@
 ;--------------------------------------------------------------------
 .InitializeBiosAndDetectDrives:
-%ifdef MODULE_HOTKEYS
-	call	TimerTicks_ReadFromBdaToAX
-	mov		[es:BOOTVARS.hotkeyVars+HOTKEYVARS.wTimeWhenDisplayed], ax
-%endif
-
 	call	Initialize_AndDetectDrives
 
Index: trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/AdvAtaInit.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/AdvAtaInit.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/AdvAtaInit.asm	(revision 593)
@@ -33,7 +33,25 @@
 ;				Cleared if no controller
 ;	Corrupts registers:
-;		BX
+;		BX, CX
 ;--------------------------------------------------------------------
 AdvAtaInit_DetectControllerForIdeBaseInBX:
+	; Detect if system has PCI bus. If it does, we can skip VLB detection. This is
+	; good thing since detecting Vision QD6850 is dangerous since Intel PIIX4 south bridge
+	; mirrors Interrupt Controller registers from Axh to Bxh. This can lead to faulty
+	; detection of QD6850 that will eventually crash the system when ports are written.
+
+	; We should save the 32-bit registers but we don't since system BIOS has stored
+	; them already and we don't use the 32-bit registers ourselves anywhere at the moment.
+	push	bx
+	push	di
+	xor		edi, edi		; Some BIOSes require this to be set to zero
+	mov		ax, PCI_INSTALLATION_CHECK
+	int		BIOS_TIME_PCI_PNP_1Ah
+	pop		di
+	pop		bx
+	test	ah, ah
+	jz		SHORT .ThisSystemHasPCIbus
+
+	; Detect VLB controllers
 	call	Vision_DetectAndReturnIDinAXandPortInDXifControllerPresent
 	jnz		SHORT .NoVisionControllerFound
@@ -51,4 +69,5 @@
 
 .NoAdvancedControllerForPortBX:
+.ThisSystemHasPCIbus:
 	xor		ax, ax		; Clear ID in AX and CF
 	ret
Index: trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/Vision.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/Vision.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/Vision.asm	(revision 593)
@@ -41,8 +41,4 @@
 	in		al, QD65XX_BASE_PORT + QD65XX_CONFIG_REGISTER_in
 
-%ifdef DANGEROUS_DETECTION
-	; Checking alternative base port is currently commented away
-	; since Intel PIIX4 south bridge mirrors Interrupt Controller registers
-	; from Axh to Bxh.
 	call	IsConfigRegisterWithIDinAL
 	je		SHORT VisionControllerDetected.Return
@@ -51,5 +47,4 @@
 	mov		dl, QD65XX_ALTERNATIVE_BASE_PORT
 	in		al, QD65XX_ALTERNATIVE_BASE_PORT + QD65XX_CONFIG_REGISTER_in
-%endif ; DANGEROUS_DETECTION
 	; Fall to IsConfigRegisterWithIDinAL
 
@@ -198,5 +193,7 @@
 
 	; Calculate Recovery Time value for QD65xx IDE Timing Register
-	call	AtaID_GetRecoveryTimeToAXfromPioModeInBXandCycleTimeInCX
+	xchg	ax, cx
+	eMOVZX	cx, BYTE [cs:bx+.rgbToSubtractFromCycleTimeBasedOnPIOmode]
+	sub		ax, cx
 	mov		bx, bp						; Active Time value now in BL
 	mov		bp, QD65xx_MAX_RECOVERY_TIME_CLOCKS | (QD65xx_MIN_RECOVERY_TIME_CLOCKS << 8)
@@ -209,4 +206,15 @@
 	ret									; Return with CF cleared
 
+.rgbToSubtractFromCycleTimeBasedOnPIOmode:
+	; For PIO 0 to 2 this method (t0 - (t1+t8+t9)) seems to give closest (little less) values to the fixed preset
+	; values used by QDI6580 DOS driver v3.7
+	db		(PIO_0_MIN_ADDRESS_VALID_NS + PIO_0_MAX_ADDR_VALID_TO_IOCS16_RELEASED + PIO_0_DIORW_TO_ADDR_VALID_HOLD)
+	db		(PIO_1_MIN_ADDRESS_VALID_NS + PIO_1_MAX_ADDR_VALID_TO_IOCS16_RELEASED + PIO_1_DIORW_TO_ADDR_VALID_HOLD)
+	db		(PIO_2_MIN_ADDRESS_VALID_NS + PIO_2_MAX_ADDR_VALID_TO_IOCS16_RELEASED + PIO_2_DIORW_TO_ADDR_VALID_HOLD)
+	db		102		; QDI6580 DOS driver v3.7 uses fixed values for PIO 3...
+	db		61		; ...and PIO 4. No idea where these values come from.
+	db		(PIO_5_MIN_CYCLE_TIME_NS / 2) ; PIO 5 and 6 were not available when QD6850 was released. Use values...
+	db		(PIO_6_MIN_CYCLE_TIME_NS / 2) ; ...that resembles those used for PIO 4
+
 
 ;--------------------------------------------------------------------
@@ -226,7 +234,7 @@
 
 	; Get VLB Cycle Time in nanosecs
-	mov		cl, VLB_33MHZ_CYCLE_TIME	; Assume 33 MHz or slower VLB bus
+	mov		cl, VLB_33MHZ_CYCLE_TIME	; Assume 33 MHz or slower VLB bus (30 ns)
 	test	BYTE [di+DPT_ADVANCED_ATA.wControllerID], FLG_QDCONFIG_ID3
-	eCMOVZ	cl, VLB_40MHZ_CYCLE_TIME
+	eCMOVZ	cl, VLB_40MHZ_CYCLE_TIME	; (25 ns)
 
 	; Convert value in AX to VLB ticks
Index: trunk/XTIDE_Universal_BIOS/Src/Initialization/AtaID.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Initialization/AtaID.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Initialization/AtaID.asm	(revision 593)
@@ -211,32 +211,4 @@
 
 ;--------------------------------------------------------------------
-; AtaID_GetRecoveryTimeToAXfromPioModeInBXandCycleTimeInCX
-;	Parameters:
-;		BX:		PIO Mode
-;		CX:		PIO Cycle Time in nanosecs
-;	Returns:
-;		AX:		Active Time in nanosecs
-;	Corrupts registers:
-;		BX, CX
-;--------------------------------------------------------------------
-AtaID_GetRecoveryTimeToAXfromPioModeInBXandCycleTimeInCX:
-	call	AtaID_GetActiveTimeToAXfromPioModeInBX
-	mov		bl, [cs:bx+.rgbPioModeToAddressValidTimeNs]
-	sub		cx, bx	; Cycle Time (t0) - Address Valid Time (t1)
-	sub		cx, ax	; - Active Time (t2)
-	xchg	ax, cx	; AX = Recovery Time (t2i)
-	ret
-
-.rgbPioModeToAddressValidTimeNs:
-	db		PIO_0_MIN_ADDRESS_VALID_NS
-	db		PIO_1_MIN_ADDRESS_VALID_NS
-	db		PIO_2_MIN_ADDRESS_VALID_NS
-	db		PIO_3_MIN_ADDRESS_VALID_NS
-	db		PIO_4_MIN_ADDRESS_VALID_NS
-	db		PIO_5_MIN_ADDRESS_VALID_NS
-	db		PIO_6_MIN_ADDRESS_VALID_NS
-
-
-;--------------------------------------------------------------------
 ; AtaID_GetActiveTimeToAXfromPioModeInBX
 ;	Parameters:
Index: trunk/XTIDE_Universal_BIOS/Src/Initialization/DetectDrives.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Initialization/DetectDrives.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Initialization/DetectDrives.asm	(revision 593)
@@ -95,4 +95,41 @@
 ; FindDPT_ForDriveNumber will not find any drives that are ours.
 ;
+
+; Here we might want to replace BIOS configured drives with the ones we detected.
+; Primary reason is to support dynamic overlay feature in the future. Second reason
+; is a hack to get Windows 95 load proper IDE drivers.
+; 
+; The Windows hack has two parts. First part is to try to alter CMOS address 12h as that
+; is what Windows 95 driver reads to detect IDE drives. Altering is not possible on all
+; systems since CMOS has a checksum but it's location is not standardized. We will first
+; try to detect valid checksum. If it succeeds, then it is safe to assume this system
+; has compatible CMOS and we can alter it.
+; If verify fails, we do the more dirty hack to zero BDA drive count. Then Windows 95 works
+; as long as user has configured at least one drive in the BIOS setup.
+
+%ifdef USE_AT	; FLG_ROMVARS_IGNORE_MOTHERBOARD_DRIVES is for AT builds only
+
+	%ifdef MODULE_WIN95_CMOS_HACK
+		mov		dl, HARD_DISK_TYPES
+		call	CMOS_ReadFromIndexInDLtoAL
+		test	al, al
+		jnz		SHORT .ContinueInitialization	; CMOS byte 12h is ready for Windows 95
+		call	CMOS_Verify10hTo2Dh
+		jnz		SHORT .ClearBdaDriveCount		; Unsupported BIOS, use plan B
+	
+		; Now we can alter CMOS location 12h
+		mov		dl, HARD_DISK_TYPES
+		mov		al, 0F0h	; Drive 0 type 16...47 but Windows doesn't care as long as this is not zero
+		call	CMOS_WriteALtoIndexInDL
+		call	CMOS_StoreNewChecksumFor10hto2Dh
+	%endif
+
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_IGNORE_MOTHERBOARD_DRIVES
+	jz		SHORT .ContinueInitialization
+.ClearBdaDriveCount:
+	mov		BYTE [es:BDA.bHDCount], 0	; Set hard disk count to zero
+.ContinueInitialization:
+%endif
+
 	mov		cx, [RAMVARS.wDrvCntAndFlopCnt]		; Our count of hard disks
 	mov		al, [es:BDA.bHDCount]
Index: trunk/XTIDE_Universal_BIOS/Src/Main.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Main.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Main.asm	(revision 593)
@@ -77,5 +77,9 @@
 ;---------------------------;
 %ifdef USE_AT
+%ifdef USE_386
+	at	ROMVARS.wFlags,			dw	FLG_ROMVARS_FULLMODE | FLG_ROMVARS_IGNORE_MOTHERBOARD_DRIVES | MASK_ROMVARS_INCLUDED_MODULES
+%else
 	at	ROMVARS.wFlags,			dw	FLG_ROMVARS_FULLMODE | MASK_ROMVARS_INCLUDED_MODULES
+%endif
 	at	ROMVARS.wDisplayMode,	dw	DEFAULT_TEXT_MODE
 %ifdef MODULE_BOOT_MENU
@@ -188,4 +192,7 @@
 
 	%include "AssemblyLibrary.asm"
+%ifdef MODULE_WIN95_CMOS_HACK
+	%include "CMOS.asm"				; This belongs in the Assembly Library
+%endif
 
 	; String compression tables need to come after the AssemblyLibrary (since they depend on addresses
Index: trunk/XTIDE_Universal_BIOS/Src/Menus/HotkeyBar.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Menus/HotkeyBar.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/Menus/HotkeyBar.asm	(revision 593)
@@ -75,4 +75,8 @@
 	mov		cl, [es:BOOTVARS.hotkeyVars+HOTKEYVARS.bFddLetter]
 	mov		di, g_szFDD
+
+	; Clear CH if floppy drive is selected for boot
+	mov		ch, [es:BOOTVARS.hotkeyVars+HOTKEYVARS.bFlags]
+	;and		ch, FLG_HOTKEY_HD_FIRST		; Needed if more flags are added
 	call	FormatDriveHotkeyString
 
@@ -92,5 +96,7 @@
 	call	BootVars_GetLetterForFirstHardDriveToAX
 	mov		ah, ANGLE_QUOTE_RIGHT
-	mov		cl, [es:BOOTVARS.hotkeyVars+HOTKEYVARS.bHddLetter]
+	mov		cx, [es:BOOTVARS.hotkeyVars+HOTKEYVARS.bHddLetter]	; Letter to CL, flags to CH
+	;and		ch, FLG_HOTKEY_HD_FIRST		; Needed if more flags are added
+	xor		ch, FLG_HOTKEY_HD_FIRST		; Clear CH if HD is selected for boot, set otherwise
 	mov		di, g_szHDD
 	call	FormatDriveHotkeyString
@@ -182,4 +188,5 @@
 ; FormatDriveHotkeyString
 ;	Parameters:
+;		CH:			Zero if letter in CL is selected for boot
 ;		CL:			Drive letter hotkey from BOOTVARS
 ;		AL:			First character for drive key string
@@ -192,6 +199,16 @@
 ;		AX, CX, DX, SI, DI
 ;--------------------------------------------------------------------
-;; No work to do before going into FormatFunctionHotkeyString
-FormatDriveHotkeyString  equ  GetNonSelectedHotkeyDescriptionAttributeToDX
+FormatDriveHotkeyString:
+	; Invalid scancodes are filtered on HotkeyBar_StoreHotkeyToBootvarsIfValidKeystrokeInAX
+	; so here we have either drive letter or function key pressed. If latter, draw
+	; drive letters as unselected
+	cmp		BYTE [es:BOOTVARS.hotkeyVars+HOTKEYVARS.bScancode], FIRST_FUNCTION_KEY_SCANCODE
+	jae		SHORT GetNonSelectedHotkeyDescriptionAttributeToDX
+
+	; Drive selected to boot from?
+	test	ch, ch
+	jnz		SHORT GetNonSelectedHotkeyDescriptionAttributeToDX
+	jmp		SHORT GetSelectedHotkeyDescriptionAttributeToDX
+
 
 ;--------------------------------------------------------------------
@@ -216,6 +233,7 @@
 %ifdef MODULE_BOOT_MENU
 
+GetSelectedHotkeyDescriptionAttributeToDX:
 	mov		si, ATTRIBUTE_CHARS.cHurryTimeout		; Selected hotkey
-	je		SHORT GetDescriptionAttributeToDX		; From compare with bScancode above
+	je		SHORT GetDescriptionAttributeToDX		; From compare with bScancode above and from FormatDriveHotkeyString
 
 GetNonSelectedHotkeyDescriptionAttributeToDX:
@@ -232,6 +250,7 @@
 %else ; if no MODULE_BOOT_MENU - No boot menu so use simpler attributes
 
+GetSelectedHotkeyDescriptionAttributeToDX:
 	mov		dx, (COLOR_ATTRIBUTE(COLOR_YELLOW, COLOR_CYAN) << 8) | MONO_REVERSE_BLINK
-	je		SHORT SelectAttributeFromDHorDLbasedOnVideoMode		; From compare with bScancode above
+	je		SHORT SelectAttributeFromDHorDLbasedOnVideoMode		; From compare with bScancode above and from FormatDriveHotkeyString
 
 GetNonSelectedHotkeyDescriptionAttributeToDX:
Index: trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/AccessDPT.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/AccessDPT.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/AccessDPT.asm	(revision 593)
@@ -64,5 +64,5 @@
 	mov		al, FLG_DEVCONTROL_nIEN	; Disable IRQ
 .EnableDeviceIrq:
-%else
+%else	; ifndef MODULE_IRQ
 	mov		al, FLG_DEVCONTROL_nIEN	; Disable IRQ
 %endif ; MODULE_IRQ
Index: trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/BootVars.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/BootVars.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/BootVars.asm	(revision 593)
@@ -35,11 +35,19 @@
 	mov		al, DRVDETECTINFO_size
 	mul		BYTE [cs:ROMVARS.bIdeCnt]
-	mov		di, BOOTVARS.rgDrvDetectInfo	; We must not initialize anything before this!
 	xchg	cx, ax
 %ifndef MODULE_HOTKEYS
+	mov		di, BOOTVARS.rgDrvDetectInfo	; We must not initialize anything before this!
 	jmp		Memory_ZeroESDIwithSizeInCX
 
 %else ; if MODULE_HOTKEYS
+	; Also zero HOTKEYVARS located above DRVDETECTINFO structs
+	mov		di, BOOTVARS.hotkeyVars
+	add		cx, BYTE HOTKEYVARS_size
 	call	Memory_ZeroESDIwithSizeInCX
+
+	; Store time when hotkeybar is displayed
+	; (it will be displayed after initialization is complete)
+	call	TimerTicks_ReadFromBdaToAX
+	mov		[es:BOOTVARS.hotkeyVars+HOTKEYVARS.wTimeWhenDisplayed], ax
 
 	; Initialize HOTKEYVARS by storing default drives to boot from
Index: trunk/XTIDE_Universal_BIOS/makefile
===================================================================
--- trunk/XTIDE_Universal_BIOS/makefile	(revision 592)
+++ trunk/XTIDE_Universal_BIOS/makefile	(revision 593)
@@ -29,4 +29,5 @@
 # MODULE_VERY_LATE_INIT       Initialize on INT 13h if our INT 19h handler is not called           #
 # MODULE_POWER_MANAGEMENT     Power Management support                                             #
+# MODULE_WIN95_CMOS_HACK      Hack for Windows 95 compatibility                                    #
 #                                                                                                  #
 # Not modules but these affect the assembly:                                                       #
@@ -34,5 +35,4 @@
 # RELOCATE_INT13H_STACK **    Relocates INT 13h stack to beginning of stolen conventional memory   #
 # RESERVE_DIAGNOSTIC_CYLINDER Reserve one L-CHS cylinder for compatibility with old BIOSes         #
-# DANGEROUS_DETECTION         Scans Advanced Controllers from dangerous ports like mirrored PIC    #
 # NO_ATAID_VALIDATION ***     Excludes code that tries to ensure proper communication with drives  #
 # USE_186                     Use instructions supported by 80188/80186 and V20/V30 and later      #
@@ -41,4 +41,5 @@
 # USE_AT                      Use features supported on AT and later systems (not available on XT) #
 # USE_UNDOC_INTEL             Optimizations for Intel CPU:s - do NOT use on NEC V20/V30/Sony CPU:s #
+# USE_NEC_V                   Optimizations for use with NEC V20/V30 processors only               #
 # CLD_NEEDED                  Only needed for compatibility with buggy software/BIOSes             #
 #                                                                                                  #
@@ -116,8 +117,9 @@
 
 DEFINES_XT_TINY = MODULE_STRINGS_COMPRESSED MODULE_8BIT_IDE NO_ATAID_VALIDATION CLD_NEEDED
-DEFINES_386_8K = $(DEFINES_AT) USE_386 MODULE_ADVANCED_ATA
+DEFINES_386 = $(DEFINES_AT) USE_386 MODULE_ADVANCED_ATA MODULE_WIN95_CMOS_HACK
+DEFINES_386_LARGE = $(DEFINES_AT_LARGE) USE_386 MODULE_ADVANCED_ATA MODULE_WIN95_CMOS_HACK
 
 DEFINES_ALL_FEATURES = MODULE_8BIT_IDE MODULE_8BIT_IDE_ADVANCED MODULE_ADVANCED_ATA MODULE_EBIOS MODULE_BOOT_MENU MODULE_HOTKEYS MODULE_IRQ MODULE_SERIAL MODULE_SERIAL_FLOPPY MODULE_STRINGS_COMPRESSED MODULE_POWER_MANAGEMENT MODULE_COMPATIBLE_TABLES
-DEFINES_ALL_FEATURES += ELIMINATE_CGA_SNOW RELOCATE_INT13H_STACK RESERVE_DIAGNOSTIC_CYLINDER
+DEFINES_ALL_FEATURES += ELIMINATE_CGA_SNOW RELOCATE_INT13H_STACK RESERVE_DIAGNOSTIC_CYLINDER MODULE_WIN95_CMOS_HACK
 
 
@@ -140,5 +142,6 @@
 DEFS_AT_LARGE = $(DEFINES_AT_LARGE:%=-D%) -DBIOS_SIZE=$(BIOS_SIZE_LARGE)
 DEFS_XT_TINY = $(DEFINES_XT_TINY:%=-D%) -DBIOS_SIZE=$(BIOS_SIZE_TINY)
-DEFS_386_8K = $(DEFINES_386_8K:%=-D%) -DBIOS_SIZE=$(BIOS_SIZE_SMALL)
+DEFS_386 = $(DEFINES_386:%=-D%) -DBIOS_SIZE=$(BIOS_SIZE_SMALL)
+DEFS_386_LARGE = $(DEFINES_386_LARGE:%=-D%) -DBIOS_SIZE=$(BIOS_SIZE_LARGE)
 DEFS_ALL_FEATURES = $(DEFINES_ALL_FEATURES:%=-D%)
 
@@ -181,8 +184,8 @@
 	@echo All done!
 
-small: xt_tiny xt xtplus at 386_8k
+small: xt_tiny xt xtplus at 386
 	@echo All small binaries built!
 
-large: xt_large xtplus_large at_large
+large: xt_large xtplus_large at_large 386_large
 	@echo All large binaries built!
 
@@ -215,7 +218,11 @@
 	@echo * Tiny XT version "$(TARGET)_tiny.bin" built.
 
-386_8k:
-	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_386_8K) -l"$(TARGET)_386.lst" -o"$(TARGET)_386.bin"
+386:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_386) -l"$(TARGET)_386.lst" -o"$(TARGET)_386.bin"
 	@echo * Small 386 version "$(TARGET)_386.bin" built.
+
+386_large:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_386_LARGE) -l"$(TARGET)_386l.lst" -o"$(TARGET)_386l.bin"
+	@echo * Large 386 version "$(TARGET)_386l.bin" built.
 
 strings: src\Strings.asm
@@ -237,4 +244,5 @@
 	@perl ..\Tools\checksum.pl $(TARGET)_atl.bin $(BIOS_SIZE_LARGE)
 	@perl ..\Tools\checksum.pl $(TARGET)_386.bin $(BIOS_SIZE_SMALL)
+	@perl ..\Tools\checksum.pl $(TARGET)_386l.bin $(BIOS_SIZE_LARGE)
 
 unused:
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/MenuStructs.inc
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/MenuStructs.inc	(revision 592)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Inc/MenuStructs.inc	(revision 593)
@@ -20,4 +20,20 @@
 %ifndef MENU_STRUCTS_INC
 %define MENU_STRUCTS_INC
+
+struc ITEM_VALUE
+	.wRomvarsValueOffset	resb	2	; ROMVARS offset to actual value to be configured
+	.szDialogTitle			resb	2	; Dialog title string
+
+	.szMultichoice			resb	2	; Multiple choices in one string
+	.rgwChoiceToValueLookup	resb	2	; Ptr to lookup table for translating selected choice to actual value
+	.rgszValueToStringLookup:			; Ptr to lookup table for translating value to string
+	.rgszChoiceToStringLookup:
+	.wMinValue				resb	2	; Minimum allowed integer value
+	.wMaxValue:
+	.wValueBitmask			resb	2	; Bitmask for item value flag or field
+	.fnValueReader			resb	2	; Called just after ROMVARS is read, providing a hook for further action
+	.fnValueWriter			resb	2	; Called just before ROMVARS is written, providing a hook for further action
+	.bFieldPosition			resb	1	; Bit field position
+endstruc
 
 struc MENUPAGE
@@ -61,20 +77,3 @@
 
 
-struc ITEM_VALUE
-	.wRomvarsValueOffset	resb	2	; ROMVARS offset to actual value to be configured
-	.szDialogTitle			resb	2	; Dialog title string
-
-	.szMultichoice			resb	2	; Multiple choices in one string
-	.rgwChoiceToValueLookup	resb	2	; Ptr to lookup table for translating selected choice to actual value
-	.rgszValueToStringLookup:			; Ptr to lookup table for translating value to string
-	.rgszChoiceToStringLookup:
-	.wMinValue				resb	2	; Minimum allowed integer value
-	.wMaxValue:
-	.wValueBitmask			resb	2	; Bitmask for item value flag or field
-	.fnValueReader			resb	2	; Called just after ROMVARS is read, providing a hook for further action
-	.fnValueWriter			resb	2	; Called just before ROMVARS is written, providing a hook for further action
-	.bFieldPosition			resb	1	; Bit field position
-endstruc
-
-
 %endif ; MENU_STRUCTS_INC
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/EEPROM.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/EEPROM.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/EEPROM.asm	(revision 593)
@@ -189,9 +189,5 @@
 	cld
 %endif
-;%if g_rgwEepromTypeToSizeInWords = 0	; *FIXME* It really is but NASM won't accept this.
-	mov		cx, [cs:bx]
-;%else
-;	mov		cx, [cs:bx+g_rgwEepromTypeToSizeInWords]
-;%endif
+	mov		cx, [cs:bx+g_rgwEepromTypeToSizeInWords]
 	rep movsw
 
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Flash.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Flash.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Flash.asm	(revision 593)
@@ -292,5 +292,5 @@
 	loop	.WriteActualDataByteAfterSdpCommand
 	sti						; Enable interrupts
-	; Fall to WaitUntilEepromPageWriteHasCompleted
+	; Fall to .WaitUntilEepromPageWriteHasCompleted
 
 
@@ -305,6 +305,5 @@
 ;		AX, BX, DI, DS, ES
 ;--------------------------------------------------------------------
-ALIGN JUMP_ALIGN
-WaitUntilEepromPageWriteHasCompleted:
+.WaitUntilEepromPageWriteHasCompleted:
 	push	ss
 	pop		ds
@@ -325,4 +324,5 @@
 	ret
 
+
 ;--------------------------------------------------------------------
 ; DisplayFlashProgressWithPagesLeftInCXandFlashvarsInSSBP
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Main.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Main.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Main.asm	(revision 593)
@@ -85,4 +85,11 @@
 	ret
 .DosVersionIsOK:
+	mov		[bDosVersionMajor], al					; bDosVersionMajor must be initialized by the application (library code depends on it)
+	cmp		al, 5
+	jb		SHORT .DoNotInstallInt2FhHandler
+	; Since we are installing our Int2Fh handler we must also hook interrupt 23h to ensure a clean exit on ctrl-c/ctrl-break
+	call	HookInterrupt23h
+	call	HookInterrupt2Fh
+.DoNotInstallInt2FhHandler:
 
 	mov		ax, SCREEN_BACKGROUND_CHARACTER_AND_ATTRIBUTE
@@ -93,4 +100,6 @@
 	mov		ax, DOS_BACKGROUND_CHARACTER_AND_ATTRIBUTE
 	call	InitializeScreenWithBackgroundCharAndAttrInAX
+
+	call	UnhookInterrupt2Fh
 
 	; Exit to DOS
@@ -156,2 +165,5 @@
 ; Section containing uninitialized data
 SECTION .bss
+
+bDosVersionMajor:	resb	1
+
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menupages/FlashMenu.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menupages/FlashMenu.asm	(revision 592)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/Src/Menupages/FlashMenu.asm	(revision 593)
@@ -346,10 +346,7 @@
 .GetSelectedEepromSizeInWordsToAX:
 	eMOVZX	bx, [cs:g_cfgVars+CFGVARS.bEepromType]
-;%if g_rgwEepromTypeToSizeInWords = 0	; *FIXME* It really is but NASM won't accept this.
-	mov		ax, [cs:bx]
-;%else
-;	mov		ax, [cs:bx+g_rgwEepromTypeToSizeInWords]
-;%endif
+	mov		ax, [cs:bx+g_rgwEepromTypeToSizeInWords]
 	ret
+
 
 ;--------------------------------------------------------------------
Index: trunk/XTIDE_Universal_BIOS_Configurator_v2/makefile
===================================================================
--- trunk/XTIDE_Universal_BIOS_Configurator_v2/makefile	(revision 592)
+++ trunk/XTIDE_Universal_BIOS_Configurator_v2/makefile	(revision 593)
@@ -54,5 +54,5 @@
 # Assembler preprocessor defines.                               #
 #################################################################
-DEFINES = EXCLUDE_FROM_XTIDECFG
+DEFINES = EXCLUDE_FROM_XTIDECFG CLD_NEEDED
 DEFINES_XT = ELIMINATE_CGA_SNOW
 DEFINES_XTPLUS = USE_186 ELIMINATE_CGA_SNOW
