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
