Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Doc/changes.txt
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Doc/changes.txt	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Doc/changes.txt	(revision 352)
@@ -0,0 +1,101 @@
+XTIDE Universal BIOS v1.1.5 (28 November 2010)
+  * Errors are now being checked when calling previous INT 13h handler on AH=08h Read Disk Drive Parameters.
+    This fixes infinite drive checking loop on unofficial MS-DOS 7.10 installer.
+  * Better INT 40h handler detection to fix floppy drive detection with AMI 286/386 BIOS.
+  * AA55h signature no longer required when booting from floppy drives. This should make booter games work.
+
+
+XTIDE Universal BIOS v1.1.4 (24 August 2010)
+  * Correct number of drives is now returned from AH=08h when it is redirected to foreign BIOS.
+  * Interrupt controllers are now unmasked during drive reset.
+  * OS hooks are now enabled for all builds. IRQ waiting no longer uses HLT instruction to fix some EMM386 and VCPI issues.
+  * XT+ build is no more since it would now be the same as AT build
+
+
+XTIDE Universal BIOS v1.1.3 (1 August 2010)
+  * v1.1.1 broke booting from foreign drives, it is now fixed.
+  * Improved error handling a bit.
+  * Longer DRQ and IRQ timeouts to minimize write timouts with some (bad) CF cards.
+  * Default boot menu drive should now be properly selected.
+
+
+XTIDE Universal BIOS v1.1.2 (26 July 2010, no public release)
+  * Fixed a bug where Disk Parameter Table was accessed with wrong pointer register after writing last block.
+  * Cleaned AH=00h, Disk Controller Reset a bit.
+
+
+XTIDE Universal BIOS v1.1.1 (19 July 2010)
+*Booting is now possible from hard disks if floppy controller reset fails
+ since AH=00h, Disk Controller Reset now returns error code for the
+ requested drive only.
+*Now assembles with Yasm.
+
+
+XTIDE Universal BIOS v1.1.0 (first stable release, 2 May 2010)
+*Lite and full operating modes
+*Diagnostic cylinder no longer has to be reserved
+*Slave drives again work without master present
+*32-bit transfers for VLB and PCI IDE controllers
+*16- and 32-bit transfers are enabled on all builds
+*Boot menu hotkeys for all drives
+*Drive swapping is handled separately for floppy and hard disk drives so it
+ is now possible to install DOS to any hard disk from any floppy drive
+*INT 13h,AH=15h return value in DL now longer gets corrupted by drive swapping
+*Rewritten drive detection and lots of code cleaning
+*Longer timeout when detecting first drive
+*Minimum number of floppy drives can be specified if autodetection fails
+*Maybe other changes that i have forgotten
+
+XTIDE Universal BIOS v1.1.0 configuration and flashing program (idecfg.com)
+*Now works as a generic EEPROM flasher
+*Improvements to configuration menus
+*SDP can be completely disabled
+
+
+XTIDE Universal BIOS v1.0.0_RC2
+*No more boot menu slowdown when no XTIDE Universal BIOS
+ controlled drives present
+*Hard disks are now reset properly.
+ This fixes some Block Mode related bugs.
+*Major improvements for error handling
+*Small improvements for interrupt handling
+
+
+XTIDE Universal BIOS v1.0.0_RC1
+*Fixed 386+ stack exception bug
+*Stack is relocated for boot menu even if DPTs are not stored to 30:0h
+*Strings and boot menu are displayed properly on BIOSes that corrupts
+ AH when returning from INT 10h/AH=Eh
+*L-CHS addressing is now used for <=504MiB drives even if LBA is supported
+
+
+XTIDE Universal BIOS v1.0.0_b4
+*Boot menu with drive swapping
+*Block mode transfers
+*Cylinder limiting
+*Drive detection read errors are now properly detected
+*A little longer timeout value when detecting drives
+*Minor optimizations to save some bytes
+
+
+XTIDE Universal BIOS beta3
+*BIOS configuration and flashing program finally available
+*No more conflicts with other hard disk BIOSes
+*Slave drives should now be detected without master
+*Timeouts now use system timer
+*Variables can now be located to top of base memory
+*Completely rewritten interrupt handling
+*Minor optimizations to 8-bit transfers
+*CTRL can be held down to skip initialization
+*Late initialization to fix compatibility issues with old systems
+
+
+XTIDE Universal BIOS beta2
+*AT build and support for 16-bit IDE Controllers
+*XT+ build for 188/186/V20/V30/286 XTs
+*Auto detection for timeout values (AT+)
+*Minor optimizations
+
+
+XTIDE Universal BIOS beta1
+*Initial release
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Doc/readme.txt
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Doc/readme.txt	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Doc/readme.txt	(revision 352)
@@ -0,0 +1,5 @@
+See XTIDE Universal BIOS wiki pages for manual and other information:
+http://code.google.com/p/xtideuniversalbios/w/list
+
+XTIDE Universal BIOS discussion can be found at:
+http://www.vintage-computer.com/vcforum/showthread.php?17986-XTIDE-Universal-BIOS
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/ATA_ID.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/ATA_ID.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/ATA_ID.inc	(revision 352)
@@ -0,0 +1,416 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	ATA Identify Drive information.
+%ifndef ATA_ID_INC
+%define ATA_ID_INC
+
+; ATA-1 Drive Information struct
+; F = Fixed value
+; V = Variable value
+; R = Reserved word
+; X = Vendor specific word
+struc ATA1
+	.wGenCfg	resw 1	; 0F, General configuration bit-significant information
+	.wCylCnt	resw 1	; 1F, Number of cylinders
+				resw 1	; 2R
+	.wHeadCnt	resw 1	; 3F, Number of heads
+	.wBpTrck	resw 1	; 4F, Number of unformatted bytes per track
+	.wBpSect	resw 1	; 5F, Number of unformatted bytes per sector
+	.wSPT		resw 1	; 6F, Number of sectors per track 
+				resw 3	; 7...9X
+	.strSerial	resb 20	; 10...19F, Serial number (20 ASCII characters, 0000h=not specified)
+	.wBuffType	resw 1	; 20F, Buffer type
+	.wBuffSize	resw 1	; 21F, Buffer size in 512 byte increments (0000h=not specified)
+	.wEccCnt	resw 1	; 22F, # of ECC bytes avail on read/write long cmds (0000h=not spec'd)
+	.strFirmW	resb 8	; 23...26F, Firmware revision (8 ASCII characters, 0000h=not specified)
+	.strModel	resb 40	; 27...46F, Model number (40 ASCII characters, 0000h=not specified)
+	.bBlckSize	resb 1	; 47[0-7]F, Maximum number of sectors that can be transferred
+						;          per interrupt on read and write multiple commands
+						;		   (00h=Read/write multiple commands not implemented)
+				resb 1	; 47[8-15]X
+	.wDWIO		resw 1	; 48F, Can perform doubleword I/O (boolean)
+	.wCaps		resw 1	; 49FRX, Capabilities
+				resw 1	; 50R
+				resb 1	; 51[0-7]X
+	.bPIOTiming	resb 1	; 51[8-15]F, PIO data transfer cycle timing mode
+				resb 1	; 52[0-7]X
+	.bDMATiming	resb 1	; 52[8-15]F, DMA data transfer cycle timing mode
+	.wFields	resw 1	; 53FVR, Field (next words) validity bits
+
+	; Words 54-58 are valid only if bit0 is set in .wFields
+	.wCurCyls	resw 1	; 54V, Number of current cylinders
+	.wCurHeads	resw 1	; 55V, Number of current heads
+	.wCurSPT	resw 1	; 56V, Number of current sectors per track
+	.dwCurSCnt	resd 1	; 57...58V, Current capacity in sectors
+
+	; Words 59-63 are always valid
+	.bBlockSel	resb 1	; 59[0-7]V, Current setting for number of sectors that
+						;           can be transferred per interrupt on R/W multiple command
+	.bBlockFlgs	resb 1	; 59[8-15]VR, bit 0 set if Multiple sector setting is valid
+	.dwLBACnt	resd 1	; 60...61F, Total number of user addressable sectors (LBA mode only)
+	.bSDMASupp	resb 1	; 62[0-7]F, Single word DMA transfer modes supported
+	.bSDMAAct	resb 1	; 62[8-15]V, Single word DMA transfer mode active
+	.bMDMASupp	resb 1	; 63[0-7]F, Multiword DMA transfer modes supported
+	.bMDMAAct	resb 1	; 63[8-15]V, Multiword DMA transfer mode active
+endstruc
+
+A1_MODEL_NUMBER_LENGTH	EQU	40		; 40 ASCII characters
+
+; ATA-1 Word 0, General configuration
+A1_wGenCfg_NONMAG		EQU	(1<<15)	; Reserved for non-magnetic drives
+A1_wGenCfg_FGAPREQ		EQU	(1<<14)	; Format speed tolerance gap required
+A1_wGenCfg_TRCKOFF		EQU	(1<<13)	; Track offset option available
+A1_wGenCfg_DATAOFF		EQU	(1<<12)	; Data strobe offset option available
+A1_wGenCfg_ROTTOL		EQU	(1<<11)	; Rotational speed tolerance is > 0,5%
+A1_wGenCfg_XFERFAST		EQU (1<<10)	; Disk transfer rate > 10 Mbs
+A1_wGenCfg_XFERMED		EQU	(1<<9)	; Disk transfer rate > 5Mbs but <= 10Mbs
+A1_wGenCfg_XFERSLOW		EQU (1<<8)	; Disk transfer rate <= 5Mbs
+A1_wGenCfg_REMOVABLE	EQU	(1<<7)	; Removable cartridge drive
+A1_wGenCfg_FIXED		EQU	(1<<6)	; Fixed drive
+A1_wGenCfg_MOTCTRL		EQU	(1<<5)	; Spindle motor control option implemented
+A1_wGenCfg_HEADSLOW		EQU	(1<<4)	; Head switch time > 15 usec
+A1_wGenCfg_NOTMFM		EQU	(1<<3)	; Not MFM encoded
+A1_wGenCfg_SOFTSECT		EQU	(1<<2)	; Soft sectored
+A1_wGenCfg_HARDSECT		EQU	(1<<1)	; Hard sectored
+
+; ATA-1 Word 49, Capabilities
+A1_wCaps_LBA			EQU	(1<<9)	; LBA supported
+A1_wCaps_DMA			EQU	(1<<8)	; DMA supported
+
+; ATA-1 Word 53, Fields
+A1_wFields_54to58		EQU	(1<<0)	; The fields reported in words 54-58 are valid
+
+; ATA-1 Word 59 high byte, Block mode flags
+A1_bBlockFlgs_VALID		EQU	(1<<0)	; Multiple sector setting (bBlockSel) is valid
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; ATA-2 Drive Information struct
+; F = Fixed value
+; V = Variable value
+; R = Reserved word
+; X = Vendor specific word
+struc ATA2
+	.wGenCfg	resw 1	; 0F, General configuration bit-significant information
+	.wCylCnt	resw 1	; 1F, Number of logical cylinders
+				resw 1	; 2R
+	.wHeadCnt	resw 1	; 3F, Number of logical heads
+				resw 1	; 4X
+				resw 1	; 5X
+	.wSPT		resw 1	; 6F, Number of logical sectors per track 
+				resw 3	; 7...9X
+	.strSerial	resb 20	; 10...19F, Serial number (20 ASCII characters, 0000h=not specified)
+				resw 1	; 20X
+				resw 1	; 21X
+	.wEccCnt	resw 1	; 22F, # of ECC bytes avail on read/write long cmds (0000h=not spec'd)
+	.strFirmW	resb 8	; 23...26F, Firmware revision (8 ASCII characters, 0000h=not specified)
+	.strModel	resb 40	; 27...46F, Model number (40 ASCII characters, 0000h=not specified)
+	.bBlckSize	resb 1	; 47[0-7]F, Maximum number of sectors that can be transferred
+						;          per interrupt on read and write multiple commands
+						;		   (00h=Read/write multiple commands not implemented)
+				resb 1	; 47[8-15]X
+				resw 1	; 48R
+	.wCaps		resw 1	; 49FRX, Capabilities
+				resw 1	; 50R
+				resb 1	; 51[0-7]X
+	.bPIOTiming	resb 1	; 51[8-15]F, PIO data transfer cycle timing mode
+				resb 1	; 52[0-7]X
+	.bDMATiming	resb 1	; 52[8-15]F, DMA data transfer cycle timing mode
+	.wFields	resw 1	; 53FVR, Field (next words) validity bits
+
+	; Words 54-58 are valid only if bit0 is set in .wFields
+	.wCurCyls	resw 1	; 54V, Number of current logical cylinders
+	.wCurHeads	resw 1	; 55V, Number of current logical heads
+	.wCurSPT	resw 1	; 56V, Number of current logical sectors per track
+	.dwCurSCnt	resd 1	; 57...58V, Current capacity in sectors
+
+	; Words 59-63 are always valid
+	.bBlockSel	resb 1	; 59[0-7]V, Current setting for number of sectors that
+						;           can be transferred per interrupt on R/W multiple command
+	.bBlockFlgs	resb 1	; 59[8-15]VR, bit 0 set if Multiple sector setting is valid	
+	.dwLBACnt	resd 1	; 60...61F, Total number of user addressable sectors (LBA mode only)
+	.bSDMASupp	resb 1	; 62[0-7]F, Single word DMA transfer modes supported
+	.bSDMAAct	resb 1	; 62[8-15]V, Single word DMA transfer mode active
+	.bMDMASupp	resb 1	; 63[0-7]F, Multiword DMA transfer modes supported
+	.bMDMAAct	resb 1	; 63[8-15]V, Multiword DMA transfer mode active
+	
+	; Words 64-70 are valid only if bit1 is set in .wFields (ATA2+)
+	.bPIOSupp	resb 1	; 64[0-7]F, Advanced PIO Transfer Modes Supported
+				resb 1	; 64[8-15]R
+	.wMDMAMinCy	resw 1	; 65F, Minimum Multiword DMA Transfer Cycle Time Per Word
+	.wMDMARecCy	resw 1	; 66F, Manufacturers Recommended Multiword DMA Transfer Cycle Time
+	.wPIOMinCy	resw 1	; 67F, Minimum PIO Transfer Cycle Time Without Flow Control
+	.wPIOMinCyF	resw 1	; 68F, Minimum PIO Transfer Cycle Time With IORDY Flow Control
+endstruc
+
+; ATA-2 Word 0, General configuration
+A2_wGenCfg_NONMAG		EQU	(1<<15)	; Reserved for non-magnetic drives
+A2_wGenCfg_REMOVABLE	EQU	(1<<7)	; Removable media device
+A2_wGenCfg_FIXED		EQU	(1<<6)	; Not removable controller and/or device
+
+; ATA-1 Word 49, Capabilities
+A2_wCaps_TIMER			EQU	(1<<13)	; Standby timer values as specified in this standard are supported
+A2_wCaps_IORDY			EQU	(1<<11)	; IORDY supported
+A2_wCaps_CANDISIORDY	EQU	(1<<10)	; IORDY can be disabled
+A2_wCaps_LBA			EQU	(1<<9)	; LBA supported
+A2_wCaps_DMA			EQU	(1<<8)	; DMA supported
+
+; ATA-2 Word 53, Fields
+A2_wFields_54to58		EQU	(1<<0)	; The fields reported in words 54-58 are valid
+A2_wFields_64to70		EQU	(1<<1)	; The fields reported in words 64-70 are valid
+
+; ATA-2 Word 59 high byte, Block mode flags
+A2_bBlockFlgs_VALID		EQU	(1<<0)	; Multiple sector setting (bBlockSel) is valid
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; ATA-6 Drive Information struct
+; F = Fixed value
+; V = Variable value
+; R = Reserved word
+; X = Vendor specific word
+struc ATA6
+	.wGenCfg	resw 1	; 0F, General configuration bit-significant information
+				resw 1	; 1X, Obsolete (Number of logical cylinders)
+				resw 1	; 2V, Specific configuration
+				resw 1	; 3X, Obsolete (Number of logical heads)
+				resw 1	; 4X
+				resw 1	; 5X
+				resw 1	; 6X, Obsolete (Number of logical sectors per track) 
+				resw 2	; 7...8V, Reserved for assignment by the CompactFlash Association
+				resw 1	; 9X
+	.strSerial	resb 20	; 10...19F, Serial number (20 ASCII characters, 0000h=not specified)
+				resw 1	; 20X
+				resw 1	; 21X
+				resw 1	; 22X, Obsolete (# of ECC bytes avail on read/write long cmds (0000h=not spec'd))
+	.strFirmW	resb 8	; 23...26F, Firmware revision (8 ASCII characters, 0000h=not specified)
+	.strModel	resb 40	; 27...46F, Model number (40 ASCII characters, 0000h=not specified)
+	.bBlckSize	resb 1	; 47[0-7]F, Maximum number of sectors that can be transferred
+						;           per interrupt on read and write multiple commands
+						;		    (00h=Read/write multiple commands not implemented)
+				resb 1	; 47[8-15]F, 80h
+				resw 1	; 48R
+	.wCaps		resw 1	; 49FX, Capabilities
+	.wCapsHigh	resw 1	; 50FX, Capabilities 2
+				resw 1	; 51X, Obsolete (PIO data transfer cycle timing mode)
+				resw 1	; 52X, Obsolete (DMA data transfer cycle timing mode)
+	.wFields	resw 1	; 53FX, Field (next words) validity bits
+
+	; Words 54-58 are valid only if bit0 is set in .wFields
+				resw 1	; 54X, Obsolete (Number of current logical cylinders)
+				resw 1	; 55X, Obsolete (Number of current logical heads)
+				resw 1	; 56X, Obsolete (Number of current logical sectors per track)
+				resd 1	; 57...58X, Obsolete (Current capacity in sectors)
+
+	; Words 59-63 are always valid
+	.bBlockSel	resb 1	; 59[0-7]V, Current setting for number of sectors that
+						;           can be transferred per interrupt on R/W multiple command
+	.bBlockFlgs	resb 1	; 59[8-15]VR, bit 0 set if Multiple sector setting is valid
+	.dwLBACnt	resd 1	; 60...61F, Total number of user addressable sectors (LBA-28)
+				resb 1	; 62[0-7]X, Obsolete (Single word DMA transfer modes supported)
+				resb 1	; 62[8-15]X, Obsolete (Single word DMA transfer mode active)
+	.wMDMA		resw 1	; 63FV, Multiword DMA transfer modes supported and active
+
+	; Words 64-70 are valid only if bit1 is set in .wFields (ATA2+)
+	.bPIOSupp	resb 1	; 64[0-7]F, Advanced PIO Transfer Modes Supported
+				resb 1	; 64[8-15]R
+	.wMDMAMinCy	resw 1	; 65F, Minimum Multiword DMA Transfer Cycle Time Per Word
+	.wMDMARecCy	resw 1	; 66F, Manufacturers Recommended Multiword DMA Transfer Cycle Time
+	.wPIOMinCy	resw 1	; 67F, Minimum PIO Transfer Cycle Time Without Flow Control
+	.wPIOMinCyF	resw 1	; 68F, Minimum PIO Transfer Cycle Time With IORDY Flow Control
+				resw 71-69	; 69...70R
+
+	; Words 71...74 are reserved for IDENTIFY PACKET DEVICE command
+				resw 75-71	; 71...74R
+
+	.wQueue		resw 1	; 75[0-4]F, Maximum queue depth - 1
+				resw 80-76	; 76...79R
+
+	.wMajorVer	resw 1	; 80F, Major Version Number
+	.wMinorVer	resw 1	; 81F, Minor Version Number
+	.wSetSup82	resw 1	; 82F, Command set supported
+	.wSetSup83	resw 1	; 83F, Command sets supported
+	.wSetSup84	resw 1	; 84F, Command set / Feature supported extension
+	.wEnFor82	resw 1	; 85FV, Command set / feature enabled (for word 82)
+	.wEnFor83	resw 1	; 86FV, Command set / feature enabled (for word 83)
+	.wEnFor84	resw 1	; 87FV, Command set / feature enabled (for word 84)
+
+	; Word 88 is valid only if bit2 is set in .wFields (word 53)
+	.wUDMA		resw 1	; 88FV, Ultra DMA Mode support
+
+	.wEraseTime	resw 1	; 89F, Time required for security erase unit completion
+	.wEnhErTime	resw 1	; 90F, Time required for Enhanced security erase completion
+	.wCurPower	resw 1	; 91V, Current advanced power management value
+	.wPWRev		resw 1	; 92V, Master Password Revision Code
+	.wReset		resw 1	; 93FV, Hardware reset result
+	.bCurAcous	resb 1	; 94[0-7]V, Current automatic acoustic management value
+	.bRecAcous	resb 1	; 94[8-15]V, Vendors recommended acoustic management value
+				resw 100-95		; 95...99R
+	.qwLBACnt	resb 8	; 100...103V, Total number of user addressable sectors (LBA48)
+				resw 127-104	; 104...126R
+	.wRMSN		resw 1	; 127F, Removable Media Status Notification feature set support
+	.wSecurity	resw 1	; 128FV, Security Status
+				resw 160-129	; 129...157X, Vendor Specific
+	.wCFAPower	resw 1	; 160FV, CFA Power Mode 1
+				resw 176-161	; 161...175R, Reserved for assignment by the CompactFlash Association
+	.strMediaSr	resw 206-176	; 176...205V, Current media serial number
+				resw 255-206	; 206...254R
+	.bSignature	resb 1	; 255[0-7]X, Signature
+	.bChecksum	resb 1	; 255[8-15]X, Checksum
+endstruc
+
+; ATA-6 Word 0, General configuration
+A6_wGenCfg_REMOVABLE	EQU	(1<<7)	; Removable media device
+A6_wGenCfg_INCOMPLETE	EQU	(1<<2)	; Response incomplete
+
+; ATA-6 Word 49, Capabilities
+A6_wCaps_TIMER			EQU	(1<<13)	; Standby timer values as specified in this standard are supported
+A6_wCaps_IORDY			EQU	(1<<11)	; IORDY supported
+A6_wCaps_CANDISIORDY	EQU	(1<<10)	; IORDY can be disabled
+A6_wCaps_LBA			EQU	(1<<9)	; LBA supported
+A6_wCaps_DMA			EQU	(1<<8)	; DMA supported
+
+; ATA-6 Word 53, Fields
+A6_wFields_88			EQU	(1<<2)	; The fields reported in word 88 are valid
+A6_wFields_64to70		EQU	(1<<1)	; The fields reported in words 64-70 are valid
+
+; ATA-6 Word 59 high byte, Block mode flags
+A6_bBlockFlgs_VALID		EQU	(1<<0)	; Multiple sector setting (bBlockSel) is valid
+
+; ATA-6 Word 63, Multiword DMA Mode
+A6_wMDMA_MODE2_SELECTED	EQU	(1<<10)	; Multiword DMA mode 2 is selected
+A6_wMDMA_MODE1_SELECTED	EQU	(1<<9)	; Multiword DMA mode 1 is selected
+A6_wMDMA_MODE0_SELECTED	EQU	(1<<8)	; Multiword DMA mode 0 is selected
+A6_wMDMA_MODE2_SUPRTD	EQU	(1<<2)	; Multiword DMA mode 2 and below are supported
+A6_wMDMA_MODE1_SUPRTD	EQU	(1<<1)	; Multiword DMA mode 1 and below are supported
+A6_wMDMA_MODE0_SUPRTD	EQU	(1<<0)	; Multiword DMA mode 0 is supported
+
+; ATA-6 Word 80, Major version number
+A6_wMajorVer_ATA6		EQU	(1<<6)
+A6_wMajorVer_ATA5		EQU	(1<<5)
+A6_wMajorVer_ATA4		EQU	(1<<4)
+A6_wMajorVer_ATA3		EQU	(1<<3)
+
+; ATA-6 Word 82, Command set supported
+A6_wSetSup82_NOP		EQU	(1<<14)	; NOP command supported
+A6_wSetSup82_RDBUFF		EQU	(1<<13)	; READ BUFFER command supported
+A6_wSetSup82_WRBUFF		EQU	(1<<12)	; WRITE BUFFER command supported
+A6_wSetSup82_PROT_AREA	EQU	(1<<10)	; Host Protected Area feature set supported
+A6_wSetSup82_DEV_RESET	EQU	(1<<9)	; DEVICE RESET command supported
+A6_wSetSup82_SERVICE	EQU	(1<<8)	; SERVICE interrupt supported
+A6_wSetSup82_RELEASE	EQU	(1<<7)	; Release interrupt supported
+A6_wSetSup82_LOOKAHEAD	EQU	(1<<6)	; Look-ahead supported
+A6_wSetSup82_WRCACHE	EQU	(1<<5)	; Write cache supported
+A6_wSetSup82_POWERMAN	EQU	(1<<3)	; Power Management feature set supported
+A6_wSetSup82_REM_MEDIA	EQU	(1<<2)	; Removable Media feature set supported
+A6_wSetSup82_SECURITY	EQU	(1<<1)	; Security Mode feature set supported
+A6_wSetSup82_SMART		EQU	(1<<0)	; SMART feature set supported
+
+; ATA-6 Word 83, Command sets supported
+A6_wSetSup83_FLUSH_EXT	EQU	(1<<13)	; FLUSH CACHE EXT command supported
+A6_wSetSup83_FLUSH		EQU	(1<<12)	; FLUSH CACHE command supported
+A6_wSetSup83_CFG		EQU	(1<<11)	; Device Configuration Overlay feature set supported
+A6_wSetSup83_LBA48		EQU	(1<<10)	; 48-bit LBA feature set supported
+A6_wSetSup83_ACOUSTIC	EQU	(1<<9)	; Automatic Acoustic Management feature set supported
+A6_wSetSup83_SET_MAX	EQU	(1<<8)	; SET MAX security extension supported
+A6_wSetSup83_FEATURES	EQU	(1<<6)	; SET FEATURES subcommand required to spinup after power-up
+A6_wSetSup83_POWERUP	EQU	(1<<5)	; Power-Up In Standby feature set supported
+A6_wSetSup83_RMSN		EQU	(1<<4)	; Removable Media Status Notification feature set supported
+A6_wSetSup83_APM		EQU	(1<<3)	; Advanced Power Management feature set supported
+A6_wSetSup83_CFA		EQU	(1<<2)	; CFA feature set supported
+A6_wSetSup83_DMAQUEUED	EQU	(1<<1)	; READ/WRITE DMA QUEUED supported
+A6_wSetSup83_MICROCODE	EQU	(1<<0)	; DOWNLOAD MICROCODE command supported
+
+; ATA-6 Word 84, Command set/feature supported extension
+A6_wSetSup84_GENLOG		EQU	(1<<5)	; General Purpose Logging feature set supported
+A6_wSetSup84_MEDIAPASS	EQU	(1<<3)	; Media Card Pass Through Command feature set supported
+A6_wSetSup84_MEDIASER	EQU	(1<<2)	; Media serial number supported
+A6_wSetSup84_SMARTTEST	EQU	(1<<1)	; SMART self-test supported
+A6_wSetSup84_SMARTLOG	EQU	(1<<0)	; SMART error logging supported
+
+; ATA-6 Word 85, Command set/feature enabled (supported by word 82)
+A6_wEnFor82_NOP			EQU	(1<<14)	; NOP command enabled
+A6_wEnFor82_RDBUFF		EQU	(1<<13)	; READ BUFFER command enabled
+A6_wEnFor82_WRBUFF		EQU	(1<<12)	; WRITE BUFFER command enabled
+A6_wEnFor82_PROT_AREA	EQU	(1<<10)	; Host Protected Area feature set enabled
+A6_wEnFor82_DEV_RESET	EQU	(1<<9)	; DEVICE RESET command enabled
+A6_wEnFor82_SERVICE		EQU	(1<<8)	; SERVICE interrupt enabled
+A6_wEnFor82_RELEASE		EQU	(1<<7)	; Release interrupt enabled
+A6_wEnFor82_LOOKAHEAD	EQU	(1<<6)	; Look-ahead enabled
+A6_wEnFor82_WRCACHE		EQU	(1<<5)	; Write cache enabled
+A6_wEnFor82_POWERMAN	EQU	(1<<3)	; Power Management feature set enabled
+A6_wEnFor82_REM_MEDIA	EQU	(1<<2)	; Removable Media feature set enabled
+A6_wEnFor82_SECURITY	EQU	(1<<1)	; Security Mode feature set enabled
+A6_wEnFor82_SMART		EQU	(1<<0)	; SMART feature set enabled
+
+; ATA-6 Word 86, Command set/feature enabled (supported by word 83)
+A6_wEnFor83_FLUSH_EXT	EQU	(1<<13)	; FLUSH CACHE EXT command supported
+A6_wEnFor83_FLUSH		EQU	(1<<12)	; FLUSH CACHE command supported
+A6_wEnFor83_CFG			EQU	(1<<11)	; Device Configuration Overlay supported
+A6_wEnFor83_LBA48		EQU	(1<<10)	; 48-bit LBA feature set supported
+A6_wEnFor83_ACOUSTIC	EQU	(1<<9)	; Automatic Acoustic Management feature set enabled
+A6_wEnFor83_SET_MAX		EQU	(1<<8)	; SET MAX security extension enabled by SET MAX SET PASSWORD
+A6_wEnFor83_FEATURES	EQU	(1<<6)	; SET FEATURES subcommand required to spinup after power-up
+A6_wEnFor83_POWERUP		EQU	(1<<5)	; Power-Up In Standby feature set enabled
+A6_wEnFor83_RMSN		EQU	(1<<4)	; Removable Media Status Notification feature set enabled
+A6_wEnFor83_APM			EQU	(1<<3)	; Advanced Power Management feature set enabled
+A6_wEnFor83_CFA			EQU	(1<<2)	; CFA feature set enabled
+A6_wEnFor83_DMAQUEUED	EQU	(1<<1)	; READ/WRITE DMA QUEUED supported
+A6_wEnFor83_MICROCODE	EQU	(1<<0)	; DOWNLOAD MICROCODE command supported
+
+; ATA-6 Word 87, Command set/feature default
+A6_wEnFor84_GENLOG		EQU	(1<<5)	; General Purpose Logging feature set supported
+A6_wEnFor84_MEDIAPASS	EQU	(1<<3)	; Media Card Pass Through Command feature set enabled
+A6_wEnFor84_MEDIASER	EQU	(1<<2)	; Media serial number is valid
+A6_wEnFor84_SMARTTEST	EQU	(1<<1)	; SMART self-test supported
+A6_wEnFor84_SMARTLOG	EQU	(1<<0)	; SMART error logging supported
+
+; ATA-6 Word 88, Ultra DMA Mode
+A6_wUDMA_MODE5_SELECTED	EQU	(1<<13)	; Ultra DMA mode 5 is selected
+A6_wUDMA_MODE4_SELECTED	EQU	(1<<12)	; Ultra DMA mode 4 is selected
+A6_wUDMA_MODE3_SELECTED	EQU	(1<<11)	; Ultra DMA mode 3 is selected
+A6_wUDMA_MODE2_SELECTED	EQU	(1<<10)	; Ultra DMA mode 2 is selected
+A6_wUDMA_MODE1_SELECTED	EQU	(1<<9)	; Ultra DMA mode 1 is selected
+A6_wUDMA_MODE0_SELECTED	EQU	(1<<8)	; Ultra DMA mode 0 is selected
+A6_wUDMA_MODE5_SUPRTD	EQU	(1<<5)	; Ultra DMA mode 5 and below are supported
+A6_wUDMA_MODE4_SUPRTD	EQU	(1<<4)	; Ultra DMA mode 4 and below are supported
+A6_wUDMA_MODE3_SUPRTD	EQU	(1<<3)	; Ultra DMA mode 3 and below are supported
+A6_wUDMA_MODE2_SUPRTD	EQU	(1<<2)	; Ultra DMA mode 2 and below are supported
+A6_wUDMA_MODE1_SUPRTD	EQU	(1<<1)	; Ultra DMA mode 1 and below are supported
+A6_wUDMA_MODE0_SUPRTD	EQU	(1<<0)	; Ultra DMA mode 0 is supported
+
+; ATA-6 Word 93, Hardware reset result
+A6_wReset_CBLID_BELOW	EQU	(1<<13)	; Device detected CBLID- above ViH
+A6_wReset_DEV1_PDIAG	EQU	(1<<11)	; Device 1 asserted PDIAG-
+A6_wReset_DEV0_RESP_D1	EQU	(1<<6)	; Device 0 responds when Device 1 is selected
+A6_wReset_DEV0_DASP		EQU	(1<<5)	; Device 0 detected the assertion of DASP-
+A6_wReset_DEV0_PDIAG	EQU	(1<<4)	; Device 0 detected the assertion of PDIAG
+A6_wReset_DEV0_PASSED	EQU	(1<<3)	; Device 0 passed diagnostics
+A6_wReset_MASK_DEV1_DETERMINE	EQU ((1<<10)|(1<<9))	; These bits indicate how Device 1 determined the device number
+A6_wReset_MASK_DEV0_DETERMINE	EQU ((1<<2)|(1<<1))		; These bits indicate how Device 0 determined the device number:
+A6_wReset_RESERVED		EQU	00b
+A6_wReset_JUMPER		EQU	01b		; a jumper was used
+A6_wReset_CSEL			EQU	10b		; the CSEL signal was used
+A6_wReset_UNKNOWN		EQU	11b		; some other method was used or the method is unknown
+
+; ATA-6 Word 127, Removable Media Status Notification feature set support
+A6_wRMSN_SUPPORTED		EQU	(1<<0)	; Removable Media Status Notification feature supported
+
+; ATA-6 Word 128, Security status
+A6_wSecurity_MAX		EQU	(1<<8)	; Security level 0 = High, 1 = Maximum
+A6_wSecurity_ENH_ERASE	EQU	(1<<5)	; Enhanced security erase supported
+A6_wSecurity_EXPIRED	EQU	(1<<4)	; Security count expired
+A6_wSecurity_FROZEN		EQU	(1<<3)	; Security frozen
+A6_wSecurity_LOCKED		EQU	(1<<2)	; Security locked
+A6_wSecurity_ENABLED	EQU	(1<<1)	; Security enabled
+A6_wSecurity_SUPPORTED	EQU	(1<<0)	; Security supported
+
+; ATA-6 Word 160, CFA Power Mode 1
+A6_wCFAPower_WORDSUPP	EQU	(1<<15)	; Word 160 supported
+A6_wCFAPower_REQUIRED	EQU	(1<<13)	; CFA power mode 1 is required for one or more commands implemented by the device
+A6_wCFAPower_DISABLED	EQU	(1<<12)	; CFA power mode 1 disabled
+A6_wCFAPower_MASK_mA	EQU	0FFFh	; Maximum current in mA
+
+
+%endif ; ATA_ID_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/BootMenu.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/BootMenu.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/BootMenu.inc	(revision 352)
@@ -0,0 +1,50 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Equates and structs used in Boot Menu.
+
+%ifndef BOOTMENU_INC
+%define BOOTMENU_INC
+
+; Boot menu sizes
+BOOT_MENU_DEFAULT_TIMEOUT				EQU	(30 * TICKS_PER_SECOND)
+BOOT_MENU_TITLE_LINES					EQU	2	; Number of title lines
+BOOT_MENU_INFO_LINES					EQU	3	; Number of info lines
+BOOT_MENU_SEPARATOR_LINES_PLUS_SHADOW	EQU	5
+BOOT_MENU_TITLE_AND_INFO_LINES			EQU	(BOOT_MENU_TITLE_LINES | (BOOT_MENU_INFO_LINES<<8))
+BOOT_MENU_WIDTH							EQU	40	; Menu width in characters (including shadow)
+BOOT_MENU_HEIGHT_WITHOUT_ITEMS			EQU	(BOOT_MENU_TITLE_LINES + BOOT_MENU_INFO_LINES + BOOT_MENU_SEPARATOR_LINES_PLUS_SHADOW)
+MENU_SCREEN_BOTTOM_LINES				EQU	1
+
+; Hotkeys
+ROM_BOOT_HOTKEY_SCANCODE				EQU	42h	; F8
+
+
+; Boot Menu Information Table. These are generated for all XTIDE Universal
+; BIOS drives. Available only until boot is successful.
+MAX_HARD_DISK_NAME_LENGTH				EQU		30		; Bytes reserved for drive name
+
+struc BOOTMENUINFO
+	.szDrvName		resb	MAX_HARD_DISK_NAME_LENGTH
+					resb	2		; Zero word (ensures string terminates)
+					resb	4		; padding to make BOOTMENUINFO size an even multiple of DPT size
+endstruc
+
+DPT_BOOTMENUINFO_SIZE_MULTIPLIER  equ	BOOTMENUINFO_size / LARGEST_DPT_SIZE
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+
+%if MAX_HARD_DISK_NAME_LENGTH % 2 <> 0
+	%error "MAX_HARD_DISK_NAME_LENGTH needs to be a multiple of 2, memory is moved with word operations."
+%endif
+
+%if BOOTMENUINFO_size % LARGEST_DPT_SIZE <> 0
+	%error "BOOTMENUINFO's size must be an even multiple of DPT's size.  Add or remove padding at the bottom of BOOTMENUINFO to bring the two sizes into alignment.  As BOOTMENUINFO is only used at boot time, with plenty of memory to consume, it is OK to waste some space here."
+%endif
+
+%if BOOTMENUINFO.szDrvName <> 0
+	%error "BOOTMENUINFO.szDrvName is assumed to be the first member of struc BOOTMENUINFO, in BootMenuPrint_RefreshItem"
+%endif
+
+%endif
+
+
+%endif ; BOOTMENU_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/BootVars.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/BootVars.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/BootVars.inc	(revision 352)
@@ -0,0 +1,101 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Defines for BOOTVARS struct used by boot menu
+;					and drive initialization.
+%ifndef BOOTVARS_INC
+%define BOOTVARS_INC
+
+
+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
+	.rgBootNfo:						; Array containing BOOTNFO structs
+endstruc
+
+
+;--------------------------------------------------------------------
+; Stores POST stack pointer to BOOTVARS.
+;
+; STORE_POST_STACK_POINTER
+;	Parameters:
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro STORE_POST_STACK_POINTER 0
+	mov		[es:BOOTVARS.dwPostStack], sp
+	mov		[es:BOOTVARS.dwPostStack+2], ss
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Initializes stack for boot menu usage.
+; POST stack is not large enough when DPTs are stored to 30:0h.
+;
+; Note regarding LOAD_BDA_SEGMENT_TO: If you force the use of SP
+; then you also have to unconditionally enable the CLI/STI pair.
+; The reason for this is that only some buggy 808x CPU:s need the
+; CLI/STI instruction pair when changing stacks. Other CPU:s disable
+; interrupts automatically when SS is modified for the duration of
+; the immediately following instruction to give time to change SP.
+;
+; SWITCH_TO_BOOT_MENU_STACK
+;	Parameters:
+;		Nothing
+;	Returns:
+;		SS:SP:	Pointer to top of Boot Menu stack
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro SWITCH_TO_BOOT_MENU_STACK 0
+%ifndef USE_186
+	cli									; Disable interrupts
+%endif
+	LOAD_BDA_SEGMENT_TO	ss, sp
+	mov		sp, BOOTVARS.rgbMnuStack	; Load offset to stack
+%ifndef USE_186
+	sti									; Enable interrupts
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Restores SS and SP to initial boot loader values.
+;
+; Note! Must return with AX=0 and CF preserved.
+; See Int19hMenu_JumpToBootSector_or_RomBoot.
+;
+; SWITCH_BACK_TO_POST_STACK
+;	Parameters:
+;		AX:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		SS:SP:	Ptr to POST stack
+;	Corrupts registers:
+;		Nothing (not even FLAGS)
+;--------------------------------------------------------------------
+%macro SWITCH_BACK_TO_POST_STACK 0
+%ifndef USE_386
+	cli
+	mov		ss, ax
+	mov		sp, [ss:BOOTVARS.dwPostStack]
+	mov		ss, [ss:BOOTVARS.dwPostStack+2]
+	sti
+%else
+	mov		ss, ax
+	lss		sp, [ss:BOOTVARS.dwPostStack]
+%endif
+%endmacro
+
+
+%endif ; BOOTVARS_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/CustomDPT.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/CustomDPT.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/CustomDPT.inc	(revision 352)
@@ -0,0 +1,87 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Defines for DPT structs containing custom
+;					Disk Parameter Table used by this BIOS.
+%ifndef CUSTOMDPT_INC
+%define CUSTOMDPT_INC
+
+; Base DPT for all device types
+struc DPT	; 10 bytes
+	; General Disk Parameter Table related
+	.wFlags:
+	.bFlagsLow					resb	1
+	.bFlagsHigh					resb	1
+	.bIdevarsOffset				resb	1	; Offset to IDEVARS for this drive
+
+	; IDE Drive related
+	; .bLbaHeads and .twLbaSectors are used for LBA addressing only.
+	.bLbaHeads:					resb	1	; Number of LBA assisted heads (1...255)
+	.twLbaSectors				resb	2	; 48-bit sector count for LBA addressing
+
+	; .wPchsCylinders and .bPchsSectors are used for CHS addressing only.
+	.wPchsCylinders				resb	2	; Number of P-CHS Cylinders (1...16383)
+	.wPchsHeadsAndSectors:
+	.bPchsHeads					resb	1	; Number of P-CHS heads (1...16)
+	.bPchsSectors				resb	1	; Number of P-CHS Sectors per Track (1...63)
+endstruc
+
+; DPT for ATA devices
+struc DPT_ATA	; 10 + 2 bytes = 12 bytes
+	.dpt						resb	DPT_size
+
+	; Block size is specified in sectors (1, 2, 4, 8, 16, 32, 64 or 128)
+	.wSetAndMaxBlock:
+	.bSetBlock					resb	1	; Current block size (at least 1)
+	.bMaxBlock					resb	1	; Maximum block size, 0 = block mode not supported
+endstruc
+
+%ifdef MODULE_SERIAL
+; DPT for Serial devices
+struc DPT_SERIAL
+	.dpt						resb	DPT_size
+
+	.wSerialPortAndBaud:
+	.bSerialPort				resb	1	; Serial connection I/O port address, divided by 4
+	.bSerialBaud				resb 	1	; Serial connection baud rate divisor
+endstruc
+%endif
+
+LARGEST_DPT_SIZE				EQU		DPT_ATA_size
+
+
+; Bit definitions for DPT.bFlagsLow
+MASKL_DPT_CHS_SHIFT_COUNT		EQU	(7<<0)	; Bits 0...3, P-CHS to L-CHS bit shift count (0...4)
+FLGL_DPT_SLAVE					EQU	FLG_DRVNHEAD_DRV	; (1<<4), Drive is slave drive
+MASKL_DPT_ADDRESSING_MODE		EQU	(3<<5)	; Bits 5..6, Addressing Mode (bit 6 == FLG_DRVNHEAD_LBA)
+FLGL_DPT_ENABLE_IRQ				EQU	(1<<7)
+
+; Bit definitions for DPT.bFlagsHigh
+FLGH_DPT_REVERSED_A0_AND_A3		EQU	(1<<0)	; XTIDE mod, Address lines 0 and 3 reversed
+FLGH_DPT_BLOCK_MODE_SUPPORTED	EQU	(1<<1)	; Use block transfer commands (must be bit 1!)
+%ifdef MODULE_SERIAL
+FLGH_DPT_SERIAL_DEVICE			EQU	(1<<2)	; Serial Port Device
+%endif
+FLGH_DPT_INTERRUPT_IN_SERVICE	EQU	(1<<3)	; Set when waiting for IRQ
+FLGH_DPT_RESET_nDRDY			EQU	(1<<4)	; Drive ready to accept commands
+FLGH_DPT_RESET_nINITPRMS		EQU	(1<<5)	; Initialize Device Parameters successful
+FLGH_DPT_RESET_nRECALIBRATE		EQU	(1<<6)	; Recalibrate successful
+FLGH_DPT_RESET_nSETBLOCK		EQU	(1<<7)	; Initialize Block Mode successful
+MASKH_DPT_RESET					EQU	0F0h
+
+FLGH_DPT_SERIAL_FLOPPY						EQU	(1<<4)
+FLGH_DPT_SERIAL_FLOPPY_TYPE_MASK			EQU	0e0h
+FLGH_DPT_SERIAL_FLOPPY_TYPE_FIELD_POSITION	EQU	5
+
+; Addressing modes for DPT.wFlags
+ADDRESSING_MODE_FIELD_POSITION	EQU		5
+ADDRESSING_MODE_LCHS			EQU		0	; L-CHS Addressing Mode (NORMAL in many other BIOSes)
+ADDRESSING_MODE_PCHS			EQU		1	; P-CHS Addressing Mode (LARGE in many other BIOSes)
+ADDRESSING_MODE_LBA28			EQU		2	; 28-bit LBA Addressing Mode
+ADDRESSING_MODE_LBA48			EQU		3	; 48-bit LBA Addressing Mode
+
+; Number of Sectors per Track is fixed to 63 for LBA assist calculation.
+; 1024 cylinders, 256 heads, 63 sectors = 8.4 GB limit (but DOS does not support more than 255 heads)
+MAX_LCHS_CYLINDERS				EQU		1024
+LBA_ASSIST_SPT					EQU		63
+
+
+%endif ; CUSTOMDPT_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/DeviceIDE.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/DeviceIDE.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/DeviceIDE.inc	(revision 352)
@@ -0,0 +1,18 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Device specific equates for IDE drives.
+%ifndef DEVICEIDE_INC
+%define DEVICEIDE_INC
+
+; Reset delays
+HSR0_RESET_WAIT_US		EQU		5		; Delay at least 5us
+HSR1_RESET_WAIT_US		EQU		2000	; Delay at least 2ms
+
+; Polling timeout delays (system timer ticks, 1 tick = 54.9 ms)
+TIMEOUT_BSY				EQU		(2000/55)	; 2000 ms
+TIMEOUT_DRDY			EQU		(2000/55)	; 2000 ms
+TIMEOUT_DRQ				EQU		255			;   14 s (some CF cards occasionally have long write delays)
+TIMEOUT_IDENTIFY_DEVICE	EQU		(500/55)	;  500 ms
+TIMEOUT_MOTOR_STARTUP	EQU		(10000/55)	;   10 s
+
+
+%endif ; DEVICEIDE_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/EBIOS.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/EBIOS.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/EBIOS.inc	(revision 352)
@@ -0,0 +1,53 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Equates used in Enhanced INT 13h functions (EBIOS).
+%ifndef EBIOS_INC
+%define EBIOS_INC
+
+; EBIOS specification returned by INT 13h, AH=41h
+EBIOS_VERSION						EQU	21h		; 21h = EDD version 1.1
+
+; Support bits returned by INT 13h, AH=41h
+ENHANCED_DRIVE_ACCESS_SUPPORT		EQU	(1<<0)	; 41h, 42h, 43h 44h, 47h and 48h are available
+DRIVE_LOCKING_AND_EJECTING_SUPPORT	EQU	(1<<1)	; 41h, 45h, 46h, 48h, 49h are available and INT 15h, AH=52h
+ENHANCED_DISK_DRIVE_SUPPORT			EQU	(1<<2)	; 41h, 48h, 4Eh are available (EDD)
+
+
+; Extended Drive Information returned by AH=48h
+struc EDRIVE_INFO
+	.wSize					resb	2	; 0, Size of this buffer, at least 26
+	.wFlags					resb	2	; 2, Information flags
+	.dwCylinders			resb	4	; 4, Total number of addressable cylinders
+	.dwHeads				resb	4	; 8, Total number of addressable heads
+	.dwSectorsPerTrack		resb	4	; 12, Number of sectors per track
+	.qwTotalSectors			resb	8	; 16, Total number of addressable sectors
+	.wSectorSize			resb	2	; 24, Number of bytes per sector
+	.fpEDDparams			resb	8	; 26, Optional pointer to Enhanced Disk Drive (EDD) configuration parameters
+endstruc
+
+MINIMUM_EDRIVEINFO_SIZE		EQU		26	; 26 bytes does not include EDD pointer
+
+; Flags for EDRIVE_INFO.wFlags
+FLG_DMA_BOUNDARY_ERRORS_HANDLED_BY_BIOS				EQU	(1<<0)
+FLG_CHS_INFORMATION_IS_VALID						EQU	(1<<1)
+FLG_REMOVABLE_DRIVE									EQU	(1<<2)
+FLG_WRITE_WITH_VERIFY_SUPPORTED						EQU	(1<<3)
+FLG_CHANGE_LINE_SUPPORT								EQU	(1<<4)	; Removable media only
+FLG_LOCKABLE										EQU	(1<<5)	; Removable media only
+FLG_NO_MEDIA_PRESENT_AND_CHS_SET_TO_MAX				EQU	(1<<6)	; Removable media only
+
+
+; Disk Address Packet for read, write and verify functions
+struc DAP
+	.bSize					resb	1	; 0, Size of this packet in bytes
+	.bReservedAt1			resb	1	; 1, Currently unused, must be zero
+	.wSectorCount			resb	2	; 2, Number of sectors to process (0...127)
+	.dwMemoryAddress:
+	.wOffset				resb	2	; 4, Memory offset for transfer
+	.wSegment				resb	2	; 6, Memory segment for transfer
+	.qwLBA					resb	8	; 8, Starting sector for transfer
+endstruc
+
+MINIMUM_DAP_SIZE			EQU		16
+
+
+%endif ; EBIOS_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/IDE_8bit.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/IDE_8bit.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/IDE_8bit.inc	(revision 352)
@@ -0,0 +1,100 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Macros for accessing data port(s) on 8-bit
+;					IDE controllers.
+%ifndef IDE_8BIT_INC
+%define IDE_8BIT_INC
+
+;--------------------------------------------------------------------
+; Emulates INSW for XTIDE.
+;
+; XTIDE_INSW
+;	Parameters:
+;		BX:		Bit mask for toggling XTIDE data low/high reg
+;		DX:		XTIDE Data Low Register address
+;		ES:DI:	Ptr to destination buffer
+;	Returns:
+;		ES:DI:	Incremented/decremented for next word
+;	Corrupts registers:
+;		AL, FLAGS
+;--------------------------------------------------------------------
+%macro XTIDE_INSW 0
+%ifdef USE_186	; INS instruction available
+	insb						; Load low byte from port DX to [ES:DI]
+	xor		dx, bx				; IDE Data Reg to XTIDE Data High Reg
+	insb						; Load high byte from port DX to [ES:DI]
+	xor		dx, bx				; Restore to IDE Data Register
+%else	; If 8088/8086
+	in		al, dx				; Load low byte from port
+	xor		dx, bx				; IDE Data Reg to XTIDE Data High Reg
+	stosb						; Store byte to [ES:DI]
+	in		al, dx				; Load high byte from port
+	xor		dx, bx				; Restore to IDE Data Register
+	stosb						; Store byte to [ES:DI]
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates OUTSW for XTIDE.
+;
+; XTIDE_OUTSW
+;	Parameters:
+;		BX:		Bit mask for toggling XTIDE data low/high reg
+;		DX:		XTIDE Data Low Register address
+;		DS:SI:	Ptr to source buffer
+;	Returns:
+;		SI:		Incremented/decremented for next word
+;	Corrupts registers:
+;		AX, FLAGS
+;--------------------------------------------------------------------
+%macro XTIDE_OUTSW 0
+%ifdef USE_186	; OUTS instruction available
+	lodsb						; Load low byte from [DS:SI] to AL
+	xor		dx, bx				; IDE Data Reg to XTIDE Data High Reg
+	outsb						; Output high byte from [DS:SI]
+	xor		dx, bx				; XTIDE Data High Reg to Data Low Reg
+	out		dx, al				; Output low byte from AL
+%else	; If 8088/8086
+	lodsw						; Load word from [DS:SI]
+	xor		dx, bx				; IDE Data Reg to XTIDE Data High Reg
+	xchg	al, ah				; => AL=high byte, AH=low byte
+	out		dx, al				; Output high byte
+	xor		dx, bx				; XTIDE Data High Reg to Data Low Reg
+	mov		al, ah				; Copy low byte to AL
+	out		dx, al				; Output low byte
+%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; Emulates OUTSW for modified XTIDE.
+;
+; XTIDE_MOD_OUTSW
+;	Parameters:
+;		DX:		XTIDE Data Low Register address
+;		DS:SI:	Ptr to source buffer
+;	Returns:
+;		SI:		Incremented/decremented for next word
+;	Corrupts registers:
+;		AX, FLAGS
+;--------------------------------------------------------------------
+%macro XTIDE_MOD_OUTSW 0
+%ifdef USE_186	; OUTS instruction available
+	lodsb						; Load low byte from [DS:SI] to AL
+	inc		dx					; IDE Data Reg to XTIDE MOD Data High Reg
+	outsb						; Output high byte from [DS:SI]
+	dec		dx					; XTIDE Data High Reg to Data Low Reg
+	out		dx, al				; Output low byte from AL
+%else	; If 8088/8086
+	lodsw						; Load word from [DS:SI]
+	inc		dx					; IDE Data Reg to XTIDE MOD Data High Reg
+	xchg	al, ah				; => AL=high byte, AH=low byte
+	out		dx, al				; Output high byte
+	dec		dx					; XTIDE Data High Reg to Data Low Reg
+	mov		al, ah				; Copy low byte to AL
+	out		dx, al				; Output low byte
+%endif
+%endmacro
+
+
+%endif ; IDE_8BIT_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/IdeRegisters.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/IdeRegisters.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/IdeRegisters.inc	(revision 352)
@@ -0,0 +1,88 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Equates for IDE registers, flags and commands.
+%ifndef IDEREGISTERS_INC
+%define IDEREGISTERS_INC
+
+; IDE Register offsets from Command Block base port
+DATA_REGISTER					EQU		0
+ERROR_REGISTER_in				EQU		1		; Read only
+FEATURES_REGISTER_out			EQU		1		; Write only, ATA1+
+;WRITE_PRECOMPENSATION_out		EQU		1		; Write only, Obsolete on ATA1+
+SECTOR_COUNT_REGISTER			EQU		2
+SECTOR_NUMBER_REGISTER			EQU		3		; LBA Low Register
+LOW_CYLINDER_REGISTER			EQU		4		; LBA Middle Register
+HIGH_CYLINDER_REGISTER			EQU		5		; LBA High Register
+LBA_LOW_REGISTER				EQU		3		; LBA 7...0, LBA48 31...24
+LBA_MIDDLE_REGISTER				EQU		4		; LBA 15...8, LBA48 39...32
+LBA_HIGH_REGISTER				EQU		5		; LBA 23...16, LBA48 47...40
+DRIVE_AND_HEAD_SELECT_REGISTER	EQU		6		; LBA28 27...24
+STATUS_REGISTER_in				EQU		7		; Read only
+COMMAND_REGISTER_out			EQU		7		; Write only
+;XTIDE_DATA_HIGH_REGISTER		EQU		8		; Non-standard (actually first Control Block reg)
+
+; IDE Register offsets from Control Block base port
+; (usually Command Block base port + 200h)
+ALTERNATE_STATUS_REGISTER_in	EQU		6		; Read only
+DEVICE_CONTROL_REGISTER_out		EQU		6		; Write only
+;DRIVE_ADDRESS_REGISTER			EQU		7		; Obsolete on ATA2+
+
+; Bit mask for XTIDE mod with reversed A0 and A3 address lines
+MASK_A3_AND_A0_ADDRESS_LINES	EQU		((1<<3) | (1<<0))
+
+; Bit definitions for IDE Error Register
+FLG_ERROR_BBK			EQU		(1<<7)	; Bad Block Detected (reserved on ATA2+, command dependent on ATA4+)
+FLG_ERROR_UNC			EQU		(1<<6)	; Uncorrectable Data Error (command dependent on ATA4+)
+FLG_ERROR_MC			EQU		(1<<5)	; Media Changed (command dependent on ATA4+)
+FLG_ERROR_IDNF			EQU		(1<<4)	; ID Not Found (command dependent on ATA4+)
+FLG_ERROR_MCR			EQU		(1<<3)	; Media Change Request (command dependent on ATA4+)
+FLG_ERROR_ABRT			EQU		(1<<2)	; Command Aborted
+FLG_ERROR_TK0NF			EQU		(1<<1)	; Track 0 Not Found (command dependent on ATA4+)
+FLG_ERROR_AMNF			EQU		(1<<0)	; Address Mark Not Found (command dependent on ATA4+)
+
+; Bit definitions for IDE Drive and Head Select Register
+FLG_DRVNHEAD_LBA		EQU		(1<<6)	; LBA Addressing enabled (instead of CHS)
+FLG_DRVNHEAD_DRV		EQU		(1<<4)	; Drive Select (0=Master, 1=Slave)
+MASK_DRVNHEAD_HEAD		EQU		0Fh		; Head select bits (bits 0...3)
+MASK_DRVNHEAD_SET		EQU		0A0h	; Bits that must be set to 1 on ATA1 (reserved on ATA2+)
+
+; Bit definitions for IDE Status Register
+FLG_STATUS_BSY			EQU		(1<<7)	; Busy (other flags undefined when set)
+FLG_STATUS_DRDY			EQU		(1<<6)	; Device Ready
+FLG_STATUS_DF			EQU		(1<<5)	; Device Fault (command dependent on ATA4+)
+FLG_STATUS_DSC			EQU		(1<<4)	; Device Seek Complete (command dependent on ATA4+)
+FLG_STATUS_DRQ			EQU		(1<<3)	; Data Request
+FLG_STATUS_CORR			EQU		(1<<2)	; Corrected Data (obsolete on ATA4+)
+FLG_STATUS_IDX			EQU		(1<<1)	; Index (vendor specific on ATA2+, obsolete on ATA4+)
+FLG_STATUS_ERR			EQU		(1<<0)	; Error
+
+; Bit definitions for IDE Device Control Register
+; Bit 0 must be zero, unlisted bits are reserved.
+;FLG_DEVCONTROL_HOB		EQU		(1<<7)	; High Order Byte (ATA6+)
+;FLG_DEVCONTROL_O8H		EQU		(1<<3)	; Drive has more than 8 heads (pre-ATA only, 1 on ATA1, reserved on ATA2+)
+FLG_DEVCONTROL_SRST		EQU		(1<<2)	; Software Reset
+FLG_DEVCONTROL_nIEN		EQU		(1<<1)	; Negated Interrupt Enable (IRQ disabled when set)
+
+; Commands for IDE Controller
+COMMAND_READ_SECTORS					EQU		20h
+COMMAND_READ_SECTORS_EXT				EQU		24h		; LBA48
+COMMAND_WRITE_SECTORS					EQU		30h
+COMMAND_WRITE_SECTORS_EXT				EQU		34h		; LBA48
+COMMAND_VERIFY_SECTORS					EQU		40h
+COMMAND_VERIFY_SECTORS_EXT				EQU		42h		; LBA48
+COMMAND_SEEK							EQU		70h
+COMMAND_INITIALIZE_DEVICE_PARAMETERS	EQU		91h
+COMMAND_SET_MULTIPLE_MODE				EQU		0C6h	; Block mode
+COMMAND_READ_MULTIPLE					EQU		0C4h	; Block mode
+COMMAND_READ_MULTIPLE_EXT				EQU		29h		; LBA48, Block mode
+COMMAND_WRITE_MULTIPLE					EQU		0C5h	; Block mode
+COMMAND_WRITE_MULTIPLE_EXT				EQU		39h		; LBA48, Block mode
+COMMAND_IDENTIFY_DEVICE					EQU		0ECh
+COMMAND_SET_FEATURES					EQU		0EFh
+
+
+; Subcommands for COMMAND_SET_FEATURES
+FEATURE_ENABLE_WRITE_CACHE				EQU		02h
+FEATURE_DISABLE_WRITE_CACHE				EQU		82h		; Can also be used to flush cache
+
+
+%endif ; IDEREGISTERS_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/Int13h.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/Int13h.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/Int13h.inc	(revision 352)
@@ -0,0 +1,50 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Equates used in INT 13h functions.
+%ifndef INT13H_INC
+%define INT13H_INC
+
+; Hard Disk function (INT 13h) return status codes in AH
+RET_HD_SUCCESS			EQU		0h		; Operation successful, no error occurred
+RET_HD_INVALID			EQU		1h		; Invalid value passed or unsupported func
+RET_HD_ADDRMARK			EQU		2h		; Missing address mark
+RET_HD_WRITEPROT		EQU		3h		; Removable media is write protected
+RET_HD_NOT_FOUND		EQU		4h		; Requested sector not found
+RET_HD_RESETFAIL		EQU		5h		; Reset failed
+RET_HD_CHANGED			EQU		6h		; Media changed
+RET_HD_PARAMACT			EQU		7h		; Drive parameter activity failed
+RET_HD_OVERRUN			EQU		8h		; DMA overrun
+RET_HD_BOUNDARY			EQU		9h		; Data boundary error
+RET_HD_BADSECTOR		EQU		0Ah		; Bad sector detected
+RET_HD_BADTRACK			EQU		0Bh		; Bad track detected
+RET_HD_UNCORRECC		EQU		10h		; Uncorrectable ECC error
+RET_HD_ECC				EQU		11h		; Corrected ECC error
+RET_HD_CONTROLLER		EQU		20h		; Hard disk controller or drive problem
+RET_HD_NOMEDIA			EQU		31h		; No media in removable media drive
+RET_HD_SEEK_FAIL		EQU		40h		; Seek operation failed
+RET_HD_TIMEOUT			EQU		80h		; Drive failed to respond
+RET_HD_NOTREADY			EQU		0AAh	; Drive is not ready or is not selected
+RET_HD_NOTLOCKED		EQU		0B0h	; Volume not locked in drive
+RET_HD_LOCKED			EQU		0B1h	; Volume locked in drive
+RET_HD_NOTREMOVABLE		EQU		0B2h	; Volume not removable
+RET_HD_INUSE			EQU		0B3h	; Volume in use
+RET_HD_LOCKEXCEEDED		EQU		0B4h	; Lock count exceeded
+RET_HD_EJECTFAIL		EQU		0B5h	; Valid eject request failed
+RET_HD_UNDEFINED		EQU		0BBh	; Undefined error occurred
+RET_HD_WRFAULT			EQU		0CCh	; Write fault on selected drive
+RET_HD_STATUSERR		EQU		0E0h	; Status error without error
+RET_HD_SENSEFAIL		EQU		0FFh	; Sense operation failed
+
+
+; Floppy Drive types returned by INT 13h, AH=08h
+FLOPPY_TYPE_525_OR_35_DD	EQU	0
+FLOPPY_TYPE_525_DD			EQU	1
+FLOPPY_TYPE_525_HD			EQU	2
+FLOPPY_TYPE_35_DD			EQU	3
+FLOPPY_TYPE_35_HD			EQU	4
+FLOPPY_TYPE_35_ED			EQU	6
+
+
+%define TIMEOUT_AND_STATUS_TO_WAIT(timeout, status)		(((timeout)<<8) | (status))
+
+
+%endif ; INT13H_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/IntController.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/IntController.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/IntController.inc	(revision 352)
@@ -0,0 +1,52 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Equates for 8259 Interrupt Controllers.
+%ifndef INT_CONTROLLER_INC
+%define INT_CONTROLLER_INC
+
+; 8259 Master and Slave Interrupt Controller Ports
+MASTER_8259_IRR_AND_ISR_in	EQU		20h		; Interrupt Request Register / Interrupt In-Service Register
+MASTER_8259_COMMAND_out		EQU		20h		; Command output
+MASTER_8259_IMR				EQU		21h		; Interrupt Mask Register
+MASTER_8259_INIT_out		EQU		21h		; Initialization Command Parameters
+SLAVE_8259_IRR_AND_ISR_in	EQU		0A0h	; Interrupt Request Register / Interrupt In-Service Register
+SLAVE_8259_COMMAND_out		EQU		0A0h	; Command output
+SLAVE_8259_IMR				EQU		0A1h	; Interrupt Mask Register
+SLAVE_8259_INIT_out			EQU		0A1h	; Initialization Command Parameters
+
+; 8259 Interrupt Controller Commands
+COMMAND_CLEAR_ROTATE_IN_AUTOMATIC_EOI_MODE	EQU		00h
+COMMAND_READ_INTERRUPT_REQUEST_REGISTER		EQU		0Ah
+COMMAND_READ_INTERRUPT_INSERVICE_REGISTER	EQU		0Bh
+COMMAND_END_OF_INTERRUPT					EQU		20h
+COMMAND_NO_OPERATION						EQU		40h
+COMMAND_CLEAR_SPECIAL_MASK_MODE				EQU		48h
+COMMAND_SPECIFIC_EOI_FOR_IR0				EQU		60h
+COMMAND_SPECIFIC_EOI_FOR_IR1				EQU		61h
+COMMAND_SPECIFIC_EOI_FOR_IR2				EQU		62h
+COMMAND_SPECIFIC_EOI_FOR_IR3				EQU		63h
+COMMAND_SPECIFIC_EOI_FOR_IR4				EQU		64h
+COMMAND_SPECIFIC_EOI_FOR_IR5				EQU		65h
+COMMAND_SPECIFIC_EOI_FOR_IR6				EQU		66h
+COMMAND_SPECIFIC_EOI_FOR_IR7				EQU		67h
+COMMAND_SET_SPECIAL_MASK_MODE				EQU		68h
+COMMAND_SET_ROTATE_IN_AUTOMATIC_EOI_MODE	EQU		80h
+COMMAND_ROTATE_ON_NONSPECIFIC_EOI			EQU		0A0h
+COMMAND_IR0_LOWEST_PRIORITY					EQU		0C0h
+COMMAND_IR1_LOWEST_PRIORITY					EQU		0C1h
+COMMAND_IR2_LOWEST_PRIORITY					EQU		0C2h
+COMMAND_IR3_LOWEST_PRIORITY					EQU		0C3h
+COMMAND_IR4_LOWEST_PRIORITY					EQU		0C4h
+COMMAND_IR5_LOWEST_PRIORITY					EQU		0C5h
+COMMAND_IR6_LOWEST_PRIORITY					EQU		0C6h
+COMMAND_IR7_LOWEST_PRIORITY					EQU		0C7h
+COMMAND_EOI_AND_IR0_LOWEST_PRIORITY			EQU		0E0h
+COMMAND_EOI_AND_IR1_LOWEST_PRIORITY			EQU		0E1h
+COMMAND_EOI_AND_IR2_LOWEST_PRIORITY			EQU		0E2h
+COMMAND_EOI_AND_IR3_LOWEST_PRIORITY			EQU		0E3h
+COMMAND_EOI_AND_IR4_LOWEST_PRIORITY			EQU		0E4h
+COMMAND_EOI_AND_IR5_LOWEST_PRIORITY			EQU		0E5h
+COMMAND_EOI_AND_IR6_LOWEST_PRIORITY			EQU		0E6h
+COMMAND_EOI_AND_IR7_LOWEST_PRIORITY			EQU		0E7h
+
+
+%endif ; INT_CONTROLLER_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/RamVars.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/RamVars.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/RamVars.inc	(revision 352)
@@ -0,0 +1,90 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	RAMVARS struct containing BIOS variables stored in RAM.
+%ifndef RAMVARS_INC
+%define RAMVARS_INC
+
+; Segment when RAMVARS is stored to top of interrupt vectors.
+LITE_MODE_RAMVARS_SEGMENT	EQU		30h
+
+
+; 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
+	.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
+endstruc
+
+; RAM Variables.
+; Variables should be kept to minimum since they might be located
+; at the top of interrupt vectors.
+struc RAMVARS
+	.fpOldI13h			resb	4	; Far pointer to old INT 13h handler
+	.wSignature			resb	2	; Sign for finding stolen 1 kiB
+	.bTimeoutTicksLeft	resb	1
+	.bLastTimeoutUpdate	resb	1
+
+	.wDrvCntAndFirst:
+	.bFirstDrv			resb	1	; Number of first drive for this BIOS
+	.wDrvCntAndFlopCnt:				; Both the hard disk and floppy counts in one word
+									; (yes, misaligned, but it is only used this way during initialization)
+	.bDrvCnt			resb	1	; Number of drives handled by this BIOS
+
+	; Variables for drive number translation
+	.xlateVars		resb	XLATEVARS_size
+endstruc
+
+%ifdef MODULE_SERIAL_FLOPPY
+  %ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if RAMVARS.xlateVars != RAMVARS.bDrvCnt+1 || XLATEVARS.bFlopCreateCnt != 0
+		%error "bFlopCreateCnt needs to be the first thing in XLATEVARS, and .xlateVars needs to come immediately after .bDrvCnt.  In at least one place, we read .wDrvCntAndFlopCnt to get both counts in one fetch"
+	%endif
+  %endif
+%endif
+
+RAMVARS_SIGNATURE		EQU	"Xu"	; RAMVARS signature for .wSignature
+
+;
+; IDEPACK NOTE: The first six bytes of this structure are directly put on the 
+; wire for MODULE_SERIAL, please do not change the order or insert other members.
+;
+struc IDEPACK
+	.bFeatures				resb	1
+	.bDrvAndHead			resb	1	; LBA28 27...24
+
+	.wSectorCountAndLbaLow:
+	.bSectorCount			resb	1
+	.bSectorNumber:
+	.bLbaLow				resb	1	; LBA 7...0
+
+	.wCylinder:
+	.wLbaMiddleAndHigh:
+	.bLbaMiddle				resb	1	; LBA 15...8
+	.bLbaHigh				resb	1	; LBA 23...16
+
+	.bCommand				resb	1
+	.bDeviceControl			resb	1	; Offset 7 shared with PIOVARS
+							resb	1
+
+	; Parameters for 48-bit LBA
+	.bLbaLowExt				resb	1	; LBA48 31...24
+	.wLbaMiddleAndHighExt:
+	.bLbaMiddleExt			resb	1	; LBA48 39...32
+	.bLbaHighExt			resb	1	; LBA48 47...40
+
+	.intpack				resb	INTPACK_size
+endstruc
+
+EXTRA_BYTES_FOR_INTPACK		EQU	(IDEPACK_size - INTPACK_size)
+
+
+%endif ; RAMVARS_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/RomVars.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/RomVars.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Inc/RomVars.inc	(revision 352)
@@ -0,0 +1,132 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Defines for ROMVARS struct containing variables stored
+;					in BIOS ROM.
+%ifndef ROMVARS_INC
+%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
+	.wfDisplayBootMenu:				; Zero = no Boot Menu, non-zero = Boot Menu timeout
+	.wBootTimeout		resb	2	; Boot Menu selection timeout in system timer ticks
+	.bIdeCnt			resb	1	; Number of available IDE controllers
+	.bBootDrv			resb	1	; Boot Menu default drive
+	.bMinFddCnt			resb	1	; Minimum number of Floppy Drives
+	.bStealSize			resb	1	; Number of 1kB blocks stolen from 640kB base RAM
+
+	.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
+
+%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
+
+; Bit defines for ROMVARS.wFlags
+FLG_ROMVARS_FULLMODE				EQU	(1<<0)	; Full operating mode (steals base RAM, supports EBIOS etc.)
+FLG_ROMVARS_DRVXLAT					EQU	(1<<2)	; Enable drive number translation
+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)
+FLG_ROMVARS_MODULE_JRIDE			EQU	(1<<5)	; Here in case the configuration needs to know functionality is present
+FLG_ROMVARS_MODULE_SERIAL			EQU (1<<6)	; Here in case the configuration needs to know functionality is present
+FLG_ROMVARS_MODULE_EBIOS			EQU (1<<7)	; Here in case the configuration needs to know functionality is present
+
+; Boot Menu Display Modes (see Assembly Library Display.inc for standard modes)
+DEFAULT_TEXT_MODE		EQU	4
+
+
+; Controller specific variables
+struc IDEVARS
+;;; Word 0
+	.wSerialPortAndBaud:					; Serial connection port (low, divided by 4) and baud rate divisor (high)
+	.wPort:									; IDE Base Port for Command Block (usual) Registers
+	.bSerialPort				resb	1
+	.bSerialBaud				resb	1
+
+;;; Word 1
+	.wPortCtrl:
+	.bSerialUnused				resb	1	; IDE Base Port for Control Block Registers
+
+	.wSerialCOMPortCharAndDevice:			; In DetectPrint, we grab the COM Port char and Device at the same time
+	.bSerialCOMPortChar			resb	1	; Serial connection COM port number/letter
+
+;;; Word 2
+	.bDevice					resb	1	; Device type
+
+	.bIRQ						resb	1	; Interrupt Request Number
+
+;;; And more...
+	.drvParamsMaster			resb	DRVPARAMS_size
+	.drvParamsSlave				resb	DRVPARAMS_size
+endstruc
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if IDEVARS.bSerialCOMPortChar+1 != IDEVARS.bDevice
+		%error "IDEVARS.bSerialCOMPortChar needs to come immediately before IDEVARS.bDevice so that both bytes can be fetched at the same time inside DetectPrint.asm"
+	%endif
+%endif
+
+; Default values for Port and PortCtrl, shared with the configurator
+;
+DEVICE_XTIDE_DEFAULT_PORT				EQU		300h
+DEVICE_XTIDE_DEFAULT_PORTCTRL			EQU		308h
+DEVICE_ATA_DEFAULT_PORT					EQU		1F0h
+DEVICE_ATA_DEFAULT_PORTCTRL				EQU		3F0h
+
+; Device types for IDEVARS.bDevice
+;
+DEVICE_8BIT_DUAL_PORT_XTIDE				EQU	(0<<1)
+DEVICE_XTIDE_WITH_REVERSED_A3_AND_A0	EQU	(1<<1)
+DEVICE_8BIT_SINGLE_PORT					EQU	(2<<1)
+DEVICE_16BIT_ATA						EQU	(3<<1)
+DEVICE_32BIT_ATA						EQU	(4<<1)
+DEVICE_SERIAL_PORT						EQU	(5<<1)
+DEVICE_JRIDE_ISA						EQU	(6<<1)
+
+
+; 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
+
+; Bit defines for DRVPARAMS.wFlags
+MASK_DRVPARAMS_WRITECACHE	EQU	(3<<0)	; Drive internal write cache settings (must start at bit 0)
+FLG_DRVPARAMS_BLOCKMODE		EQU	(1<<2)	; Enable Block mode transfers
+FLG_DRVPARAMS_USERCHS		EQU	(1<<3)	; User specified P-CHS values
+FLG_DRVPARAMS_USERLBA		EQU	(1<<4)	; User specified LBA values
+
+; Drive Write Cache values for DRVPARAMS.wFlags.MASK_DRVPARAMS_WRITECACHE
+DEFAULT_WRITE_CACHE			EQU	0		; Must be 0
+DISABLE_WRITE_CACHE			EQU	1
+ENABLE_WRITE_CACHE			EQU	2
+
+%endif ; ROMVARS_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenu.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenu.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenu.asm	(revision 352)
@@ -0,0 +1,224 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Displays Boot Menu.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Displays Boot Menu and returns Drive or Function number.
+;
+; BootMenu_DisplayAndReturnSelectionInDX
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		DX:		Untranslated drive number to be used for booting
+;	Corrupts registers:
+;		All General Purpose Registers
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_DisplayAndReturnSelectionInDX:
+	call	DriveXlate_Reset
+	call	BootMenuPrint_TheBottomOfScreen
+	call	BootMenu_Enter			; Get selected menuitem index to CX
+	call	BootMenuPrint_ClearScreen
+	call	BootMenu_GetDriveToDXforMenuitemInCX
+	jnc		BootMenu_DisplayAndReturnSelectionInDX
+	ret
+
+;--------------------------------------------------------------------
+; BootMenu_GetDriveToDXforMenuitemInCX_And_RamVars_GetSegmentToDS
+; BootMenu_GetDriveToDXforMenuitemInCX
+;	Parameters:
+;		CX:		Index of menuitem selected from Boot Menu
+;	Returns:
+;		DX:		Drive number to be used for booting
+;		DS:		RAMVARS segment
+;       CF:     Set: There is a selected menu item, DL is valid
+;               Clear: There is no selected menu item, DL is not valid
+;	Corrupts registers:
+;		AX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetDriveToDXforMenuitemInCX_And_RamVars_GetSegmentToDS:
+	call	RamVars_GetSegmentToDS
+;;; fall-through
+
+ALIGN JUMP_ALIGN
+BootMenu_GetDriveToDXforMenuitemInCX:
+	cmp		cl, NO_ITEM_HIGHLIGHTED
+	je		SHORT .ReturnFloppyDriveInDX	; Clear CF if branch taken
+
+	mov		dl, cl							; Copy menuitem index to DX
+	call	FloppyDrive_GetCountToAX
+	cmp		dl, al							; Floppy drive?
+	jb		SHORT .ReturnFloppyDriveInDX	; Set CF if branch taken
+	or		al, 80h							; Or 80h into AL before the sub
+											; to cause CF to be set after
+											; and result has high order bit set
+	sub		dl, al							; Remove floppy drives from index
+
+.ReturnFloppyDriveInDX:
+	ret
+
+
+;--------------------------------------------------------------------
+; Enters Boot Menu or submenu.
+;
+; BootMenu_Enter
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CX:		Index of selected item or NO_ITEM_SELECTED
+;	Corrupts registers:
+;		AX, BX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_Enter:
+	mov		bx, BootMenuEvent_Handler
+	CALL_MENU_LIBRARY DisplayWithHandlerInBXandUserDataInDXAX
+	xchg	cx, ax
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns number of menuitems in Boot Menu.
+;
+; BootMenu_GetMenuitemCountToAX
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AX:		Number of boot menu items
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetMenuitemCountToAX:
+	call	RamVars_GetHardDiskCountFromBDAtoAX
+	xchg	ax, cx
+	call	FloppyDrive_GetCountToAX
+	add		ax, cx
+	ret
+
+
+;--------------------------------------------------------------------
+; BootMenu_GetHeightToAHwithItemCountInAL
+;	Parameters:
+;		AL:		Number of menuitems
+;	Returns:
+;		AH:		Boot menu height
+;	Corrupts registers:
+;		AL, CX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetHeightToAHwithItemCountInAL:
+	add		al, BOOT_MENU_HEIGHT_WITHOUT_ITEMS
+	xchg	cx, ax
+	CALL_DISPLAY_LIBRARY GetColumnsToALandRowsToAH
+	sub		ah, MENU_SCREEN_BOTTOM_LINES*2	; Leave space for bottom info
+	cmp		ah, cl
+	jb		SHORT .Return
+	mov		ah, cl
+ALIGN JUMP_ALIGN, ret
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; BootMenu_GetMenuitemToAXforAsciiHotkeyInAL
+;	Parameters:
+;		AL:		ASCII hotkey
+;	Returns:
+;		AX:		Menuitem index
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetMenuitemToAXforAsciiHotkeyInAL:
+	call	Char_ALtoUpperCaseLetter
+	cbw
+	xchg	ax, cx
+	call	BootMenu_GetLetterForFirstHardDiskToAL
+	cmp		cl, al						; Letter is for Hard Disk?
+	jae		SHORT .StartFromHardDiskLetter
+	xchg	ax, cx
+	sub		al, 'A'						; Letter to Floppy Drive menuitem
+	ret
+ALIGN JUMP_ALIGN
+.StartFromHardDiskLetter:
+	sub		cl, al						; Hard Disk index
+	call	FloppyDrive_GetCountToAX
+	add		ax, cx						; Menuitem index
+										; Note: no need to xchg ax, cx as above, since adding with result to ax
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns letter for first hard disk. Usually it will be 'c' but it
+; can be higher if more than two floppy drives are found.
+;
+; BootMenu_GetLetterForFirstHardDiskToCL
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CL:		Upper case letter for first hard disk
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetLetterForFirstHardDiskToAL:
+	call	FloppyDrive_GetCountToAX
+	add		al, 'A'
+	cmp		al, 'C'
+	ja		.Return
+	mov		al, 'C'
+ALIGN JUMP_ALIGN, ret
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; BootMenu_GetMenuitemToDXforDriveInDL
+;	Parameters:
+;		DL:		Drive number
+;	Returns:
+;		DX:		Menuitem index (assuming drive is available)
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_GetMenuitemToDXforDriveInDL:
+	xor		dh, dh						; Drive number now in DX
+	test	dl, dl
+	jns		SHORT .ReturnItemIndexInDX	; Return if floppy drive (HD bit not set)
+	call	FloppyDrive_GetCountToAX
+	and		dl, ~80h					; Clear HD bit
+	add		dx, ax
+.ReturnItemIndexInDX:
+	ret
+
+
+;--------------------------------------------------------------------
+; Checks is drive number valid for this system.
+;
+; BootMenu_IsDriveInSystem
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		CF:		Set if drive number is valid
+;				Clear if drive is not present in system
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenu_IsDriveInSystem:
+	test	dl, dl								; Floppy drive?
+	jns		SHORT .IsFloppyDriveInSystem
+	call	RamVars_GetHardDiskCountFromBDAtoAX	; Hard Disk count to AX
+	or		al, 80h								; Set Hard Disk bit to AX
+	jmp		SHORT .CompareDriveNumberToDriveCount
+.IsFloppyDriveInSystem:
+	call	FloppyDrive_GetCountToAX
+.CompareDriveNumberToDriveCount:
+	cmp		dl, al								; Set CF when DL is smaller
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuEvent.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuEvent.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuEvent.asm	(revision 352)
@@ -0,0 +1,156 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Boot Menu event handler for menu library callbacks.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; BootMenuEvent_Handler
+;	Common parameters for all events:
+;		BX:			Menu event (anything from MENUEVENT struct)
+;		SS:BP:		Menu library handle
+;	Common return values for all events:
+;		CF:			Set if event processed
+;					Cleared if event not processed
+;	Corrupts registers:
+;		All
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuEvent_Handler:
+
+%ifdef MENUEVENT_INLINE_OFFSETS
+
+	add		bx, BootMenuEvent_Handler.FirstEvent
+	jmp		bx
+
+MENUEVENT_InitializeMenuinitFromDSSI equ  (BootMenuEvent_Handler.InitializeMenuinitFromDSSI - BootMenuEvent_Handler.FirstEvent)
+MENUEVENT_ExitMenu equ  (BootMenuEvent_EventCompleted - BootMenuEvent_Handler.FirstEvent)
+MENUEVENT_ItemHighlightedFromCX equ (BootMenuEvent_Handler.ItemHighlightedFromCX - BootMenuEvent_Handler.FirstEvent)
+MENUEVENT_ItemSelectedFromCX equ (BootMenuEvent_Handler.ItemSelectedFromCX - BootMenuEvent_Handler.FirstEvent)
+MENUEVENT_KeyStrokeInAX equ (BootMenuEvent_Handler.KeyStrokeInAX - BootMenuEvent_Handler.FirstEvent)
+MENUEVENT_RefreshTitle equ (BootMenuPrint_TitleStrings - BootMenuEvent_Handler.FirstEvent)
+MENUEVENT_RefreshInformation equ (BootMenuPrint_RefreshInformation - BootMenuEvent_Handler.FirstEvent)
+MENUEVENT_RefreshItemFromCX equ (BootMenuPrint_RefreshItem - BootMenuEvent_Handler.FirstEvent)
+;
+; Note that there is no entry for MENUEVENT_IdleProcessing.  If MENUEVENT_IDLEPROCESSING_ENABLE is not %defined,
+; then the entry point will not be called (saving memory on this end and at the CALL point).
+;
+
+%else
+
+	cmp		bx, BYTE MENUEVENT.RefreshItemFromCX	; Above last supported item?
+	ja		SHORT .EventNotHandled
+	jmp		[cs:bx+.rgfnEventSpecificHandlers]
+
+.EventNotHandled:
+	clc
+	ret
+
+ALIGN WORD_ALIGN
+.rgfnEventSpecificHandlers:
+	dw		.InitializeMenuinitFromDSSI			; MENUEVENT.InitializeMenuinitFromDSSI
+	dw		BootMenuEvent_EventCompleted		; MENUEVENT.ExitMenu
+	dw		.EventNotHandled					; MENUEVENT.IdleProcessing
+	dw		.ItemHighlightedFromCX				; MENUEVENT.ItemHighlightedFromCX
+	dw		.ItemSelectedFromCX					; MENUEVENT.ItemSelectedFromCX
+	dw		.KeyStrokeInAX						; MENUEVENT.KeyStrokeInAX
+	dw		BootMenuPrint_TitleStrings			; MENUEVENT.RefreshTitle
+	dw		BootMenuPrint_RefreshInformation	; MENUEVENT.RefreshInformation
+	dw		BootMenuPrint_RefreshItem			; MENUEVENT.RefreshItemFromCX
+
+%endif
+
+
+; Parameters:
+;	DS:SI:		Ptr to MENUINIT struct to initialize
+; Returns:
+;	DS:SI:		Ptr to initialized MENUINIT struct
+ALIGN JUMP_ALIGN
+.FirstEvent:	
+.InitializeMenuinitFromDSSI:
+	push	ds
+	call	RamVars_GetSegmentToDS
+	call	.GetDefaultMenuitemToDX
+	call	BootMenu_GetMenuitemCountToAX
+	pop		ds
+	mov		[si+MENUINIT.wItems], ax
+	mov		[si+MENUINIT.wHighlightedItem], dx
+	mov		WORD [si+MENUINIT.wTitleAndInfoLines], BOOT_MENU_TITLE_AND_INFO_LINES
+	mov		BYTE [si+MENUINIT.bWidth], BOOT_MENU_WIDTH
+	call	BootMenu_GetHeightToAHwithItemCountInAL
+	mov		[si+MENUINIT.bHeight], ah
+	mov		ax, [cs:ROMVARS.wBootTimeout]
+	CALL_MENU_LIBRARY StartSelectionTimeoutWithTicksInAX
+	stc
+	ret
+
+ALIGN JUMP_ALIGN
+.GetDefaultMenuitemToDX:
+	mov		dl, [cs:ROMVARS.bBootDrv]	; Default boot drive
+	call	BootMenu_IsDriveInSystem
+	jnc		SHORT .DoNotSetDefaultMenuitem
+	call	DriveXlate_SetDriveToSwap
+	jmp		BootMenu_GetMenuitemToDXforDriveInDL
+ALIGN JUMP_ALIGN
+.DoNotSetDefaultMenuitem:
+	xor		dx, dx						; Whatever appears first on boot menu
+	ret
+
+
+; Parameters:
+;	CX:			Index of new highlighted item
+;	DX:			Index of previously highlighted item or NO_ITEM_HIGHLIGHTED
+ALIGN JUMP_ALIGN
+.ItemHighlightedFromCX:
+	push	cx
+	call	BootMenu_GetDriveToDXforMenuitemInCX_And_RamVars_GetSegmentToDS		
+	call	DriveXlate_Reset
+	call	DriveXlate_SetDriveToSwap
+
+	xor		ax, ax	; Update first floppy drive (for translated drive number)
+	CALL_MENU_LIBRARY RefreshItemFromAX
+	mov		dl, 80h
+	call	BootMenu_GetMenuitemToDXforDriveInDL
+	xchg	ax, dx	; Update first hard disk (for translated drive number)
+	CALL_MENU_LIBRARY RefreshItemFromAX
+	pop		ax		; Update new item (for translated drive number)
+	CALL_MENU_LIBRARY RefreshItemFromAX
+	CALL_MENU_LIBRARY RefreshInformation
+	stc
+	ret
+
+
+; Parameters:
+;	AL:			ASCII character for the key
+;	AH:			Keyboard library scan code for the key
+ALIGN JUMP_ALIGN
+.KeyStrokeInAX:
+	cmp		ah, ROM_BOOT_HOTKEY_SCANCODE
+	jne		SHORT .CheckDriveHotkeys
+	;; NOTE: carry flag will be clear after compare above that resulted in zero
+	jmp		Int19hMenu_JumpToBootSector_or_RomBoot   	
+ALIGN JUMP_ALIGN
+.CheckDriveHotkeys:
+	call	BootMenu_GetMenuitemToAXforAsciiHotkeyInAL
+	cmp		ax, [bp+MENUINIT.wItems]
+	jae		SHORT BootMenuEvent_EventCompleted	; Invalid key
+
+	; Highlighting new item resets drive translation and we do not want that.
+	; We must be able to translate both floppy drive and hard drive when using hotkey.
+	call	RamVars_GetSegmentToDS	
+	mov		dx, [RAMVARS.xlateVars+XLATEVARS.wFDandHDswap]
+	CALL_MENU_LIBRARY HighlightItemFromAX
+	or		[RAMVARS.xlateVars+XLATEVARS.wFDandHDswap], dx
+	; Fall to .ItemSelectedFromCX
+
+
+; Parameters:
+;	CX:			Index of selected item
+ALIGN JUMP_ALIGN
+.ItemSelectedFromCX:
+	CALL_MENU_LIBRARY Close
+
+BootMenuEvent_EventCompleted:
+	stc
+	ret
+
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuInfo.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuInfo.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuInfo.asm	(revision 352)
@@ -0,0 +1,85 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for generating and accessing drive
+;					information to be displayed on boot menu.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Creates new BOOTMENUINFO struct for detected hard disk.
+;
+; BootMenuInfo_CreateForHardDisk
+;	Parameters:
+;		DL:		Drive number
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		ES:BX:	Ptr to BOOTMENUINFO (if successful)
+;	Corrupts registers:
+;		AX, BX, CX, DX, DI
+;--------------------------------------------------------------------
+BootMenuInfo_CreateForHardDisk:
+	call	BootMenuInfo_ConvertDPTtoBX			; ES:BX now points to new BOOTMENUINFO
+
+	; Store Drive Name
+	push	ds									; Preserve RAMVARS
+	push	si
+
+	push	es									; ES copied to DS
+	pop		ds
+
+	add		si, BYTE ATA1.strModel				; DS:SI now points drive name
+	lea		di, [bx+BOOTMENUINFO.szDrvName]		; ES:DI now points to name destination
+	mov		cx, MAX_HARD_DISK_NAME_LENGTH / 2	; Max number of WORDs allowed
+.CopyNextWord:
+	lodsw
+	xchg	al, ah								; Change endianness
+	stosw
+	loop	.CopyNextWord
+	xor		ax, ax								; Zero AX and clear CF
+	stosw										; Terminate with NULL
+
+	pop		si
+	pop		ds
+		
+	ret
+
+
+;--------------------------------------------------------------------
+; BootMenuInfo_GetTotalSectorCount
+;	Parameters:
+;		DS:DI:		DPT Pointer
+;	Returns:
+;		BX:DX:AX:	48-bit sector count
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuInfo_GetTotalSectorCount:
+	test	BYTE [di+DPT.bFlagsLow], FLG_DRVNHEAD_LBA
+	jnz		SHORT .ReturnFullCapacity
+	jmp		AH15h_GetSectorCountToBXDXAX
+.ReturnFullCapacity:
+	jmp		AccessDPT_GetLbaSectorCountToBXDXAX
+
+
+;--------------------------------------------------------------------
+; Returns offset to BOOTMENUINFO based on DPT pointer.
+;
+; BootMenuInfo_ConvertDPTtoBX
+;	Parameters:
+;		DS:DI:	DPT Pointer
+;	Returns:
+;		BX:		Offset to BOOTMENUINFO struct
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuInfo_ConvertDPTtoBX:
+	mov		ax, di
+	sub		ax, RAMVARS_size						; subtract off base of DPTs
+	mov		bl, DPT_BOOTMENUINFO_SIZE_MULTIPLIER	; BOOTMENUINFO's are a whole number multiple of DPT size
+	mul		bl								
+	add		ax, BOOTVARS.rgBootNfo					; add base of BOOTMENUINFO
+	xchg	ax, bx
+	ret			
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuPrint.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuPrint.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuPrint.asm	(revision 352)
@@ -0,0 +1,394 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for printing boot menu strings.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; BootMenuPrint_RefreshItem
+;
+;	Parameters:
+;		DL:		Untranslated Floppy Drive number
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_RefreshItem:
+	call	BootMenu_GetDriveToDXforMenuitemInCX_And_RamVars_GetSegmentToDS
+	jnc		BootMenuEvent_EventCompleted			; if no menu item selected, out we go
+
+	push	bp
+	mov		bp, sp
+
+	call	FindDPT_ForDriveNumberInDL
+	jc		.notOurs
+
+	call	BootMenuInfo_ConvertDPTtoBX
+	mov		si, g_szDriveNumBOOTNFO					; special g_szDriveNum that prints from BDA
+	jmp		.go
+
+.notOurs:
+	mov		si,g_szDriveNum
+	mov		bx,g_szForeignHD						; assume a hard disk for the moment
+
+	test	dl, dl
+	js		.go
+	mov		bl,((g_szFloppyDrv)-$$ & 0xff)			; and revisit the earlier assumption...
+
+.go:
+	mov		ax, dx									; preserve DL for the floppy drive letter addition
+	call	DriveXlate_ToOrBack
+	push	dx										; translated drive number
+	push	bx										; sub string
+	add		al, 'A'									; floppy drive letter (we always push this although
+	push	ax										; the hard disks don't ever use it, but it does no harm)
+
+	jmp		short BootMenuPrint_RefreshInformation.FormatRelay
+
+;--------------------------------------------------------------------
+; Prints Boot Menu title strings.
+;
+; BootMenuPrint_TitleStrings
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CF:		Set since menu event handled
+;	Corrupts registers:
+;		AX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_TitleStrings:
+	mov		si, ROMVARS.szTitle
+	call	BootMenuPrint_NullTerminatedStringFromCSSIandSetCF
+	CALL_DISPLAY_LIBRARY PrintNewlineCharacters
+	mov		si, ROMVARS.szVersion
+	; Fall to BootMenuPrint_NullTerminatedStringFromCSSIandSetCF
+
+;--------------------------------------------------------------------
+; BootMenuPrint_NullTerminatedStringFromCSSIandSetCF
+;	Parameters:
+;		CS:SI:	Ptr to NULL terminated string to print
+;	Returns:
+;		CF:		Set since menu event was handled successfully
+;	Corrupts registers:
+;		AX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_NullTerminatedStringFromCSSIandSetCF:
+;
+; We send all CSSI strings through the Format routine for the case of
+; compressed strings, but this doesn't hurt in the non-compressed case either
+; (perhaps a little slower, but shouldn't be noticeable to the user)
+; and results in smaller code size.
+;
+	push	bp
+	mov		bp,sp
+	jmp		short BootMenuPrint_RefreshInformation.FormatRelay
+
+
+;--------------------------------------------------------------------
+; BootMenuPrint_FloppyMenuitemInformation
+;	Parameters:
+;		DL:		Untranslated Floppy Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		CF:		Set since menu event was handled successfully
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI, DI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_RefreshInformation:
+	CALL_MENU_LIBRARY ClearInformationArea
+
+	call	BootMenu_GetDriveToDXforMenuitemInCX_And_RamVars_GetSegmentToDS
+	jnc		BootMenuEvent_EventCompleted				; if no menu selection, abort
+
+	push	bp
+	mov		bp, sp
+
+	mov		si, g_szCapacity							; Setup print string now, carries through to print call
+
+	call	FindDPT_ForDriveNumberInDL
+
+	inc		dl											; are we a hard disk?
+	dec		dl											; inc/dec will set SF, without modifying CF or DL
+	js		.HardDiskRefreshInformation
+
+	jnc		.ours										; Based on CF from FindDPT_ForDriveNumberInDL above
+	call	FloppyDrive_GetType							; Get Floppy Drive type to BX
+	jmp		.around
+.ours:
+	call	AH8h_GetDriveParameters
+.around:
+
+	mov		ax, g_szFddSizeOr	        				; .PrintXTFloppyType
+	test	bl, bl										; Two possibilities? (FLOPPY_TYPE_525_OR_35_DD)
+	jz		SHORT .PushAXAndOutput
+
+	mov		al, (g_szFddUnknown - $$) & 0xff	        ; .PrintUnknownFloppyType
+	cmp		bl, FLOPPY_TYPE_35_ED
+	ja		SHORT .PushAXAndOutput
+
+	; Fall to .PrintKnownFloppyType
+
+;--------------------------------------------------------------------
+; .PrintKnownFloppyType
+;	Parameters:
+;		BX:		Floppy drive type
+;	Returns:
+;		CF:		Set since menu event was handled successfully
+;	Corrupts registers:
+;		AX, BX, SI, DI
+;
+; Floppy Drive Types:
+;
+;   0  Handled above
+;   1  FLOPPY_TYPE_525_DD          5 1/4   360K
+;   2  FLOPPY_TYPE_525_HD          5 1/4   1.2M
+;   3  FLOPPY_TYPE_35_DD           3 1/2   720K
+;   4  FLOPPY_TYPE_35_HD           3 1/2   1.44M
+;   5  3.5" ED on some BIOSes      3 1/2   2.88M
+;   6  FLOPPY_TYPE_35_ED		   3 1/2   2.88M
+;   >6 Unknwon, handled above
+;
+;--------------------------------------------------------------------
+.PrintKnownFloppyType:
+	mov		al, (g_szFddSize - $$) & 0xff
+	push	ax
+
+	mov		al, (g_szFddThreeHalf - $$) & 0xff
+	cmp		bl, FLOPPY_TYPE_525_HD
+	ja		.ThreeHalf
+	mov		al, (g_szFddFiveQuarter - $$) & 0xff
+.ThreeHalf:
+	push	ax											; "5 1/4" or "3 1/2"
+
+	mov		al,FloppyTypes.rgbCapacityMultiplier
+	mov		bh, 0
+	mul		byte [cs:bx+FloppyTypes.rgbCapacity - 1]    ; -1 since 0 is handled above and not in the table
+
+.PushAXAndOutput:
+	push	ax
+
+.FormatRelay:
+	jmp		short BootMenuPrint_FormatCSSIfromParamsInSSBP
+
+
+;--------------------------------------------------------------------
+; Prints Hard Disk Menuitem information strings.
+;
+; BootMenuPrint_HardDiskMenuitemInformation
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		CF:		Set since menu event was handled successfully
+;	Corrupts registers:
+;		BX, CX, DX, SI, DI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.HardDiskRefreshInformation:
+	jc		.HardDiskMenuitemInfoForForeignDrive		; Based on CF from FindDPT_ForDriveNumberInDL (way) above
+
+.HardDiskMenuitemInfoForOurDrive:
+	ePUSH_T ax, g_szInformation							; Add substring for our hard disk information
+	call	BootMenuInfo_GetTotalSectorCount			; Get Total LBA Size
+	jmp		.ConvertSectorCountInBXDXAXtoSizeAndPushForFormat
+
+.HardDiskMenuitemInfoForForeignDrive:
+	call	DriveXlate_ToOrBack
+	call	AH15h_GetSectorCountFromForeignDriveToDXAX
+
+.ConvertSectorCountInBXDXAXtoSizeAndPushForFormat:
+	ePUSH_T	cx, g_szCapacityNum		; Push format substring
+	call	Size_ConvertSectorCountInBXDXAXtoKiB
+	mov		cx, BYTE_MULTIPLES.kiB
+	call	Size_GetSizeToAXAndCharToDLfromBXDXAXwithMagnitudeInCX
+	push	ax						; Size in magnitude
+	push	cx						; Tenths
+	push	dx						; Magnitude character
+
+	test	di,di
+	jz		short BootMenuPrint_FormatCSSIfromParamsInSSBP
+
+%include "BootMenuPrintCfg.asm"			; inline of code to fill out remainder of information string
+
+;;; fall-through to BootMenuPrint_FormatCSSIfromParamsInSSBP
+
+
+;--------------------------------------------------------------------
+; BootMenuPrint_FormatCSSIfromParamsInSSBP
+;	Parameters:
+;		CS:SI:	Ptr to string to format
+;		BP:		SP before pushing parameters
+;	Returns:
+;		BP:		Popped from stack
+;		CF:		Set since menu event was handled successfully
+;	Corrupts registers:
+;		AX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_FormatCSSIfromParamsInSSBP:
+	CALL_DISPLAY_LIBRARY FormatNullTerminatedStringFromCSSI
+	stc				; Successful return from menu event
+	pop		bp
+	ret
+
+
+;--------------------------------------------------------------------
+; BootMenuPrint_ClearScreen
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_ClearScreen:
+	call	BootMenuPrint_InitializeDisplayContext
+	xor		ax, ax
+	CALL_DISPLAY_LIBRARY SetCursorCoordinatesFromAX
+	mov		ax, ' ' | (MONO_NORMAL<<8)
+	CALL_DISPLAY_LIBRARY ClearScreenWithCharInALandAttrInAH
+	ret
+
+
+;--------------------------------------------------------------------
+; BootMenuPrint_TheBottomOfScreen
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_TheBottomOfScreen:
+	call	FloppyDrive_GetCountToAX
+	xchg	bx, ax					; Floppy Drive count to BL
+	call	RamVars_GetHardDiskCountFromBDAtoAX
+	mov		bh, al					; Hard Disk count to BH
+	; Fall to .MoveCursorToHotkeyStrings
+
+;--------------------------------------------------------------------
+; .MoveCursorToHotkeyStrings
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DI
+;--------------------------------------------------------------------
+.MoveCursorToHotkeyStrings:
+	CALL_DISPLAY_LIBRARY GetColumnsToALandRowsToAH
+	xor		al, al
+	dec		ah
+	CALL_DISPLAY_LIBRARY SetCursorCoordinatesFromAX
+	; Fall to .PrintHotkeyString
+
+;--------------------------------------------------------------------
+; .PrintHotkeyString
+;	Parameters:
+;		BL:		Floppy Drives
+;		BH:		Hard Drives
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+.PrintHotkeyString:
+	; Display Library should not be called like this
+	mov		si, ATTRIBUTE_CHARS.cHighlightedItem
+	call	MenuAttribute_GetToAXfromTypeInSI
+	xchg	dx, ax
+	mov		cx, MONO_BRIGHT
+
+	test	bl, bl		; Any Floppy Drives?
+	jz		SHORT .SkipFloppyDriveHotkeys
+	mov		ax, 'A' | (ANGLE_QUOTE_RIGHT<<8)
+	mov		si, g_szFDD
+	call	PushHotkeyParamsAndFormat
+
+.SkipFloppyDriveHotkeys:
+	test	bh, bh		; Any Hard Drives?
+	jz		SHORT .SkipHardDriveHotkeys
+	call	BootMenu_GetLetterForFirstHardDiskToAL
+	mov		ah, ANGLE_QUOTE_RIGHT
+	mov		si, g_szHDD
+	call	PushHotkeyParamsAndFormat
+
+.SkipHardDriveHotkeys:
+	; Fall to .PrintRomBootHotkey
+
+;--------------------------------------------------------------------
+; .PrintRomBootHotkey
+;	Parameters:
+;		CX:		Key Attribute
+;		DX:		Description Attribute
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, SI, DI
+;--------------------------------------------------------------------
+.PrintRomBootHotkey:
+	mov		ax, 'F' | ('8'<<8)		; F8
+	mov		si, g_szRomBoot
+	; Fall to PushHotkeyParamsAndFormat
+
+;--------------------------------------------------------------------
+; PushHotkeyParamsAndFormat
+;	Parameters:
+;		AL:		First character
+;		AH:		Second character
+;		CX:		Key Attribute
+;		DX:		Description Attribute
+;		CS:SI:	Description string
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+PushHotkeyParamsAndFormat:
+	push	bp
+	mov		bp, sp
+
+	push	cx			; Key attribute
+	push	ax			; First character
+	xchg	al, ah
+	push	ax			; Second character
+	push	dx			; Description attribute
+	push	si			; Description string
+	push	cx			; Key attribute for last space
+	mov		si, g_szHotkey
+
+BootMenuPrint_FormatCSSIfromParamsInSSBP_Relay:
+	jmp		SHORT BootMenuPrint_FormatCSSIfromParamsInSSBP
+
+
+;--------------------------------------------------------------------
+; BootMenuPrint_InitializeDisplayContext
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootMenuPrint_InitializeDisplayContext:
+	CALL_DISPLAY_LIBRARY InitializeDisplayContext
+	ret
+
+
+FloppyTypes:
+.rgbCapacityMultiplier equ 20	        ; Multiplier to reduce word sized values to byte size
+.rgbCapacity:
+	db		360   / FloppyTypes.rgbCapacityMultiplier    ;  type 1
+	db		1200  / FloppyTypes.rgbCapacityMultiplier    ;  type 2
+	db		720   / FloppyTypes.rgbCapacityMultiplier    ;  type 3
+	db		1440  / FloppyTypes.rgbCapacityMultiplier    ;  type 4
+	db		2880  / FloppyTypes.rgbCapacityMultiplier    ;  type 5
+	db		2880  / FloppyTypes.rgbCapacityMultiplier    ;  type 6
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuPrintCfg.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuPrintCfg.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootMenuPrintCfg.asm	(revision 352)
@@ -0,0 +1,120 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for printing drive configuration
+;					information on Boot Menu.
+;
+; Included by BootMenuPrint.asm, this routine is to be inserted into
+; BootMenuPrint_HardDiskRefreshInformation.
+;
+; Section containing code
+SECTION .text
+
+;;; fall-into from BootMenuPrint_HardDiskRefreshInformation.
+
+;--------------------------------------------------------------------
+; Prints Hard Disk configuration for drive handled by our BIOS.
+; Cursor is set to configuration header string position.
+;
+; BootMenuPrintCfg_ForOurDrive
+;	Parameters:
+;		DS:DI:		Pointer to DPT
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+.BootMenuPrintCfg_ForOurDrive:
+	eMOVZX	ax, [di+DPT.bIdevarsOffset]
+	xchg	bx, ax						; CS:BX now points to IDEVARS
+	; Fall to .PushAndFormatCfgString
+
+;--------------------------------------------------------------------
+; PushAddressingMode
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		CS:BX:	Ptr to IDEVARS
+;	Returns:
+;		Nothing (jumps to next push below)
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+.PushAddressingMode:
+	AccessDPT_GetUnshiftedAddressModeToALZF
+	;;
+	;; This multiply both shifts the addressing mode bits down to low order bits, and
+	;; at the same time multiplies by the size of the string displacement.  The result is in AH,
+	;; with AL clear, and so we exchange AL and AH after the multiply for the final result.
+	;;
+	mov		cl,(1<<(8-ADDRESSING_MODE_FIELD_POSITION)) * g_szAddressingModes_Displacement
+	mul		cl
+	xchg	al,ah
+	add		ax,g_szAddressingModes
+	push	ax
+
+;--------------------------------------------------------------------
+; PushBlockMode
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		CS:BX:	Ptr to IDEVARS
+;	Returns:
+;		Nothing (falls to next push below)
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+.PushBlockMode:
+	mov		ax, 1
+	test	BYTE [di+DPT.bFlagsHigh], FLGH_DPT_BLOCK_MODE_SUPPORTED
+	jz		SHORT .PushBlockSizeFromAX
+	mov		al, [di+DPT_ATA.bSetBlock]
+.PushBlockSizeFromAX:
+	push	ax
+
+;--------------------------------------------------------------------
+; PushBusType
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		CS:BX:	Ptr to IDEVARS
+;	Returns:
+;		Nothing (jumps to next push below)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+.PushBusType:
+	mov		al,g_szBusTypeValues_Displacement
+	mul		BYTE [cs:bx+IDEVARS.bDevice]
+
+	shr		ax,1			; divide by 2 since IDEVARS.bDevice is multiplied by 2
+
+	add		ax,g_szBusTypeValues
+	push	ax
+
+;--------------------------------------------------------------------
+; PushIRQ
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		CS:BX:	Ptr to IDEVARS
+;	Returns:
+;		Nothing (falls to next push below)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+.PushIRQ:
+	mov		al, [cs:bx+IDEVARS.bIRQ]
+	cbw
+	push	ax
+
+;--------------------------------------------------------------------
+; PushResetStatus
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		CS:BX:	Ptr to IDEVARS
+;	Returns:
+;		Nothing (falls to next push below)
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+.PushResetStatus:
+	mov		al, [di+DPT.bFlagsHigh]
+	and		al, MASKH_DPT_RESET			;  ah already zero from last push
+	push	ax
+
+;;; fall-out to BootMenuPrint_HardDiskRefreshInformation.
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootPrint.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootPrint.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootPrint.asm	(revision 352)
@@ -0,0 +1,58 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for printing boot related strings.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; BootPrint_FailedToLoadFirstSector
+;	Parameters:
+;		AH:		INT 13h error code
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootPrint_FailedToLoadFirstSector:
+	push	bp
+	mov		bp, sp
+	eMOVZX	cx, ah
+	push	cx					; Push INT 13h error code
+	mov		si, g_szReadError
+		
+	jmp		short BootMenuPrint_FormatCSSIfromParamsInSSBP_Relay
+		
+
+;--------------------------------------------------------------------
+; BootPrint_TryToBootFromDL
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, SI, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootPrint_TryToBootFromDL:
+	push	bp
+	mov		bp, sp
+
+	mov		ax, g_szHDD
+	test	dl, dl
+	js		SHORT .NotFDD
+	mov		ax, g_szFDD
+.NotFDD:
+	push	ax
+
+	call	DriveXlate_ToOrBack
+	push	dx					; Push untranslated drive number
+	call	DriveXlate_ToOrBack
+	push	dx					; Push translated drive number
+
+	mov		si, g_szTryToBoot
+	jmp		short BootMenuPrint_FormatCSSIfromParamsInSSBP_Relay		
+
+
+
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootSector.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootSector.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Boot/BootSector.asm	(revision 352)
@@ -0,0 +1,109 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Reading and jumping to boot sector.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; BootSector_TryToLoadFromDriveDL
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;		DS:		RAMVARS segment
+;	Returns:
+;		ES:BX:	Ptr to boot sector (if successful)
+;		CF:		Set if boot sector loaded successfully
+;				Cleared if failed to load boot sector
+;	Corrupts registers:
+;		AX, CX, DH, SI, DI, (DL if failed to read boot sector)
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+BootSector_TryToLoadFromDriveDL:
+	call	BootPrint_TryToBootFromDL
+	call	LoadFirstSectorFromDriveDL
+	jc		SHORT .FailedToLoadFirstSector
+
+	test	dl, dl
+	jns		SHORT .AlwaysBootFromFloppyDriveForBooterGames
+	cmp		WORD [es:bx+510], 0AA55h		; Valid boot sector?
+	jne		SHORT .FirstHardDiskSectorNotBootable
+.AlwaysBootFromFloppyDriveForBooterGames:
+	stc
+	ret
+.FailedToLoadFirstSector:
+	call	BootPrint_FailedToLoadFirstSector
+	clc
+	ret
+.FirstHardDiskSectorNotBootable:
+	mov		si, g_szBootSectorNotFound
+	call	BootMenuPrint_NullTerminatedStringFromCSSIandSetCF
+	clc
+	ret
+
+;--------------------------------------------------------------------
+; LoadFirstSectorFromDriveDL
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;	Returns:
+;		AH:		INT 13h error code
+;		ES:BX:	Ptr to boot sector (if successful)
+;		CF:		Cleared if read successful
+;				Set if any error
+;	Corrupts registers:
+;		AL, CX, DH, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+LoadFirstSectorFromDriveDL:
+	LOAD_BDA_SEGMENT_TO	es, bx				; ES:BX now points to...
+	mov		bx, BOOTVARS.rgbBootSect		; ...boot sector location
+	mov		di, BOOT_READ_RETRY_TIMES		; Initialize retry counter
+ALIGN JUMP_ALIGN
+.ReadRetryLoop:
+	call	.ResetBootDriveFromDL
+	call	.LoadFirstSectorFromDLtoESBX
+	jnc		SHORT .Return
+	dec		di								; Decrement retry counter
+	jnz		SHORT .ReadRetryLoop			; Loop while retries left
+.Return:
+	ret
+
+;--------------------------------------------------------------------
+; .ResetBootDriveFromDL
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;	Returns:
+;		AH:		INT 13h error code
+;		CF:		Cleared if read successful
+;				Set if any error
+;	Corrupts registers:
+;		AL
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.ResetBootDriveFromDL:
+	xor		ax, ax							; AH=0h, Disk Controller Reset
+	test	dl, dl							; Floppy drive?
+	jns		SHORT .SkipAltReset
+	mov		ah, 0Dh							; AH=Dh, Reset Hard Disk (Alternate reset)
+.SkipAltReset:
+	int		BIOS_DISK_INTERRUPT_13h
+	ret
+
+;--------------------------------------------------------------------
+; .LoadFirstSectorFromDLtoESBX
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;		ES:BX:	Destination buffer for boot sector
+;	Returns:
+;		AH:		INT 13h error code
+;		ES:BX:	Ptr to boot sector
+;		CF:		Cleared if read successful
+;				Set if any error
+;	Corrupts registers:
+;		AL, CX, DH
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.LoadFirstSectorFromDLtoESBX:
+	mov		ax, 0201h						; Read 1 sector
+	mov		cx, 1							; Cylinder 0, Sector 1
+	xor		dh, dh							; Head 0
+	int		BIOS_DISK_INTERRUPT_13h
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Device.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Device.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Device.asm	(revision 352)
@@ -0,0 +1,230 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Command and port direction functions for different device types.
+
+; Section containing code
+SECTION .text
+
+
+%macro TEST_USING_DPT_AND_JUMP_IF_SERIAL_DEVICE 1
+	test	BYTE [di+DPT.bFlagsHigh], FLGH_DPT_SERIAL_DEVICE
+	jnz		SHORT %1
+%endmacro
+
+%macro CMP_USING_DPT_AND_JUMP_IF_JRIDE_DEVICE 1
+	xchg	ax, bx
+	eMOVZX	bx, [di+DPT.bIdevarsOffset]
+	cmp		BYTE [cs:bx+IDEVARS.bDevice], DEVICE_JRIDE_ISA
+	xchg	bx, ax				; Restore BX
+	je		SHORT %1
+%endmacro
+
+%macro CMP_USING_IDEVARS_IN_CSBP_AND_JUMP_IF 2
+	cmp		BYTE [cs:bp+IDEVARS.bDevice], %1
+	je		SHORT %2
+%endmacro
+
+
+
+;--------------------------------------------------------------------
+; Device_FinalizeDPT
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+%ifdef MODULE_SERIAL
+Device_FinalizeDPT:
+	; needs to check IDEVARS vs. checking the DPT as the serial bit in the DPT is set in the Finalize routine
+	CMP_USING_IDEVARS_IN_CSBP_AND_JUMP_IF DEVICE_SERIAL_PORT, .FinalizeDptForSerialPortDevice
+	jmp		IdeDPT_Finalize
+.FinalizeDptForSerialPortDevice:
+	jmp		SerialDPT_Finalize
+
+%else	; IDE or JR-IDE/ISA
+	Device_FinalizeDPT EQU IdeDPT_Finalize
+%endif
+
+
+;--------------------------------------------------------------------
+; Device_ResetMasterAndSlaveController
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+%ifdef MODULE_JRIDE
+	%ifdef MODULE_SERIAL				; IDE + JR-IDE/ISA + Serial
+	Device_ResetMasterAndSlaveController:
+		TEST_USING_DPT_AND_JUMP_IF_SERIAL_DEVICE ReturnSuccessForSerialPort
+		CMP_USING_DPT_AND_JUMP_IF_JRIDE_DEVICE .ResetJrIDE
+		jmp		IdeCommand_ResetMasterAndSlaveController
+
+	%else								; IDE + JR-IDE/ISA
+	Device_ResetMasterAndSlaveController:
+		CMP_USING_DPT_AND_JUMP_IF_JRIDE_DEVICE .ResetJrIDE
+		jmp		IdeCommand_ResetMasterAndSlaveController
+	%endif
+
+%elifdef MODULE_SERIAL					; IDE + Serial
+Device_ResetMasterAndSlaveController:
+	TEST_USING_DPT_AND_JUMP_IF_SERIAL_DEVICE ReturnSuccessForSerialPort
+	jmp		IdeCommand_ResetMasterAndSlaveController
+
+%else									; IDE
+	Device_ResetMasterAndSlaveController EQU IdeCommand_ResetMasterAndSlaveController
+%endif
+
+%ifdef MODULE_JRIDE
+.ResetJrIDE:
+	jmp		MemIdeCommand_ResetMasterAndSlaveController
+%endif
+
+
+;--------------------------------------------------------------------
+; Device_IdentifyToBufferInESSIwithDriveSelectByteInBH
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Select Register
+;		DS:		Segment to RAMVARS
+;		ES:SI:	Ptr to normalized buffer to receive 512-byte IDE Information
+;		CS:BP:	Ptr to IDEVARS
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BL, CX, DX, SI, DI, ES
+;--------------------------------------------------------------------
+%ifdef MODULE_JRIDE
+	%ifdef MODULE_SERIAL				; IDE + JR-IDE/ISA + Serial
+	Device_IdentifyToBufferInESSIwithDriveSelectByteInBH:
+		CMP_USING_IDEVARS_IN_CSBP_AND_JUMP_IF DEVICE_SERIAL_PORT, .IdentifyDriveFromSerialPort
+		CMP_USING_IDEVARS_IN_CSBP_AND_JUMP_IF DEVICE_JRIDE_ISA, .IdentifyDriveFromJrIde
+		jmp		IdeCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH
+
+	%else								; IDE + JR-IDE/ISA
+	Device_IdentifyToBufferInESSIwithDriveSelectByteInBH:
+		CMP_USING_IDEVARS_IN_CSBP_AND_JUMP_IF DEVICE_JRIDE_ISA, .IdentifyDriveFromJrIde
+		jmp		IdeCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH
+	%endif
+
+%elifdef MODULE_SERIAL					; IDE + Serial
+Device_IdentifyToBufferInESSIwithDriveSelectByteInBH:
+	CMP_USING_IDEVARS_IN_CSBP_AND_JUMP_IF DEVICE_SERIAL_PORT, .IdentifyDriveFromSerialPort
+	jmp		IdeCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH
+
+%else									; IDE
+	Device_IdentifyToBufferInESSIwithDriveSelectByteInBH EQU IdeCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH
+%endif
+
+%ifdef MODULE_JRIDE
+.IdentifyDriveFromJrIde:
+	jmp		MemIdeCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH
+%endif
+
+%ifdef MODULE_SERIAL
+.IdentifyDriveFromSerialPort:
+	jmp		SerialCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH
+%endif
+
+
+;--------------------------------------------------------------------
+; Device_OutputCommandWithParameters
+;	Parameters:
+;		BH:		Default system timer ticks for timeout (can be ignored)
+;		BL:		IDE Status Register bit to poll after command
+;		ES:SI:	Ptr to normalized buffer (for data transfer commands)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CX:		Number of successfully transferred sectors (for transfer commands)
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, (CX), DX, (ES:SI for data transfer commands)
+;--------------------------------------------------------------------
+%ifdef MODULE_JRIDE
+	%ifdef MODULE_SERIAL				; IDE + JR-IDE/ISA + Serial
+	Device_OutputCommandWithParameters:
+		TEST_USING_DPT_AND_JUMP_IF_SERIAL_DEVICE .OutputCommandToSerialPort
+		CMP_USING_DPT_AND_JUMP_IF_JRIDE_DEVICE .OutputCommandToJrIDE
+		jmp		IdeCommand_OutputWithParameters
+
+	%else								; IDE + JR-IDE/ISA
+	Device_OutputCommandWithParameters:
+		CMP_USING_DPT_AND_JUMP_IF_JRIDE_DEVICE .OutputCommandToJrIDE
+		jmp		IdeCommand_OutputWithParameters
+	%endif
+
+%elifdef MODULE_SERIAL					; IDE + Serial
+Device_OutputCommandWithParameters:
+	TEST_USING_DPT_AND_JUMP_IF_SERIAL_DEVICE .OutputCommandToSerialPort
+	jmp		IdeCommand_OutputWithParameters
+
+%else									; IDE
+	Device_OutputCommandWithParameters EQU IdeCommand_OutputWithParameters
+%endif
+
+%ifdef MODULE_JRIDE
+ALIGN JUMP_ALIGN
+.OutputCommandToJrIDE:
+	jmp		MemIdeCommand_OutputWithParameters
+%endif
+
+%ifdef MODULE_SERIAL
+ALIGN JUMP_ALIGN
+.OutputCommandToSerialPort:
+	jmp		SerialCommand_OutputWithParameters
+%endif
+
+
+;--------------------------------------------------------------------
+; Device_SelectDrive
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+%ifdef MODULE_JRIDE
+	%ifdef MODULE_SERIAL				; IDE + JR-IDE/ISA + Serial
+	Device_SelectDrive:
+		TEST_USING_DPT_AND_JUMP_IF_SERIAL_DEVICE ReturnSuccessForSerialPort
+		CMP_USING_DPT_AND_JUMP_IF_JRIDE_DEVICE .SelectJrIdeDrive
+		jmp		IdeCommand_SelectDrive
+
+	%else								; IDE + JR-IDE/ISA
+	Device_SelectDrive:
+		CMP_USING_DPT_AND_JUMP_IF_JRIDE_DEVICE .SelectJrIdeDrive
+		jmp		IdeCommand_SelectDrive
+	%endif
+
+%elifdef MODULE_SERIAL					; IDE + Serial
+Device_SelectDrive:
+	TEST_USING_DPT_AND_JUMP_IF_SERIAL_DEVICE ReturnSuccessForSerialPort
+	jmp		IdeCommand_SelectDrive
+
+%else									; IDE
+	Device_SelectDrive EQU IdeCommand_SelectDrive
+%endif
+
+%ifdef MODULE_JRIDE
+ALIGN JUMP_ALIGN
+.SelectJrIdeDrive:
+	jmp		MemIdeCommand_SelectDrive
+%endif
+
+%ifdef MODULE_SERIAL
+ALIGN JUMP_ALIGN
+ReturnSuccessForSerialPort:
+	xor		ax, ax
+	ret
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IOMappedIDE.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IOMappedIDE.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IOMappedIDE.inc	(revision 352)
@@ -0,0 +1,69 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Macros for normal I/O mapped ATA controllers.
+
+%ifndef IO_MAPPED_IDE_INC
+%define IO_MAPPED_IDE_INC
+
+;--------------------------------------------------------------------
+; OUTPUT_AL_TO_IDE_REGISTER_IN_DL
+; JUMP_TO_OUTPUT_AL_TO_IDE_REGISTER_IN_DL
+; OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER_IN_DL
+;	Parameters:
+;		AL:		Byte to output
+;		%1:		IDE Register				(OUTPUT_AL_TO_IDE_REGISTER)
+;				IDE Control Block Register	(OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, DX
+;--------------------------------------------------------------------
+%macro OUTPUT_AL_TO_IDE_REGISTER 1
+%ifnidni %1, dl
+	mov		dl, %1
+%endif
+	call	IdeIO_OutputALtoIdeRegisterInDL
+%endmacro
+
+%macro JUMP_TO_OUTPUT_AL_TO_IDE_REGISTER 1
+%ifnidni %1, dl
+	mov		dl, %1
+%endif
+	jmp		IdeIO_OutputALtoIdeRegisterInDL
+%endmacro
+
+%macro OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER 1
+%ifnidni %1, dl
+	mov		dl, %1
+%endif
+	call	IdeIO_OutputALtoIdeControlBlockRegisterInDL
+%endmacro
+
+
+;--------------------------------------------------------------------
+; INPUT_TO_AL_FROM_IDE_REGISTER
+; JUMP_TO_INPUT_TO_AL_FROM_IDE_REGISTER
+;	Parameters:
+;		%1:		IDE Register
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AL:		Inputted byte
+;	Corrupts registers:
+;		BX, DX
+;--------------------------------------------------------------------
+%macro INPUT_TO_AL_FROM_IDE_REGISTER 1
+%ifnidni %1, dl
+	mov		dl, %1
+%endif
+	call	IdeIO_InputToALfromIdeRegisterInDL
+%endmacro
+
+%macro JUMP_TO_INPUT_TO_AL_FROM_IDE_REGISTER 1
+%ifnidni %1, dl
+	mov		dl, %1
+%endif
+	jmp		IdeIO_InputToALfromIdeRegisterInDL
+%endmacro
+
+
+%endif ; IO_MAPPED_IDE_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeCommand.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeCommand.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeCommand.asm	(revision 352)
@@ -0,0 +1,225 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	IDE Device Command functions.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; IdeCommand_ResetMasterAndSlaveController
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+IDEDEVICE%+Command_ResetMasterAndSlaveController:
+	; HSR0: Set_SRST
+	call	AccessDPT_GetDeviceControlByteToAL
+	or		al, FLG_DEVCONTROL_SRST | FLG_DEVCONTROL_nIEN	; Set Reset bit
+	OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER		DEVICE_CONTROL_REGISTER_out
+	mov		ax, HSR0_RESET_WAIT_US
+	call	Timer_DelayMicrosecondsFromAX
+
+	; HSR1: Clear_wait
+	call	AccessDPT_GetDeviceControlByteToAL
+	or		al, FLG_DEVCONTROL_nIEN
+	and		al, ~FLG_DEVCONTROL_SRST						; Clear reset bit
+	OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER		DEVICE_CONTROL_REGISTER_out
+	mov		ax, HSR1_RESET_WAIT_US
+	call	Timer_DelayMicrosecondsFromAX
+
+	; HSR2: Check_status
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_MOTOR_STARTUP, FLG_STATUS_BSY)
+	jmp		IDEDEVICE%+Wait_PollStatusFlagInBLwithTimeoutInBH
+
+
+;--------------------------------------------------------------------
+; IdeCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Select Register
+;		DS:		Segment to RAMVARS
+;		ES:SI:	Ptr to buffer to receive 512-byte IDE Information
+;		CS:BP:	Ptr to IDEVARS
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BL, CX, DX, SI, DI, ES
+;--------------------------------------------------------------------
+IDEDEVICE%+Command_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH:
+	; Create fake DPT to be able to use Device.asm functions
+	call	FindDPT_ForNewDriveToDSDI
+	eMOVZX	ax, bh
+	mov		[di+DPT.wFlags], ax
+	mov		[di+DPT.bIdevarsOffset], bp
+	mov		BYTE [di+DPT_ATA.bSetBlock], 1	; Block = 1 sector
+%ifdef ASSEMBLE_SHARED_IDE_DEVICE_FUNCTIONS
+	call	IdeDPT_StoreReversedAddressLinesFlagIfNecessary
+%endif
+
+	; Wait until drive motors have reached max speed
+	cmp		bp, BYTE ROMVARS.ideVars0
+	jne		SHORT .SkipLongWaitSinceDriveIsNotPrimaryMaster
+	test	al, FLG_DRVNHEAD_DRV
+	jnz		SHORT .SkipLongWaitSinceDriveIsNotPrimaryMaster
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_MOTOR_STARTUP, FLG_STATUS_BSY)
+	call	IDEDEVICE%+Wait_PollStatusFlagInBLwithTimeoutInBH
+.SkipLongWaitSinceDriveIsNotPrimaryMaster:
+
+	; Create IDEPACK without INTPACK
+	push	bp
+	call	Idepack_FakeToSSBP
+
+	; Prepare to output Identify Device command
+	mov		dl, 1						; Sector count (required by IdeTransfer.asm)
+	mov		al, COMMAND_IDENTIFY_DEVICE
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_IDENTIFY_DEVICE, FLG_STATUS_DRQ)
+	call	Idepack_StoreNonExtParametersAndIssueCommandFromAL
+
+	; Clean stack and return
+	lea		sp, [bp+EXTRA_BYTES_FOR_INTPACK]	; This assumes BP hasn't changed between Idepack_FakeToSSBP and here
+	pop		bp
+	ret
+
+
+;--------------------------------------------------------------------
+; IdeCommand_OutputWithParameters
+;	Parameters:
+;		BH:		System timer ticks for timeout
+;		BL:		IDE Status Register bit to poll after command
+;		ES:SI:	Ptr to buffer (for data transfer commands)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CX:		Number of successfully transferred sectors (for transfer commands)
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, (CX), DX, (ES:SI for data transfer commands)
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+IDEDEVICE%+Command_OutputWithParameters:
+	push	bx						; Store status register bits to poll
+
+	; Select Master or Slave drive and output head number or LBA28 top bits
+	call	IDEDEVICE%+Command_SelectDrive
+	jc		SHORT .DriveNotReady
+
+	; Output Device Control Byte to enable or disable interrupts
+	mov		al, [bp+IDEPACK.bDeviceControl]
+%ifdef ASSEMBLE_SHARED_IDE_DEVICE_FUNCTIONS	; JR-IDE/ISA
+	test	al, FLG_DEVCONTROL_nIEN	; Interrupts disabled?
+	jnz		SHORT .DoNotSetInterruptInServiceFlag
+
+	; Clear Task Flag and set Interrupt In-Service Flag
+	or		BYTE [di+DPT.bFlagsHigh], FLGH_DPT_INTERRUPT_IN_SERVICE
+	push	ds
+	LOAD_BDA_SEGMENT_TO	ds, dx, !	; Also zero DX
+	mov		[BDA.bHDTaskFlg], dl
+	pop		ds
+.DoNotSetInterruptInServiceFlag:
+%endif
+	OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER		DEVICE_CONTROL_REGISTER_out
+
+	; Output Feature Number
+	mov		al, [bp+IDEPACK.bFeatures]
+	OUTPUT_AL_TO_IDE_REGISTER	FEATURES_REGISTER_out
+
+	; Output Sector Address High (only used by LBA48)
+%ifdef MODULE_EBIOS
+	eMOVZX	ax, [bp+IDEPACK.bLbaLowExt]		; Zero sector count
+	mov		cx, [bp+IDEPACK.wLbaMiddleAndHighExt]
+	call	IDEDEVICE%+OutputSectorCountAndAddress
+%endif
+
+	; Output Sector Address Low
+	mov		ax, [bp+IDEPACK.wSectorCountAndLbaLow]
+	mov		cx, [bp+IDEPACK.wLbaMiddleAndHigh]
+	call	IDEDEVICE%+OutputSectorCountAndAddress
+
+	; Output command
+	mov		al, [bp+IDEPACK.bCommand]
+	OUTPUT_AL_TO_IDE_REGISTER	COMMAND_REGISTER_out
+
+	; Wait until command completed
+	pop		bx						; Pop status and timeout for polling
+	cmp		bl, FLG_STATUS_DRQ		; Data transfer started?
+	je		SHORT IDEDEVICE%+Transfer_StartWithCommandInAL
+	test	BYTE [bp+IDEPACK.bDeviceControl], FLG_DEVCONTROL_nIEN
+	jz		SHORT .WaitForIrqOrRdy
+	jmp		IDEDEVICE%+Wait_PollStatusFlagInBLwithTimeoutInBH
+
+ALIGN JUMP_ALIGN
+.WaitForIrqOrRdy:
+	jmp		IDEDEVICE%+Wait_IRQorStatusFlagInBLwithTimeoutInBH
+
+.DriveNotReady:
+	pop		bx							; Clean stack
+	ret
+
+
+;--------------------------------------------------------------------
+; IdeCommand_SelectDrive
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+IDEDEVICE%+Command_SelectDrive:
+	; Wait until neither Master or Slave Drive is busy.
+	; I don't think this wait is necessary.
+	;mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_BSY, FLG_STATUS_BSY)
+	;cmp		BYTE [bp+IDEPACK.bCommand], COMMAND_IDENTIFY_DEVICE
+	;eCMOVE	bh, TIMEOUT_IDENTIFY_DEVICE
+	;call	IDEDEVICE%+Wait_PollStatusFlagInBLwithTimeoutInBH
+
+	; Select Master or Slave Drive
+	mov		al, [bp+IDEPACK.bDrvAndHead]
+	OUTPUT_AL_TO_IDE_REGISTER	DRIVE_AND_HEAD_SELECT_REGISTER
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRDY, FLG_STATUS_DRDY)
+	cmp		BYTE [bp+IDEPACK.bCommand], COMMAND_IDENTIFY_DEVICE
+	eCMOVE	bh, TIMEOUT_IDENTIFY_DEVICE
+	call	IDEDEVICE%+Wait_PollStatusFlagInBLwithTimeoutInBH
+
+	; Ignore errors from IDE Error Register (set by previous command)
+	cmp		ah, RET_HD_TIMEOUT
+	je		SHORT .FailedToSelectDrive
+	xor		ax, ax					; Always success unless timeout
+	ret
+.FailedToSelectDrive:
+	stc
+	ret
+
+
+;--------------------------------------------------------------------
+; OutputSectorCountAndAddress
+;	Parameters:
+;		AH:		LBA low bits (Sector Number)
+;		AL:		Sector Count
+;		CL:		LBA middle bits (Cylinder Number low)
+;		CH:		LBA high bits (Cylinder Number high)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AL, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+IDEDEVICE%+OutputSectorCountAndAddress:
+	OUTPUT_AL_TO_IDE_REGISTER	SECTOR_COUNT_REGISTER
+
+	mov		al, ah
+	OUTPUT_AL_TO_IDE_REGISTER	LBA_LOW_REGISTER
+
+	mov		al, cl
+	OUTPUT_AL_TO_IDE_REGISTER	LBA_MIDDLE_REGISTER
+
+	mov		al, ch
+	JUMP_TO_OUTPUT_AL_TO_IDE_REGISTER	LBA_HIGH_REGISTER
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeDPT.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeDPT.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeDPT.asm	(revision 352)
@@ -0,0 +1,55 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Sets IDE Device specific parameters to DPT.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; IdeDPT_Finalize
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		CF:		Clear, IDE interface only supports hard disks
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+IdeDPT_Finalize:
+	; Fall to .StoreBlockMode
+
+;--------------------------------------------------------------------
+; .StoreBlockMode
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+.StoreBlockMode:
+	mov		al, 1							; Block mode will be enabled on AH=9h
+	mov		ah, [es:si+ATA1.bBlckSize]		; Max block size in sectors
+	mov		[di+DPT_ATA.wSetAndMaxBlock], ax
+	; Fall to IdeDPT_StoreReversedAddressLinesFlagIfNecessary
+
+;--------------------------------------------------------------------
+; IdeDPT_StoreReversedAddressLinesFlagIfNecessary
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		CF:		Always clear, we don't support floppies on the IDE inteface
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+IdeDPT_StoreReversedAddressLinesFlagIfNecessary:
+	cmp		BYTE [cs:bp+IDEVARS.bDevice], DEVICE_XTIDE_WITH_REVERSED_A3_AND_A0
+	jne		SHORT .EndDPT
+	or		BYTE [di+DPT.bFlagsHigh], FLGH_DPT_REVERSED_A0_AND_A3
+
+.EndDPT:
+	clc
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeError.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeError.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeError.asm	(revision 352)
@@ -0,0 +1,98 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	IDE Device error functions.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; IdeError_GetBiosErrorCodeToAHfromPolledStatusRegisterInAL
+;	Parameters:
+;		AL:		IDE Status Register contents
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		BIOS error code
+;		CF:		Set if error
+;				Cleared if no error
+;	Corrupts registers:
+;		AL, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+IDEDEVICE%+Error_GetBiosErrorCodeToAHfromPolledStatusRegisterInAL:
+	mov		ah, al			; IDE Status Register to AH
+	INPUT_TO_AL_FROM_IDE_REGISTER	ERROR_REGISTER_in
+
+%ifndef ASSEMBLE_SHARED_IDE_DEVICE_FUNCTIONS	; JR-IDE/ISA
+	jmp		ContinueFromMemIdeError
+%else
+ContinueFromMemIdeError:
+	xchg	al, ah			; Status Register now in AL, Error Register now in AH
+
+	; I don't think anything actually reads these from BDA
+	;push	ds
+	;LOAD_BDA_SEGMENT_TO	ds, dx
+	;mov		[HDBDA.wHDStAndErr], ax
+	;pop		ds
+
+	; Fall to GetBiosErrorCodeToAHfromStatusAndErrorRegistersInAX
+
+
+;--------------------------------------------------------------------
+; GetBiosErrorCodeToAHfromStatusAndErrorRegistersInAX
+;	Parameters:
+;		AL:		IDE Status Register contents
+;		AH:		IDE Error Register contents
+;	Returns:
+;		AH:		BIOS INT 13h error code
+;		CF:		Set if error
+;				Cleared if no error
+;	Corrupts registers:
+;		BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+GetBiosErrorCodeToAHfromStatusAndErrorRegistersInAX:
+	test	al, FLG_STATUS_BSY
+	jz		SHORT .CheckErrorBitsFromStatusRegisterInAL
+	mov		ah, RET_HD_TIMEOUT
+	jmp		SHORT .ReturnBiosErrorCodeInAH
+
+ALIGN JUMP_ALIGN
+.CheckErrorBitsFromStatusRegisterInAL:
+	test	al, FLG_STATUS_DF | FLG_STATUS_CORR | FLG_STATUS_ERR
+	jnz		SHORT .ProcessErrorFromStatusRegisterInAL
+	xor		ah, ah					; No errors, zero AH and CF
+	ret
+
+.ProcessErrorFromStatusRegisterInAL:
+	test	al, FLG_STATUS_ERR		; Error specified in Error register?
+	jnz		SHORT .ConvertBiosErrorToAHfromErrorRegisterInAH
+	mov		ah, RET_HD_ECC			; Assume ECC corrected error
+	test	al, FLG_STATUS_CORR		; ECC corrected error?
+	jnz		SHORT .ReturnBiosErrorCodeInAH
+	mov		ah, RET_HD_CONTROLLER	; Must be Device Fault
+	jmp		SHORT .ReturnBiosErrorCodeInAH
+
+.ConvertBiosErrorToAHfromErrorRegisterInAH:
+	xor		bx, bx					; Clear CF
+.ErrorBitLoop:
+	rcr		ah, 1					; Set CF if error bit set
+	jc		SHORT .LookupErrorCode
+	inc		bx
+	test	ah, ah					; Clear CF
+	jnz		SHORT .ErrorBitLoop
+.LookupErrorCode:
+	mov		ah, [cs:bx+.rgbRetCodeLookup]
+.ReturnBiosErrorCodeInAH:
+	stc								; Set CF since error
+	ret
+
+.rgbRetCodeLookup:
+	db	RET_HD_ADDRMARK		; Bit0=AMNF, Address Mark Not Found
+	db	RET_HD_SEEK_FAIL	; Bit1=TK0NF, Track 0 Not Found
+	db	RET_HD_INVALID		; Bit2=ABRT, Aborted Command
+	db	RET_HD_NOTLOCKED	; Bit3=MCR, Media Change Requested
+	db	RET_HD_NOT_FOUND	; Bit4=IDNF, ID Not Found
+	db	RET_HD_LOCKED		; Bit5=MC, Media Changed
+	db	RET_HD_UNCORRECC	; Bit6=UNC, Uncorrectable Data Error
+	db	RET_HD_BADSECTOR	; Bit7=BBK, Bad Block Detected
+	db	RET_HD_STATUSERR	; When Error Register is zero
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeIO.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeIO.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeIO.asm	(revision 352)
@@ -0,0 +1,81 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	IDE Register I/O functions.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; IdeIO_OutputALtoIdeControlBlockRegisterInDL
+; IdeIO_OutputALtoIdeRegisterInDL
+;	Parameters:
+;		AL:		Byte to output
+;		DL:		IDE Control Block Register	(IdeIO_OutputALtoIdeControlBlockRegisterInDL)
+;				IDE Register				(IdeIO_OutputALtoIdeRegisterInDL)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+IdeIO_OutputALtoIdeControlBlockRegisterInDL:
+	mov		bl, IDEVARS.wPortCtrl
+	SKIP2B	f	; cmp ax, <next instruction>
+	; Fall to IdeIO_OutputALtoIdeRegisterInDL
+
+IdeIO_OutputALtoIdeRegisterInDL:
+	mov		bl, IDEVARS.wPort
+	call	GetPortToDXandTranslateA0andA3ifNecessary
+	out		dx, al
+	ret
+
+
+;--------------------------------------------------------------------
+; IdeIO_InputToALfromIdeRegisterInDL
+;	Parameters:
+;		DL:		IDE Register
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AL:		Inputted byte
+;	Corrupts registers:
+;		BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+IdeIO_InputToALfromIdeRegisterInDL:
+	mov		bl, IDEVARS.wPort
+	call	GetPortToDXandTranslateA0andA3ifNecessary
+	in		al, dx
+	ret
+
+
+;--------------------------------------------------------------------
+; GetPortToDXandTranslateA0andA3ifNecessary
+;	Parameters:
+;		BL:		Offset to port in IDEVARS (IDEVARS.wPort or IDEVARS.wPortCtrl)
+;		DL:		IDE Register
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		DX:		Source/Destination Port
+;	Corrupts registers:
+;		BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+GetPortToDXandTranslateA0andA3ifNecessary:
+	xor		bh, bh
+	add		bl, [di+DPT.bIdevarsOffset]		; CS:BX now points port address
+	xor		dh, dh							; DX now has IDE register offset
+	add		dx, [cs:bx]
+	test	BYTE [di+DPT.bFlagsHigh], FLGH_DPT_REVERSED_A0_AND_A3
+	jz		SHORT .ReturnPortInDX
+
+	; Exchange address lines A0 and A3 from DL
+	mov		bl, dl
+	mov		bh, MASK_A3_AND_A0_ADDRESS_LINES
+	and		bh, bl							; BH = 0, 1, 8 or 9, we can ignore 0 and 9
+	jz		SHORT .ReturnPortInDX			; Jump out since DH is 0
+	xor		bh, MASK_A3_AND_A0_ADDRESS_LINES
+	jz		SHORT .ReturnPortInDX			; Jump out since DH was 9
+	and		dl, ~MASK_A3_AND_A0_ADDRESS_LINES
+	or		dl, bh							; Address lines now reversed
+.ReturnPortInDX:
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeIrq.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeIrq.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeIrq.asm	(revision 352)
@@ -0,0 +1,126 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Interrupt handling related functions.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; IdeIrq_WaitForIRQ
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		CF:		Set if wait done by operating system
+;				Cleared if BIOS must perform task flag polling
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+IdeIrq_WaitForIRQ:
+
+;--------------------------------------------------------------------
+; .NotifyOperatingSystemAboutWaitingForIRQ
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CF:		Set if wait done by operating system
+;				Cleared if BIOS must perform task flag polling
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+.NotifyOperatingSystemAboutWaitingForIRQ:
+	push	ds
+
+	LOAD_BDA_SEGMENT_TO	ds, ax, !		; Zero AX
+	mov		ah, OS_HOOK_DEVICE_BUSY		; Hard disk busy (AX=9000h)
+	cli									; Disable interrupts
+	cmp		al, [BDA.bHDTaskFlg]		; Task flag already set?
+	jc		SHORT .ReturnFromWaitNotify	;  If so, skip OS notification
+	int		BIOS_SYSTEM_INTERRUPT_15h	; OS hook, device busy
+	jnc		SHORT .ReturnFromWaitNotify	; CF cleared, BIOS handles waiting
+
+	; Make sure that OS hooks are supported, otherwise the CF means unsupported function
+	test	ah, ah						; OS hook supported? (clears CF)
+	jnz		SHORT .ReturnFromWaitNotify	; AH has error, BIOS must do the wait
+	stc									; Set CF since wait done by OS
+.ReturnFromWaitNotify:
+	sti									; Enable interrupts
+	pop		ds
+	ret
+
+
+;--------------------------------------------------------------------
+; IDE Interrupt Service Routines.
+;
+; IdeIrq_InterruptServiceRoutineForIrqs2to7
+; IdeIrq_InterruptServiceRoutineForIrqs8to15
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+IdeIrq_InterruptServiceRoutineForIrqs2to7:
+	push	di
+	push	ax
+	call	AcknowledgeIdeInterruptAndSetTaskFlag
+
+	mov		al, COMMAND_END_OF_INTERRUPT
+	jmp		SHORT AcknowledgeMasterInterruptController
+
+
+ALIGN JUMP_ALIGN
+IdeIrq_InterruptServiceRoutineForIrqs8to15:
+	push	di
+	push	ax
+	call	AcknowledgeIdeInterruptAndSetTaskFlag
+
+	mov		al, COMMAND_END_OF_INTERRUPT
+	out		SLAVE_8259_COMMAND_out, al	; Acknowledge Slave 8259
+AcknowledgeMasterInterruptController:
+	out		MASTER_8259_COMMAND_out, al	; Acknowledge Master 8259
+
+	; Issue Int 15h, function AX=9100h (Interrupt ready)
+	mov		ax, OS_HOOK_DEVICE_POST<<8	; Interrupt ready, device 0 (HD)
+	int		BIOS_SYSTEM_INTERRUPT_15h
+
+	pop		ax
+	pop		di
+	iret
+
+
+;--------------------------------------------------------------------
+; AcknowledgeIdeInterruptAndSetTaskFlag
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AcknowledgeIdeInterruptAndSetTaskFlag:
+	push	ds
+	push	si
+	push	dx
+	push	bx
+
+	; Reading Status Register acknowledges IDE interrupt
+	call	RamVars_GetSegmentToDS
+	mov		bl, FLGH_DPT_INTERRUPT_IN_SERVICE
+	call	FindDPT_ToDSDIforFlagsHighInBL
+	INPUT_TO_AL_FROM_IDE_REGISTER STATUS_REGISTER_in
+
+	; Clear Interrupt In-Service Flag from DPT
+	and		BYTE [di+DPT.bFlagsHigh], ~FLGH_DPT_INTERRUPT_IN_SERVICE
+
+	; Set Task Flag
+	LOAD_BDA_SEGMENT_TO	ds, ax
+	mov		BYTE [BDA.bHDTaskFlg], 0FFh		; Set task flag
+
+	pop		bx
+	pop		dx
+	pop		si
+	pop		ds
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeTransfer.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeTransfer.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeTransfer.asm	(revision 352)
@@ -0,0 +1,407 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	IDE Device transfer functions.
+
+; Structure containing variables for PIO transfer functions.
+; This struct must not be larger than IDEPACK without INTPACK.
+struc PIOVARS
+	.wWordsInBlock			resb	2	; 0, Block size in WORDs
+	.wWordsLeft				resb	2	; 2, WORDs left to transfer
+	.wWordsDone				resb	2	; 4, Number of sectors xferred
+							resb	1	; 6,
+							resb	1	; 7, IDEPACK.bDeviceControl
+	.wDataPort				resb	2	; 8, IDE Data Port
+	.fnXfer					resb	2	; 10, Offset to transfer function
+endstruc
+
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; IdeTransfer_StartWithCommandInAL
+;	Parameters:
+;		AL:		IDE command that was used to start the transfer
+;				(all PIO read and write commands including Identify Device)
+;		ES:SI:	Ptr to normalized data buffer
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CX:		Number of successfully transferred sectors
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, DX, SI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+IdeTransfer_StartWithCommandInAL:
+	; Are we reading or writing?
+	test	al, 16	; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
+	mov		ah, [bp+IDEPACK.bSectorCount]
+	jnz		SHORT WriteToDrive
+	cmp		al, COMMAND_WRITE_MULTIPLE
+	je		SHORT WriteToDrive
+	; Fall to ReadFromDrive
+
+;--------------------------------------------------------------------
+; ReadFromDrive
+;	Parameters:
+;		AH:		Number of sectors to transfer (1...128)
+;		ES:SI:	Normalized ptr to buffer to receive data
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to PIOVARS
+;	Returns:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		AH:		BIOS Error code
+;		CX:		Number of successfully transferred sectors
+;		CF:		0 if transfer successful
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX, DX, SI, ES
+;--------------------------------------------------------------------
+ReadFromDrive:
+	; Prepare to read data to ESSI
+	mov		bx, g_rgfnPioRead
+	call	InitializePiovarsInSSBPwithSectorCountInAH
+
+	; Wait until drive is ready to transfer
+	call	IdeWait_IRQorDRQ					; Wait until ready to transfer
+	jc		SHORT ReturnWithTransferErrorInAH
+	xchg	si, di								; ES:DI now points buffer
+
+	mov		cx, [bp+PIOVARS.wWordsInBlock]
+
+ALIGN JUMP_ALIGN
+.ReadNextBlockFromDrive:
+	mov		dx, [bp+PIOVARS.wDataPort]
+	cmp		[bp+PIOVARS.wWordsLeft], cx
+	jbe		SHORT .ReadLastBlockFromDrive
+	call	[bp+PIOVARS.fnXfer]
+
+	; Wait until ready for next block and check for errors
+	xchg	di, si								; DS:DI now points DPT
+	call	IdeWait_IRQorDRQ					; Wait until ready to transfer
+	jc		SHORT ReturnWithTransferErrorInAH
+	xchg	si, di								; ES:DI now points buffer
+
+	; Increment number of successfully read WORDs
+	mov		cx, [bp+PIOVARS.wWordsInBlock]
+	sub		[bp+PIOVARS.wWordsLeft], cx
+	add		[bp+PIOVARS.wWordsDone], cx
+	jmp		SHORT .ReadNextBlockFromDrive
+
+ALIGN JUMP_ALIGN
+.ReadLastBlockFromDrive:
+	mov		cx, [bp+PIOVARS.wWordsLeft]
+	call	[bp+PIOVARS.fnXfer]					; Transfer possibly partial block
+
+	; Check for errors in last block
+	mov		di, si								; DS:DI now points DPT
+CheckErrorsAfterTransferringLastBlock:
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRDY)
+	call	IdeWait_PollStatusFlagInBLwithTimeoutInBH
+
+	; Return number of successfully read sectors
+ReturnWithTransferErrorInAH:
+	mov		cx, [bp+PIOVARS.wWordsDone]
+	jc		SHORT .ConvertTransferredWordsInCXtoSectors
+	add		cx, [bp+PIOVARS.wWordsLeft]			; Never sets CF
+.ConvertTransferredWordsInCXtoSectors:
+	xchg	cl, ch
+	ret
+
+
+;--------------------------------------------------------------------
+; WriteToDrive
+;	Parameters:
+;		AH:		Number of sectors to transfer (1...128)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		ES:SI:	Normalized ptr to buffer containing data
+;		SS:BP:	Ptr to PIOVARS
+;	Returns:
+;		AH:		BIOS Error code
+;		CX:		Number of successfully transferred sectors
+;		CF:		0 if transfer successful
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX, DX, SI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+WriteToDrive:
+	; Prepare to write data from ESSI
+	mov		bx, g_rgfnPioWrite
+	call	InitializePiovarsInSSBPwithSectorCountInAH
+
+	; Always poll when writing first block (IRQs are generated for following blocks)
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
+	call	IdeWait_PollStatusFlagInBLwithTimeoutInBH
+	jc		SHORT ReturnWithTransferErrorInAH
+
+	mov		cx, [bp+PIOVARS.wWordsInBlock]
+
+ALIGN JUMP_ALIGN
+.WriteNextBlockToDrive:
+	mov		dx, [bp+PIOVARS.wDataPort]
+	cmp		[bp+PIOVARS.wWordsLeft], cx
+	jbe		SHORT .WriteLastBlockToDrive
+	call	[bp+PIOVARS.fnXfer]
+
+	; Wait until ready for next block and check for errors
+	call	IdeWait_IRQorDRQ					; Wait until ready to transfer
+	jc		SHORT ReturnWithTransferErrorInAH
+
+	; Increment number of successfully written WORDs
+	mov		cx, [bp+PIOVARS.wWordsInBlock]
+	sub		[bp+PIOVARS.wWordsLeft], cx
+	add		[bp+PIOVARS.wWordsDone], cx
+	jmp		SHORT .WriteNextBlockToDrive
+
+ALIGN JUMP_ALIGN
+.WriteLastBlockToDrive:
+	mov		cx, [bp+PIOVARS.wWordsLeft]
+%ifdef USE_186
+	push	CheckErrorsAfterTransferringLastBlock
+	jmp		[bp+PIOVARS.fnXfer]					; Transfer possibly partial block
+%else
+	call	[bp+PIOVARS.fnXfer]					; Transfer possibly partial block
+	jmp		SHORT CheckErrorsAfterTransferringLastBlock
+%endif
+
+
+;--------------------------------------------------------------------
+; InitializePiovarsInSSBPwithSectorCountInAH
+;	Parameters:
+;		AH:		Number of sectors to transfer (1...128)
+;		BX:		Offset to transfer function lookup table
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to PIOVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+InitializePiovarsInSSBPwithSectorCountInAH:
+	; Store sizes
+	xor		al, al
+	mov		[bp+PIOVARS.wWordsLeft], ax
+	mov		ah, [di+DPT_ATA.bSetBlock]
+	mov		[bp+PIOVARS.wWordsInBlock], ax
+	cbw
+	mov		[bp+PIOVARS.wWordsDone], ax			; Zero
+
+	; Get transfer function based on bus type
+	xchg	ax, bx								; Lookup table offset to AX
+	mov		bl, [di+DPT.bIdevarsOffset]			; CS:BX now points to IDEVARS
+	mov		dx, [cs:bx+IDEVARS.wPort]			; Load IDE Data port address
+	mov		bl, [cs:bx+IDEVARS.bDevice]			; Load device type to BX
+	add		bx, ax
+	mov		[bp+PIOVARS.wDataPort], dx
+	mov		ax, [cs:bx]							; Load offset to transfer function
+	mov		[bp+PIOVARS.fnXfer], ax
+	ret
+
+
+;--------------------------------------------------------------------
+; DualByteReadForXtide		Dual port 8-bit XTIDE PIO read transfer
+; SingleByteRead			Single port 8-bit PIO read transfer
+; WordReadForXTIDEmod		8088/8086 compatible 16-bit IDE PIO read transfer
+; WordReadForXTplusAndAT	Normal 16-bit IDE PIO read transfer
+; DWordRead					VLB/PCI 32-bit IDE PIO read transfer
+;	Parameters:
+;		CX:		Block size in WORDs
+;		DX:		IDE Data port address
+;		ES:DI:	Normalized ptr to buffer to receive data
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DualByteReadForXtide:
+	eSHR_IM	cx, 2		; Loop unrolling
+	mov		bx, 8		; Bit mask for toggling data low/high reg
+ALIGN JUMP_ALIGN
+.InswLoop:
+	XTIDE_INSW
+	XTIDE_INSW
+	XTIDE_INSW
+	XTIDE_INSW
+	loop	.InswLoop
+	ret
+
+;----
+ALIGN JUMP_ALIGN
+SingleByteRead:
+%ifdef USE_186	; INS instruction available
+	shl		cx, 1		; WORD count to BYTE count
+	dec		cx			; Fix for CX overflowing on a 128 sector transfer
+	insb
+	rep insb
+%else			; If 8088/8086
+	shr		cx, 1		; WORD count to DWORD count
+ALIGN JUMP_ALIGN
+.InsdLoop:
+	in		al, dx
+	stosb				; Store to [ES:DI]
+	in		al, dx
+	stosb
+	in		al, dx
+	stosb
+	in		al, dx
+	stosb
+	loop	.InsdLoop
+%endif
+	ret
+
+;----
+%ifndef USE_186
+ALIGN JUMP_ALIGN
+WordReadForXTIDEmod:
+	times 2 shr	cx, 1	; WORD count to QWORD count
+ALIGN JUMP_ALIGN
+.ReadNextQword:
+	in		ax, dx		; Read 1st WORD
+	stosw				; Store 1st WORD to [ES:DI]
+	in		ax, dx
+	stosw				; 2nd
+	in		ax, dx
+	stosw				; 3rd
+	in		ax, dx
+	stosw				; 4th
+	loop	.ReadNextQword
+	ret
+%endif
+
+;----
+ALIGN JUMP_ALIGN
+WordReadForXTplusAndAT:
+	rep
+	db		6Dh			; INSW (we want this in XT build)
+	ret
+
+;----
+ALIGN JUMP_ALIGN
+DWordRead:
+	shr		cx, 1		; WORD count to DWORD count
+	rep
+	db		66h			; Override operand size to 32-bit
+	db		6Dh			; INSW/INSD
+	ret
+
+
+;--------------------------------------------------------------------
+; DualByteWriteForXtide		Dual port 8-bit XTIDE PIO write transfer
+; SingleByteWrite			Single port 8-bit PIO write transfer
+; WordWriteForXTIDEmod		8088/8086 compatible 16-bit IDE PIO read transfer
+; WordWrite					Normal 16-bit IDE PIO write transfer
+; DWordWrite				VLB/PCI 32-bit IDE PIO write transfer
+;	Parameters:
+;		CX:		Block size in WORDs
+;		DX:		IDE Data port address
+;		ES:SI:	Normalized ptr to buffer containing data
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DualByteWriteForXtide:
+	push	ds
+	push	bx
+	eSHR_IM	cx, 2		; Loop unrolling
+	mov		bx, 8		; Bit mask for toggling data low/high reg
+	push	es			; Copy ES...
+	pop		ds			; ...to DS
+ALIGN JUMP_ALIGN
+.OutswLoop:
+	XTIDE_OUTSW
+	XTIDE_OUTSW
+	XTIDE_OUTSW
+	XTIDE_OUTSW
+	loop	.OutswLoop
+	pop		bx
+	pop		ds
+	ret
+
+;----
+ALIGN JUMP_ALIGN
+SingleByteWrite:
+%ifdef USE_186	; OUTS instruction available
+	shl		cx, 1		; WORD count to BYTE count
+	dec		cx			; Fix for CX overflowing on a 128 sector transfer
+	es outsb			; Source is ES segment
+	rep es outsb
+%else			; If 8088/8086
+	shr		cx, 1		; WORD count to DWORD count
+	push	ds			; Store DS
+	push	es			; Copy ES...
+	pop		ds			; ...to DS
+ALIGN JUMP_ALIGN
+.OutsdLoop:
+	lodsb				; Load from [DS:SI] to AL
+	out		dx, al
+	lodsb
+	out		dx, al
+	lodsb
+	out		dx, al
+	lodsb
+	out		dx, al
+	loop	.OutsdLoop
+	pop		ds			; Restore DS
+%endif
+	ret
+
+;---
+ALIGN JUMP_ALIGN
+WordWriteForXTIDEmod:
+	push	ds
+	eSHR_IM	cx, 2		; Loop unrolling
+	push	es			; Copy ES...
+	pop		ds			; ...to DS
+ALIGN JUMP_ALIGN
+.WriteNextQword:
+	XTIDE_MOD_OUTSW
+	XTIDE_MOD_OUTSW
+	XTIDE_MOD_OUTSW
+	XTIDE_MOD_OUTSW
+	loop	.WriteNextQword
+	pop		ds
+	ret
+
+;----
+ALIGN JUMP_ALIGN
+WordWrite:
+	es					; Source is ES segment
+	rep
+	db		6Fh			; OUTSW (we want this in XT build)
+	ret
+
+ALIGN JUMP_ALIGN
+DWordWrite:
+	shr		cx, 1		; WORD count to DWORD count
+	es					; Source is ES segment
+	rep
+	db		66h			; Override operand size to 32-bit
+	db		6Fh			; OUTSW/OUTSD
+	ret
+
+
+; Lookup tables to get transfer function based on bus type
+ALIGN WORD_ALIGN
+g_rgfnPioRead:
+	dw		DualByteReadForXtide	; DEVICE_8BIT_DUAL_PORT_XTIDE
+%ifdef USE_186
+	dw		WordReadForXTplusAndAT	; DEVICE_XTIDE_WITH_REVERSED_A3_AND_A0
+%else
+	dw		WordReadForXTIDEmod
+%endif
+	dw		SingleByteRead			; DEVICE_8BIT_SINGLE_PORT
+	dw		WordReadForXTplusAndAT	; DEVICE_16BIT_ATA
+	dw		DWordRead				; DEVICE_32BIT_ATA
+
+g_rgfnPioWrite:
+	dw		DualByteWriteForXtide	; DEVICE_8BIT_DUAL_PORT_XTIDE
+	dw		WordWriteForXTIDEmod	; DEVICE_XTIDE_WITH_REVERSED_A3_AND_A0
+	dw		SingleByteWrite			; DEVICE_8BIT_SINGLE_PORT
+	dw		WordWrite				; DEVICE_16BIT_ATA
+	dw		DWordWrite				; DEVICE_32BIT_ATA
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeWait.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeWait.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/IDE/IdeWait.asm	(revision 352)
@@ -0,0 +1,118 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	IDE Device wait functions.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; IdeWait_IRQorDRQ
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK, PIOVARS or MEMPIOVARS
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+IDEDEVICE%+Wait_IRQorDRQ:
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
+%ifdef ASSEMBLE_SHARED_IDE_DEVICE_FUNCTIONS		; JR-IDE/ISA does not support IRQ
+	test	BYTE [bp+IDEPACK.bDeviceControl], FLG_DEVCONTROL_nIEN
+	jnz		SHORT IDEDEVICE%+Wait_PollStatusFlagInBLwithTimeoutInBH	; Interrupt disabled
+%endif
+	; Fall to IdeWait_IRQorStatusFlagInBLwithTimeoutInBH
+
+
+;--------------------------------------------------------------------
+; IdeWait_IRQorStatusFlagInBLwithTimeoutInBH
+;	Parameters:
+;		BH:		Timeout ticks
+;		BL:		IDE Status Register bit to wait
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+IDEDEVICE%+Wait_IRQorStatusFlagInBLwithTimeoutInBH:
+%ifdef ASSEMBLE_SHARED_IDE_DEVICE_FUNCTIONS		; JR-IDE/ISA does not support IRQ
+	call	IdeIrq_WaitForIRQ
+%endif
+	; Always fall to IdeWait_PollStatusFlagInBLwithTimeoutInBH for error processing
+
+
+;--------------------------------------------------------------------
+; IdeWait_PollStatusFlagInBLwithTimeoutInBH
+;	Parameters:
+;		BH:		Timeout ticks
+;		BL:		IDE Status Register bit to poll
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+IDEDEVICE%+Wait_PollStatusFlagInBLwithTimeoutInBH:
+	mov		ah, bl
+	mov		cl, bh
+	call	Timer_InitializeTimeoutWithTicksInCL
+	and		ah, ~FLG_STATUS_BSY
+	jz		SHORT IDEDEVICE%+PollBsyOnly
+	; Fall to PollBsyAndFlgInAH
+
+;--------------------------------------------------------------------
+; PollBsyAndFlgInAH
+;	Parameters:
+;		AH:		Status Register Flag to poll (until set) when device not busy
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		Clear if wait completed successfully (no errors)
+;				Set if any error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+IDEDEVICE%+PollBsyAndFlgInAH:
+	INPUT_TO_AL_FROM_IDE_REGISTER	STATUS_REGISTER_in	; Discard contents for first read
+ALIGN JUMP_ALIGN
+.PollLoop:
+	INPUT_TO_AL_FROM_IDE_REGISTER	STATUS_REGISTER_in
+	test	al, FLG_STATUS_BSY					; Controller busy?
+	jnz		SHORT .UpdateTimeout				;  If so, jump to timeout update
+	test	al, ah								; Test secondary flag
+	jnz		SHORT IDEDEVICE%+Error_GetBiosErrorCodeToAHfromPolledStatusRegisterInAL
+.UpdateTimeout:
+	call	Timer_SetCFifTimeout
+	jnc		SHORT .PollLoop						; Loop if time left
+	call	IDEDEVICE%+Error_GetBiosErrorCodeToAHfromPolledStatusRegisterInAL
+	jc		SHORT .ReturnErrorCodeInAH
+	mov		ah, RET_HD_TIMEOUT					; Expected bit never got set
+	stc
+.ReturnErrorCodeInAH:
+	ret
+
+
+;--------------------------------------------------------------------
+; PollBsyOnly
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		Clear if wait completed successfully (no errors)
+;				Set if any error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+IDEDEVICE%+PollBsyOnly:
+	INPUT_TO_AL_FROM_IDE_REGISTER	STATUS_REGISTER_in	; Discard contents for first read
+ALIGN JUMP_ALIGN
+.PollLoop:
+	INPUT_TO_AL_FROM_IDE_REGISTER	STATUS_REGISTER_in
+	test	al, FLG_STATUS_BSY					; Controller busy?
+	jz		SHORT IDEDEVICE%+Error_GetBiosErrorCodeToAHfromPolledStatusRegisterInAL
+	call	Timer_SetCFifTimeout				; Update timeout counter
+	jnc		SHORT .PollLoop						; Loop if time left (sets CF on timeout)
+	jmp		SHORT IDEDEVICE%+Error_GetBiosErrorCodeToAHfromPolledStatusRegisterInAL
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Idepack.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Idepack.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Idepack.asm	(revision 352)
@@ -0,0 +1,151 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for managing IDEPACK struct.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Idepack_FakeToSSBP
+;	Parameters:
+;		Nothing
+;	Returns:
+;		SS:BP:	Ptr to IDEPACK
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+Idepack_FakeToSSBP:
+	pop		ax
+	sub		sp, BYTE EXTRA_BYTES_FOR_INTPACK
+	mov		bp, sp
+	jmp		ax
+
+
+;--------------------------------------------------------------------
+; Idepack_ConvertDapToIdepackAndIssueCommandFromAH
+;	Parameters:
+;		AH:		IDE command to issue
+;		BH:		Timeout ticks
+;		BL:		IDE Status Register flag to wait after command
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		ES:SI:	Ptr to DAP (EBIOS Disk Address Packet)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CX:		Number of successfully transferred sectors (for transfer commands)
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, (CX), DX, SI, ES
+;--------------------------------------------------------------------
+%ifdef MODULE_EBIOS
+ALIGN JUMP_ALIGN
+Idepack_ConvertDapToIdepackAndIssueCommandFromAH:
+	mov		al, [es:si+DAP.wSectorCount]
+	mov		[bp+IDEPACK.bSectorCount], al
+	mov		[bp+IDEPACK.bCommand], ah
+
+	mov		al, [es:si+DAP.qwLBA]		; LBA byte 0
+	mov		[bp+IDEPACK.bLbaLow], al
+	mov		ax, [es:si+DAP.qwLBA+1]		; LBA bytes 1 and 2
+	mov		[bp+IDEPACK.wLbaMiddleAndHigh], ax
+	mov		ah, [es:si+DAP.qwLBA+3]		; LBA byte 3, LBA28 bits 24...27
+	mov		[bp+IDEPACK.bLbaLowExt], ah
+	mov		cx, [es:si+DAP.qwLBA+4]		; LBA bytes 4 and 5
+	mov		[bp+IDEPACK.wLbaMiddleAndHighExt], cx
+
+	and		ah, 0Fh						; Limit bits for LBA28
+	call	AccessDPT_GetDriveSelectByteToAL
+	or		al, ah
+	mov		[bp+IDEPACK.bDrvAndHead], al
+
+	; Normalize data buffer pointer to ES:SI
+	mov		ax, [es:si+DAP.wOffset]
+	mov		cx, ax
+	eSHR_IM	ax, 4								; Divide offset by 16
+	add		ax, [es:si+DAP.wSegment]			; Add segment
+	mov		es, ax								; Segment normalized
+	mov		si, cx
+	and		si, BYTE 0Fh						; Offset normalized
+	jmp		SHORT GetDeviceControlByteToIdepackAndStartTransfer
+%endif
+
+
+;--------------------------------------------------------------------
+; Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH
+;	Parameters:
+;		AH:		IDE command to issue
+;		AL:		Number of sectors to transfer (for xfer commands)
+;		BH:		Timeout ticks
+;		BL:		IDE Status Register flag to wait after command
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		ES:SI:	Ptr to normalized data buffer (for xfer commands)
+;		SS:BP:	Ptr to IDEPACK (containing INTPACK)
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CX:		Number of successfully transferred sectors (for transfer commands)
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, (CX), DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH:
+	mov		[bp+IDEPACK.bSectorCount], al
+	mov		[bp+IDEPACK.bCommand], ah
+
+	push	bx
+	call	Address_OldInt13hAddressToIdeAddress
+	call	AccessDPT_GetDriveSelectByteToAL
+	or		al, bh			; AL now has Drive and Head Select Byte
+	mov		[bp+IDEPACK.bDrvAndHead], al
+	mov		[bp+IDEPACK.bLbaLow], bl
+	mov		[bp+IDEPACK.wLbaMiddleAndHigh], cx
+	pop		bx
+
+GetDeviceControlByteToIdepackAndStartTransfer:
+	call	AccessDPT_GetDeviceControlByteToAL
+	mov		[bp+IDEPACK.bDeviceControl], al
+	jmp		Device_OutputCommandWithParameters
+
+
+;--------------------------------------------------------------------
+; Idepack_StoreNonExtParametersAndIssueCommandFromAL
+;	Parameters:
+;		BH:		Timeout ticks
+;		BL:		IDE Status Register flag to wait after command
+;		AL:		IDE command to issue
+;		AH:		Parameter to Drive and Head Select Register (Head bits only)
+;		DL:		Parameter to Sector Count Register
+;		DH:		Parameter to LBA Low / Sector Number Register
+;		CL:		Parameter to LBA Middle / Cylinder Low Register
+;		CH:		Parameter to LBA High / Cylinder High Register
+;		SI:		Parameter to Features Register
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Idepack_StoreNonExtParametersAndIssueCommandFromAL:
+	mov		[bp+IDEPACK.bFeatures], si
+	mov		[bp+IDEPACK.bCommand], al
+	mov		[bp+IDEPACK.wSectorCountAndLbaLow], dx
+	mov		[bp+IDEPACK.wLbaMiddleAndHigh], cx
+
+	; Drive and Head select byte
+	and		ah, MASK_DRVNHEAD_HEAD		; Keep head bits only
+	call	AccessDPT_GetDriveSelectByteToAL
+	or		al, ah
+	mov		[bp+IDEPACK.bDrvAndHead], al
+
+	; Device Control byte with interrupts disabled
+	call	AccessDPT_GetDeviceControlByteToAL
+	or		al, FLG_DEVCONTROL_nIEN		; Disable interrupt
+	mov		[bp+IDEPACK.bDeviceControl], al
+
+	jmp		Device_OutputCommandWithParameters
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/MemoryMappedIDE/MemIdeTransfer.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/MemoryMappedIDE/MemIdeTransfer.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/MemoryMappedIDE/MemIdeTransfer.asm	(revision 352)
@@ -0,0 +1,243 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Memory mapped IDE Device transfer functions.
+
+; Structure containing variables for PIO transfer functions.
+; This struct must not be larger than IDEPACK without INTPACK.
+struc MEMPIOVARS
+	.wWordsInBlock			resb	2	; 0, Block size in WORDs
+	.wWordsLeft				resb	2	; 2, WORDs left to transfer
+	.wWordsDone				resb	2	; 4, Number of sectors xferred
+	; TODO: The above word vars could just as well be byte vars?
+							resb	1	; 6,
+							resb	1	; 7, IDEPACK.bDeviceControl
+	.fpDPT					resb	4	; 8, Far pointer to DPT
+endstruc
+
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; MemIdeTransfer_StartWithCommandInAL
+;	Parameters:
+;		AL:		IDE command that was used to start the transfer
+;				(all PIO read and write commands including Identify Device)
+;		ES:SI:	Ptr to normalized data buffer
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CX:		Number of successfully transferred sectors
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, DX, SI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+MemIdeTransfer_StartWithCommandInAL:
+	push	cs	; We push CS here (segment of SAW) and later pop it to DS (reads) or ES (writes)
+
+	; Initialize MEMPIOVARS
+	xor		cx, cx
+	mov		[bp+MEMPIOVARS.wWordsDone], cx
+	mov		ch, [bp+IDEPACK.bSectorCount]
+	mov		[bp+MEMPIOVARS.wWordsLeft], cx
+	mov		ch, [di+DPT_ATA.bSetBlock]
+	mov		[bp+MEMPIOVARS.wWordsInBlock], cx
+	mov		[bp+MEMPIOVARS.fpDPT], di
+	mov		[bp+MEMPIOVARS.fpDPT+2], ds
+
+	; Are we reading or writing?
+	test	al, 16	; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
+	jnz		SHORT WriteToSectorAccessWindow
+	cmp		al, COMMAND_WRITE_MULTIPLE
+	je		SHORT WriteToSectorAccessWindow
+	; Fall to ReadFromSectorAccessWindow
+
+;--------------------------------------------------------------------
+; ReadFromSectorAccessWindow
+;	Parameters:
+;		Stack:	Segment part of ptr to Sector Access Window
+;		ES:SI:	Normalized ptr to buffer to receive data
+;		SS:BP:	Ptr to MEMPIOVARS
+;	Returns:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		AH:		BIOS Error code
+;		CX:		Number of successfully transferred sectors
+;		CF:		0 if transfer successful
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX, DX, SI, ES
+;--------------------------------------------------------------------
+ReadFromSectorAccessWindow:
+	pop		ds		; CS -> DS
+	mov		di, si	; ES:DI = destination
+	mov		si, JRIDE_SECTOR_ACCESS_WINDOW_OFFSET	; DS:SI = source
+
+	call	WaitUntilReadyToTransferNextBlock
+	jc		SHORT ReturnWithMemoryIOtransferErrorInAH
+
+	mov		cx, [bp+MEMPIOVARS.wWordsInBlock]
+
+ALIGN JUMP_ALIGN
+.ReadNextBlockFromDrive:
+	cmp		[bp+MEMPIOVARS.wWordsLeft], cx
+	jbe		SHORT .ReadLastBlockFromDrive
+	call	ReadSingleBlockFromSectorAccessWindowInDSSItoESDI
+	call	WaitUntilReadyToTransferNextBlock
+	jc		SHORT ReturnWithMemoryIOtransferErrorInAH
+
+	; Increment number of successfully read WORDs
+	mov		cx, [bp+MEMPIOVARS.wWordsInBlock]
+	sub		[bp+MEMPIOVARS.wWordsLeft], cx
+	add		[bp+MEMPIOVARS.wWordsDone], cx
+	jmp		SHORT .ReadNextBlockFromDrive
+
+ALIGN JUMP_ALIGN
+.ReadLastBlockFromDrive:
+	mov		ch, [bp+MEMPIOVARS.wWordsLeft+1]	; Sectors left
+	call	ReadSingleBlockFromSectorAccessWindowInDSSItoESDI
+
+	; Check for errors in last block
+CheckErrorsAfterTransferringLastMemoryMappedBlock:
+	lds		di, [bp+MEMPIOVARS.fpDPT]			; DPT now in DS:DI
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRDY)
+	call	IDEDEVICE%+Wait_PollStatusFlagInBLwithTimeoutInBH
+
+	; Return number of successfully transferred sectors
+ReturnWithMemoryIOtransferErrorInAH:
+	lds		di, [bp+MEMPIOVARS.fpDPT]			; DPT now in DS:DI
+	mov		cx, [bp+MEMPIOVARS.wWordsDone]
+	jc		SHORT .ConvertTransferredWordsInCXtoSectors
+	add		cx, [bp+MEMPIOVARS.wWordsLeft]		; Never sets CF
+.ConvertTransferredWordsInCXtoSectors:
+	xchg	cl, ch
+	ret
+
+
+;--------------------------------------------------------------------
+; WriteToSectorAccessWindow
+;	Parameters:
+;		Stack:	Segment part of ptr to Sector Access Window
+;		ES:SI:	Normalized ptr to buffer containing data
+;		SS:BP:	Ptr to MEMPIOVARS
+;	Returns:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		AH:		BIOS Error code
+;		CX:		Number of successfully transferred sectors
+;		CF:		0 if transfer successful
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX, DX, SI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+WriteToSectorAccessWindow:
+	push	es
+	pop		ds
+	pop		es	; CS -> ES
+	mov		di, JRIDE_SECTOR_ACCESS_WINDOW_OFFSET
+
+	; Always poll when writing first block (IRQs are generated for following blocks)
+	call	WaitUntilReadyToTransferNextBlock
+	jc		SHORT ReturnWithMemoryIOtransferErrorInAH
+
+	mov		cx, [bp+MEMPIOVARS.wWordsInBlock]
+
+ALIGN JUMP_ALIGN
+.WriteNextBlockToDrive:
+	cmp		[bp+MEMPIOVARS.wWordsLeft], cx
+	jbe		SHORT .WriteLastBlockToDrive
+	call	WriteSingleBlockFromDSSIToSectorAccessWindowInESDI
+	call	WaitUntilReadyToTransferNextBlock
+	jc		SHORT ReturnWithMemoryIOtransferErrorInAH
+
+	; Increment number of successfully written WORDs
+	mov		cx, [bp+MEMPIOVARS.wWordsInBlock]
+	sub		[bp+MEMPIOVARS.wWordsLeft], cx
+	add		[bp+MEMPIOVARS.wWordsDone], cx
+	jmp		SHORT .WriteNextBlockToDrive
+
+ALIGN JUMP_ALIGN
+.WriteLastBlockToDrive:
+	mov		ch, [bp+MEMPIOVARS.wWordsLeft+1]		; Sectors left
+	ePUSH_T	bx, CheckErrorsAfterTransferringLastMemoryMappedBlock
+	; Fall to WriteSingleBlockFromDSSIToSectorAccessWindowInESDI
+
+;--------------------------------------------------------------------
+; WriteSingleBlockFromDSSIToSectorAccessWindowInESDI
+;	Parameters:
+;		CH:		Number of sectors in block
+;		DS:SI:	Normalized ptr to source buffer
+;		ES:DI:	Ptr to Sector Access Window
+;	Returns:
+;		CX, DX:	Zero
+;		SI:		Updated
+;	Corrupts registers:
+;		BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+WriteSingleBlockFromDSSIToSectorAccessWindowInESDI:
+	mov		bx, di
+	eMOVZX	dx, ch
+	xor		cl, cl
+ALIGN JUMP_ALIGN
+.WriteBlock:
+	mov		ch, JRIDE_SECTOR_ACCESS_WINDOW_SIZE >> 9
+	rep movsw
+	mov		di, bx	; Reset for next sector
+	dec		dx
+	jnz		SHORT .WriteBlock
+	ret
+
+
+;--------------------------------------------------------------------
+; ReadSingleBlockFromSectorAccessWindowInDSSItoESDI
+;	Parameters:
+;		CH:		Number of sectors in block
+;		ES:DI:	Normalized ptr to buffer to receive data (destination)
+;		DS:SI:	Ptr to Sector Access Window (source)
+;	Returns:
+;		CX, DX:	Zero
+;		DI:		Updated
+;	Corrupts registers:
+;		BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+ReadSingleBlockFromSectorAccessWindowInDSSItoESDI:
+	mov		bx, si
+	eMOVZX	dx, ch
+	xor		cl, cl
+ALIGN JUMP_ALIGN
+.ReadBlock:
+	mov		ch, JRIDE_SECTOR_ACCESS_WINDOW_SIZE >> 9
+	rep movsw
+	mov		si, bx	; Reset for next sector
+	dec		dx
+	jnz		SHORT .ReadBlock
+	ret
+
+
+;--------------------------------------------------------------------
+; WaitUntilReadyToTransferNextBlock
+;	Parameters:
+;		SS:BP:	Ptr to MEMPIOVARS
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+WaitUntilReadyToTransferNextBlock:
+	push	ds
+	push	di
+	lds		di, [bp+MEMPIOVARS.fpDPT]			; DPT now in DS:DI
+	call	IDEDEVICE%+Wait_IRQorDRQ			; Always polls
+	pop		di
+	pop		ds
+	ret
+
+
+%if JRIDE_SECTOR_ACCESS_WINDOW_SIZE <> 512
+	%error "JRIDE_SECTOR_ACCESS_WINDOW_SIZE is no longer equal to 512. MemIdeTransfer.asm needs changes."
+%endif
+
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/MemoryMappedIDE/MemMappedIDE.inc
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/MemoryMappedIDE/MemMappedIDE.inc	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/MemoryMappedIDE/MemMappedIDE.inc	(revision 352)
@@ -0,0 +1,68 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Macros for memory mapped ATA controllers.
+
+%ifndef MEM_MAPPED_IDE_INC
+%define MEM_MAPPED_IDE_INC
+
+JRIDE_SECTOR_ACCESS_WINDOW_OFFSET			EQU	3C00h	; 512 byte IDE Sector Access Window
+JRIDE_COMMAND_BLOCK_REGISTER_WINDOW_OFFSET	EQU	3E00h	; 8 byte CS0 IDE Register Window
+JRIDE_CONTROL_BLOCK_REGISTER_WINDOW_OFFSET	EQU	3E08h	; 8 byte CS1 IDE Register Window
+JRIDE_SECTOR_ACCESS_WINDOW_SIZE				EQU	512		; 512 bytes
+
+
+
+;--------------------------------------------------------------------
+; OUTPUT_AL_TO_IDE_REGISTER_IN_DL
+; JUMP_TO_OUTPUT_AL_TO_IDE_REGISTER_IN_DL
+; OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER_IN_DL
+;	Parameters:
+;		AL:		Byte to output
+;		%1:		IDE Register				(OUTPUT_AL_TO_IDE_REGISTER)
+;				IDE Control Block Register	(OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, DX
+;--------------------------------------------------------------------
+%unmacro OUTPUT_AL_TO_IDE_REGISTER 1
+%macro OUTPUT_AL_TO_IDE_REGISTER 1
+	mov		[cs:JRIDE_COMMAND_BLOCK_REGISTER_WINDOW_OFFSET+%1], al
+%endmacro
+
+%unmacro JUMP_TO_OUTPUT_AL_TO_IDE_REGISTER 1
+%macro JUMP_TO_OUTPUT_AL_TO_IDE_REGISTER 1
+	OUTPUT_AL_TO_IDE_REGISTER %1
+	ret
+%endmacro
+
+%unmacro OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER 1
+%macro OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER 1
+	mov		[cs:JRIDE_CONTROL_BLOCK_REGISTER_WINDOW_OFFSET+%1], al
+%endmacro
+
+
+;--------------------------------------------------------------------
+; INPUT_TO_AL_FROM_IDE_REGISTER
+; JUMP_TO_INPUT_TO_AL_FROM_IDE_REGISTER
+;	Parameters:
+;		%1:		IDE Register
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AL:		Inputted byte
+;	Corrupts registers:
+;		BX, DX
+;--------------------------------------------------------------------
+%unmacro INPUT_TO_AL_FROM_IDE_REGISTER 1
+%macro INPUT_TO_AL_FROM_IDE_REGISTER 1
+	mov		al, [cs:JRIDE_COMMAND_BLOCK_REGISTER_WINDOW_OFFSET+%1]
+%endmacro
+
+%unmacro JUMP_TO_INPUT_TO_AL_FROM_IDE_REGISTER 1
+%macro JUMP_TO_INPUT_TO_AL_FROM_IDE_REGISTER 1
+	INPUT_TO_AL_FROM_IDE_REGISTER %1
+	ret
+%endmacro
+
+
+%endif ; MEM_MAPPED_IDE_INC
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Serial/SerialCommand.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Serial/SerialCommand.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Serial/SerialCommand.asm	(revision 352)
@@ -0,0 +1,173 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Serial Device Command functions.
+
+; Section containing code
+SECTION .text
+
+%define SERIALSERVER_AH_ALREADY_HAS_COMMAND_BYTE
+%define SERIALSERVER_NO_ZERO_SECTOR_COUNTS		
+
+;--------------------------------------------------------------------
+; SerialCommand_OutputWithParameters
+;	Parameters:
+;		BH:		Non-zero if 48-bit addressing used
+;               (ignored at present as 48-bit addressing is not supported)
+;		BL:		IDE Status Register bit to poll after command
+;               (ignored at present, since there is no IDE status register to poll)
+;		ES:SI:	Ptr to buffer (for data transfer commands)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEREGS_AND_INTPACK
+;	Returns:
+;		AH:		INT 13h Error Code
+;		CX:		Number of successfully transferred sectors (for transfer commands)
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BX, CX, DX, (ES:SI for data transfer commands)
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+SerialCommand_OutputWithParameters:
+
+		mov		ah,SerialServer_Command_Read
+
+		mov		al,[bp+IDEPACK.bCommand]
+
+		cmp		al,20h			; Read Sectors IDE command
+		jz		.readOrWrite
+		inc		ah				; now SerialServer_Protocol_Write
+		cmp		al,30h			; Write Sectors IDE command
+		jz		.readOrWrite
+
+;  all other commands return success
+;  including function 0ech which should return drive information, this is handled with the identify functions
+;
+		xor		ah,ah			;  also clears carry
+		ret
+
+.readOrWrite:
+		mov		[bp+IDEPACK.bFeatures],ah		; store protocol command
+				
+		mov		dx, [di+DPT_SERIAL.wSerialPortAndBaud]
+
+ALIGN JUMP_ALIGN
+SerialCommand_FallThroughToSerialServer_SendReceive:
+
+%include "SerialServer.asm"
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS		
+	%if SerialCommand_FallThroughToSerialServer_SendReceive <> SerialServer_SendReceive
+		%error "SerialServer_SendReceive must be the first routine at the top of SerialServer.asm in the Assembly_Library"
+	%endif
+%endif
+
+ALIGN JUMP_ALIGN		
+SerialCommand_ReturnError:		
+		stc
+		ret		
+
+;--------------------------------------------------------------------
+; SerialCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Select Register
+;		DS:		Segment to RAMVARS
+;		ES:SI:	Ptr to buffer to receive 512-byte IDE Information
+;		CS:BP:	Ptr to IDEVARS
+;	Returns:
+;		CF:		Cleared if success, Set if error
+;	Corrupts registers:
+;		AL, BL, CX, DX, SI, DI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+SerialCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH:
+;
+; To improve boot time, we do our best to avoid looking for slave serial drives when we already know the results
+; from the looking for a master.  This is particularly true when doing a COM port scan, as we will end up running
+; through all the COM ports and baud rates a second time.
+;
+; But drive detection isn't the only case - we also need to get the right drive when called on int13h/25h.
+;
+; The decision tree:
+;
+;    Master:
+;		   wSerialPortAndBaud Non-Zero:           -> Continue with wSerialPortAndBaud (1)
+;		   wSerialPortAndBaud Zero:
+;		       previous serial drive not found:   -> Scan (2)
+;		       previous serial drive found:       -> Continue with previous serial drive info (3)
+;
+;    Slave:
+;		   wSerialPortAndBaud Non-Zero:
+;		   	   previous serial drive not found:   -> Error - Not Found (4)
+;			   previous serial drive found:       -> Continue with wSerialPackedAndBaud (5)
+;          wSerialPortAndBaud Zero:
+;		   	   previous serial drive not found:	  -> Error - Not Found (4)
+;			   previous serial drive found:       -> Continue with previous serial drive info (6)
+;
+; (1) This was a port/baud that was explicitly set with the configurator.  In the drive detection case, as this
+;     is the Master, we are checking out a new controller, and so don't care if we already have a serial drive.
+;     And as with the int13h/25h case, we just go off and get the needed information using the user's setting.
+; (2) We are using the special .ideVarsSerialAuto structure.  During drive detection, we would only be here
+;     if we hadn't already seen a serial drive (since we only scan if no explicit drives are set),
+;     so we go off to scan.
+; (3) We are using the special .ideVarsSerialAuto structure.  We won't get here during drive detection, but
+;     we might get here on an int13h/25h call.  If we have scanned COM drives, they are the ONLY serial drives
+;     in use, and so we use the values from the previously seen serial drive DPT.
+; (4) No master has been found yet, therefore no slave should be found.  Avoiding the slave reduces boot time,
+;     especially in the full COM port scan case.  Note that this is different from the hardware IDE, where we
+;     will scan for a slave even if a master is not present.  Note that if ANY master had been previously found,
+;     we will do the slave scan, which isn't harmful, it just wastes time.  But the most common case (by a wide
+;     margin) will be just one serial controller.
+; (5) A COM port scan for a master had been previously completed, and a drive was found.  In a multiple serial
+;     controller scenario being called with int13h/25h, we need to use the value in bSerialPackedPortAndBaud
+;     to make sure we get the proper drive.
+; (6) A COM port scan for a master had been previously completed, and a drive was found.  We would only get here
+;     if no serial drive was explicitly set by the user in the configurator or that drive had not been found.
+;     Instead of performing the full COM port scan for the slave, use the port/baud value stored during the
+;     master scan.
+;
+		mov		dx,[cs:bp+IDEVARS.wSerialPortAndBaud]
+		xor		ax,ax
+		
+		push	si
+		call	FindDPT_ToDSDIforSerialDevice
+		pop		si
+%ifdef MODULE_SERIAL_FLOPPY
+		jnc		.founddpt
+;
+; If not found above with FindDPT_ToDSDIforSerialDevice, DI will point to the DPT after the last hard disk DPT
+; So, if there was a previously found floppy disk, DI will point to that DPT and we use that value for the slave.
+;
+		cmp		byte [RAMVARS.xlateVars+XLATEVARS.bFlopCntAndFirst], 0
+		jz		.notfounddpt
+.founddpt:
+%else
+		jc		.notfounddpt
+%endif
+		mov		ax, [di+DPT_SERIAL.wSerialPortAndBaud]
+.notfounddpt:
+
+		test	bh, FLG_DRVNHEAD_DRV
+		jz		.master
+
+		test	ax,ax			; Take care of the case that is different between master and slave.
+		jz		SerialCommand_ReturnError
+
+; fall-through
+.master:
+		test	dx,dx
+		jnz		.identifyDeviceInDX
+
+		xchg	dx, ax			;  move ax to dx (move previously found serial drive to dx, could be zero)
+
+.identifyDeviceInDX:
+
+ALIGN JUMP_ALIGN
+SerialCommand_FallThroughToSerialServerScan_ScanForServer:		
+		
+%include "SerialServerScan.asm"
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS				
+	%if SerialCommand_FallThroughToSerialServerScan_ScanForServer <> SerialServerScan_ScanForServer
+		%error "SerialServerScan_ScanForServer must be the first routine at the top of SerialServerScan.asm in the Assembly_Library"
+	%endif
+%endif
+
+
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Serial/SerialDPT.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Serial/SerialDPT.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Serial/SerialDPT.asm	(revision 352)
@@ -0,0 +1,37 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Sets Serial Device specific parameters to DPT.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; SerialDPT_Finalize
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		CF:		Set, indicates that this is a floppy disk
+;               Clear, indicates that this is a hard disk
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+SerialDPT_Finalize:
+		mov		ax, [es:si+SerialServer_ATA_wPortAndBaud]
+		mov		[di+DPT_SERIAL.wSerialPortAndBaud], ax
+
+;
+; Note that this section is not under %ifdef MODULE_SERIAL_FLOPPY.  It is important to 
+; distinguish floppy disks presented by the server and not treat them as hard disks, even
+; if the floppy support is disabled.
+;
+		mov		al, [es:si+SerialServer_ATA_wDriveFlags]
+		shl		al, 1
+		mov		byte [di+DPT.bFlagsHigh], al
+		
+		ret
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if FLGH_DPT_SERIAL_DEVICE != 0x4 || FLGH_DPT_SERIAL_FLOPPY != 0x10 || FLGH_DPT_SERIAL_FLOPPY_TYPE_MASK != 0xe0 || FLGH_DPT_SERIAL_FLOPPY_TYPE_FIELD_POSITION != 5
+		%error "The serial server passes FLGH values into SerialDPT_Finalize directly.  If the flag positions are changed, corresponding changes will need to be made in the serial server, and likely a version check put in to deal with servers talking to incompatible clients"
+	%endif
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Timer.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Timer.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Device/Timer.asm	(revision 352)
@@ -0,0 +1,118 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Timeout and delay functions for INT 13h services.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Timer_InitializeTimeoutWithTicksInCL
+;	Parameters:
+;		CL:		Timeout value in system timer ticks
+;		DS:		Segment to RAMVARS
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Timer_InitializeTimeoutWithTicksInCL:
+	mov		[RAMVARS.bTimeoutTicksLeft], cl		; Ticks until timeout
+	call	ReadTimeFromBdaToCX
+	mov		[RAMVARS.bLastTimeoutUpdate], cl	; Start time
+	ret
+
+
+;--------------------------------------------------------------------
+; Timer_SetCFifTimeout
+;	Parameters:
+;		DS:		Segment to RAMVARS
+;	Returns:
+;		CF:		Set if timeout
+;				Cleared if time left
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Timer_SetCFifTimeout:
+	call	ReadTimeFromBdaToCX
+	cmp		cl, [RAMVARS.bLastTimeoutUpdate]
+	je		SHORT .StillPollingTheSameTick
+	mov		[RAMVARS.bLastTimeoutUpdate], cl
+	sub		BYTE [RAMVARS.bTimeoutTicksLeft], 1	; DEC does not update CF
+.StillPollingTheSameTick:
+	ret
+
+
+;--------------------------------------------------------------------
+; Delay is always at least one millisecond since
+; RTC resolution is 977 microsecs.
+;
+; Timer_DelayMicrosecondsFromAX
+;	Parameters:
+;		AX:		Number of microsecs to wait
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+Timer_DelayMicrosecondsFromAX:
+%ifndef USE_AT
+	mov		ax, 2
+	; Fall to Timer_DelayTimerTicksFromAX
+%else
+	push	dx
+	push	cx
+
+	xor		cx, cx
+	xchg	dx, ax						; Microsecs now in CX:DX
+	mov		ah, EVENT_WAIT
+	int		BIOS_SYSTEM_INTERRUPT_15h
+	sti									; XT BIOSes return with interrupts disabled. TODO: Maybe we can remove this since it's in an AT-only block?
+
+	pop		cx
+	pop		dx
+	mov		ax, 1								; Prepare to wait 1 timer tick
+	jc		SHORT Timer_DelayTimerTicksFromAX	; Event Wait was unsupported or busy
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; First tick might take 0...54.9 ms and remaining ticks
+; will occur at 54.9 ms intervals.
+;
+; Timer_DelayTimerTicksFromAX
+;	Parameters:
+;		AX:		Number of timer ticks to wait
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+Timer_DelayTimerTicksFromAX:
+	sti								; Make sure that interrupts are enabled
+	call	ReadTimeFromBdaToCX
+	add		ax, cx					; AX = end time
+.WaitLoop:
+	call	ReadTimeFromBdaToCX
+	cmp		cx, ax
+	jne		SHORT .WaitLoop			; Loop until end time is reached
+	ret
+
+
+;--------------------------------------------------------------------
+; ReadTimeFromBdaToCX
+;	Parameters
+;		Nothing
+;	Returns:
+;		CX:		System time in 54.9 ms ticks
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+ReadTimeFromBdaToCX:
+	push	ds
+	LOAD_BDA_SEGMENT_TO	ds, cx
+	mov		cx, [BDA.dwTimerTicks]	; Read low WORD only
+	pop		ds
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h.asm	(revision 352)
@@ -0,0 +1,339 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h BIOS functions (Floppy and Hard disk).
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h software interrupt handler.
+; Jumps to specific function defined in AH.
+;
+; Note to developers: Do not make recursive INT 13h calls!
+;
+; Int13h_DiskFunctionsHandler
+;	Parameters:
+;		AH:		Bios function
+;		DL:		Drive number
+;		Other:	Depends on function
+;	Returns:
+;		Depends on function
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_DiskFunctionsHandler:
+	sti									; Enable interrupts
+	cld									; String instructions to increment pointers
+	CREATE_FRAME_INTPACK_TO_SSBP	EXTRA_BYTES_FOR_INTPACK
+
+	call	RamVars_GetSegmentToDS
+
+	call	DriveXlate_ToOrBack
+	mov		[RAMVARS.xlateVars+XLATEVARS.bXlatedDrv], dl
+
+	call	FindDPT_ForDriveNumberInDL	; DS:DI points to our DPT, or NULL if not our drive
+	jc		SHORT .NotOurDrive			; DPT not found so this is not one of our drives
+
+.OurFunction:
+	; Jump to correct BIOS function
+	eMOVZX	bx, ah
+	shl		bx, 1
+	cmp		ah, 25h						; Possible EBIOS function?
+%ifdef MODULE_EBIOS
+	ja		SHORT .JumpToEbiosFunction
+%else
+	ja		SHORT Int13h_UnsupportedFunction
+%endif
+	jmp		[cs:bx+g_rgw13hFuncJump]	; Jump to BIOS function
+
+%ifdef MODULE_EBIOS
+	; Jump to correct EBIOS function
+ALIGN JUMP_ALIGN
+.JumpToEbiosFunction:
+	test	BYTE [di+DPT.bFlagsLow], FLG_DRVNHEAD_LBA
+	jz		SHORT Int13h_UnsupportedFunction	; No eINT 13h for CHS drives
+	sub		bl, 41h<<1					; BX = Offset to eINT 13h jump table
+	jb		SHORT Int13h_UnsupportedFunction
+	cmp		ah, 48h
+	ja		SHORT Int13h_UnsupportedFunction
+	jmp		[cs:bx+g_rgwEbiosFunctionJumpTable]
+%endif
+
+ALIGN JUMP_ALIGN
+.NotOurDrive:
+	test	ah, ah
+	jz		SHORT .OurFunction			; We handle all function 0h requests (resets)
+
+%ifndef MODULE_SERIAL_FLOPPY
+; Without floppy support, we handle only hard disk traffic for function 08h.
+	test	dl, dl
+	jns		SHORT Int13h_DirectCallToAnotherBios
+%endif
+; With floppy support, we handle all traffic for function 08h, as we need to wrap both hard disk and floppy drive counts.
+	cmp		ah, 8
+	je		SHORT .OurFunction
+	; Fall to Int13h_DirectCallToAnotherBios
+
+;--------------------------------------------------------------------
+; Int13h_UnsupportedFunction
+; Int13h_DirectCallToAnotherBios
+;	Parameters:
+;		DL:		Translated drive number
+;		DS:		RAMVARS segment
+;		SS:BP:	Ptr to IDEPACK
+;		BX, DI:	Corrupted on Int13h_DiskFunctionsHandler
+;		Other:	Function specific INT 13h parameters
+;	Returns:
+;		Depends on function
+;	Corrupts registers:
+;		Flags
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_UnsupportedFunction:
+Int13h_DirectCallToAnotherBios:
+	call	ExchangeCurrentInt13hHandlerWithOldInt13hHandler
+	mov		bx, [bp+IDEPACK.intpack+INTPACK.bx]
+	mov		di, [bp+IDEPACK.intpack+INTPACK.di]
+	mov		ds, [bp+IDEPACK.intpack+INTPACK.ds]
+	push	WORD [bp+IDEPACK.intpack+INTPACK.flags]
+	popf
+	push	bp
+	mov		bp, [bp+IDEPACK.intpack+INTPACK.bp]
+	int		BIOS_DISK_INTERRUPT_13h	; Can safely do as much recursion as it wants
+
+	; Store returned values to INTPACK
+	pop		bp	; Standard INT 13h functions never uses BP as return register
+%ifdef USE_386
+;	mov		[bp+IDEPACK.intpack+INTPACK.gs], gs
+;	mov		[bp+IDEPACK.intpack+INTPACK.fs], fs
+%endif
+	mov		[bp+IDEPACK.intpack+INTPACK.es], es
+	mov		[bp+IDEPACK.intpack+INTPACK.ds], ds
+	mov		[bp+IDEPACK.intpack+INTPACK.di], di
+	mov		[bp+IDEPACK.intpack+INTPACK.si], si
+	mov		[bp+IDEPACK.intpack+INTPACK.bx], bx
+	mov		[bp+IDEPACK.intpack+INTPACK.dh], dh
+	mov		[bp+IDEPACK.intpack+INTPACK.cx], cx
+	mov		[bp+IDEPACK.intpack+INTPACK.ax], ax
+	pushf
+	pop		WORD [bp+IDEPACK.intpack+INTPACK.flags]
+	call	RamVars_GetSegmentToDS
+	cmp		dl, [RAMVARS.xlateVars+XLATEVARS.bXlatedDrv]
+	je		SHORT .ExchangeInt13hHandlers
+	mov		[bp+IDEPACK.intpack+INTPACK.dl], dl		; Something is returned in DL
+ALIGN JUMP_ALIGN
+.ExchangeInt13hHandlers:
+%ifdef USE_186
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+	jmp		SHORT ExchangeCurrentInt13hHandlerWithOldInt13hHandler
+%else
+	call	ExchangeCurrentInt13hHandlerWithOldInt13hHandler
+	jmp		SHORT Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%endif
+
+%ifdef MODULE_SERIAL_FLOPPY
+;--------------------------------------------------------------------
+; Int13h_ReturnSuccessForFloppy
+;
+; Some operations, such as format of a floppy disk track, should just
+; return success, while for hard disks it should be treated as unsupported.
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_ReturnSuccessForFloppy:
+	test	dl, dl
+	js		short Int13h_UnsupportedFunction
+	xor		ah, ah
+	jmp		short Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%endif
+
+;--------------------------------------------------------------------
+; Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAHandTransferredSectorsFromCL
+;	Parameters:
+;		AH:		BIOS Error code
+;		CL:		Number of sectors actually transferred
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		All registers are loaded from INTPACK
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAHandTransferredSectorsFromCL:
+	mov		[bp+IDEPACK.intpack+INTPACK.al], cl
+	; Fall to Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+
+;--------------------------------------------------------------------
+; Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+; Int13h_ReturnFromHandlerWithoutStoringErrorCode
+;	Parameters:
+;		AH:		BIOS Error code
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		All registers are loaded from INTPACK
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH:
+%ifdef MODULE_SERIAL_FLOPPY
+	mov		al, [bp+IDEPACK.intpack+INTPACK.dl]
+Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH_ALHasDriveNumber:
+	call	Int13h_SetErrorCodeToBdaAndToIntpackInSSBPfromAH_ALHasDriveNumber
+%else
+	call	Int13h_SetErrorCodeToBdaAndToIntpackInSSBPfromAH
+%endif
+Int13h_ReturnFromHandlerWithoutStoringErrorCode:
+	or		WORD [bp+IDEPACK.intpack+INTPACK.flags], FLG_FLAGS_IF	; Return with interrupts enabled
+	mov		sp, bp									; Now we can exit anytime
+	RESTORE_FRAME_INTPACK_FROM_SSBP		EXTRA_BYTES_FOR_INTPACK
+
+
+;--------------------------------------------------------------------
+; Int13h_CallPreviousInt13hHandler
+;	Parameters:
+;		AH:		INT 13h function to call
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		Depends on function
+;       NOTE: ES:DI needs to be returned from the previous interrupt
+;		      handler, for floppy DPT in function 08h
+;	Corrupts registers:
+;		None
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int13h_CallPreviousInt13hHandler:
+	call	ExchangeCurrentInt13hHandlerWithOldInt13hHandler
+	int		BIOS_DISK_INTERRUPT_13h
+;;;  fall-through to ExchangeCurrentInt13hHandlerWithOldInt13hHandler
+
+;--------------------------------------------------------------------
+; ExchangeCurrentInt13hHandlerWithOldInt13hHandler
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;       Nothing
+;       Note: Flags are preserved
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+ExchangeCurrentInt13hHandlerWithOldInt13hHandler:
+	push	es
+	push	si
+	LOAD_BDA_SEGMENT_PRESERVE_FLAGS_TO	es, si
+	mov		si, [RAMVARS.fpOldI13h]
+	cli
+	xchg	si, [es:BIOS_DISK_INTERRUPT_13h*4]
+	mov		[RAMVARS.fpOldI13h], si
+	mov		si, [RAMVARS.fpOldI13h+2]
+	xchg	si, [es:BIOS_DISK_INTERRUPT_13h*4+2]
+	sti
+	mov		[RAMVARS.fpOldI13h+2], si
+	pop		si
+	pop		es
+	ret
+
+
+;--------------------------------------------------------------------
+; Int13h_SetErrorCodeToBdaAndToIntpackInSSBPfromAH
+; Int13h_SetErrorCodeToIntpackInSSBPfromAH
+;	Parameters:
+;		AH:		BIOS error code (00h = no error)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		SS:BP:	Ptr to IDEPACK with error condition set
+;	Corrupts registers:
+;		DS, DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+%ifdef MODULE_SERIAL_FLOPPY
+Int13h_SetErrorCodeToBdaAndToIntpackInSSBPfromAH_ALHasDriveNumber:
+	; Store error code to BDA
+	mov		bx, BDA.bHDLastSt
+	test	al, al
+	js		.HardDisk
+	mov		bl, BDA.bFDRetST & 0xff
+.HardDisk:
+	LOAD_BDA_SEGMENT_TO	ds, di
+	mov		[bx], ah
+%else
+Int13h_SetErrorCodeToBdaAndToIntpackInSSBPfromAH:
+	; Store error code to BDA
+	LOAD_BDA_SEGMENT_TO	ds, di
+	mov		[BDA.bHDLastSt], ah
+%endif
+
+	; Store error code to INTPACK
+Int13h_SetErrorCodeToIntpackInSSBPfromAH:
+	mov		[bp+IDEPACK.intpack+INTPACK.ah], ah
+	test	ah, ah
+	jnz		SHORT .SetCFtoIntpack
+	and		BYTE [bp+IDEPACK.intpack+INTPACK.flags], ~FLG_FLAGS_CF
+	ret
+.SetCFtoIntpack:
+	or		BYTE [bp+IDEPACK.intpack+INTPACK.flags], FLG_FLAGS_CF
+	ret
+
+
+; Jump table for correct BIOS function
+ALIGN WORD_ALIGN
+g_rgw13hFuncJump:
+	dw	AH0h_HandlerForDiskControllerReset				; 00h, Disk Controller Reset (All)
+	dw	AH1h_HandlerForReadDiskStatus					; 01h, Read Disk Status (All)
+	dw	AH2h_HandlerForReadDiskSectors					; 02h, Read Disk Sectors (All)
+	dw	AH3h_HandlerForWriteDiskSectors					; 03h, Write Disk Sectors (All)
+	dw	AH4h_HandlerForVerifyDiskSectors				; 04h, Verify Disk Sectors (All)
+%ifdef MODULE_SERIAL_FLOPPY
+	dw	Int13h_ReturnSuccessForFloppy					; 05h, Format Disk Track (XT, AT, EISA)
+%else
+	dw	Int13h_UnsupportedFunction						; 05h, Format Disk Track (XT, AT, EISA)
+%endif
+	dw	Int13h_UnsupportedFunction						; 06h, Format Disk Track with Bad Sectors (XT)
+	dw	Int13h_UnsupportedFunction						; 07h, Format Multiple Cylinders (XT)
+	dw	AH8h_HandlerForReadDiskDriveParameters			; 08h, Read Disk Drive Parameters (All)
+	dw	AH9h_HandlerForInitializeDriveParameters		; 09h, Initialize Drive Parameters (All)
+	dw	Int13h_UnsupportedFunction						; 0Ah, Read Disk Sectors with ECC (XT, AT, EISA)
+	dw	Int13h_UnsupportedFunction						; 0Bh, Write Disk Sectors with ECC (XT, AT, EISA)
+	dw	AHCh_HandlerForSeek								; 0Ch, Seek (All)
+	dw	AHDh_HandlerForResetHardDisk					; 0Dh, Alternate Disk Reset (All)
+	dw	Int13h_UnsupportedFunction						; 0Eh, Read Sector Buffer (XT, PS/1), ESDI Undocumented Diagnostic (PS/2)
+	dw	Int13h_UnsupportedFunction						; 0Fh, Write Sector Buffer (XT, PS/1), ESDI Undocumented Diagnostic (PS/2)
+	dw	AH10h_HandlerForCheckDriveReady					; 10h, Check Drive Ready (All)
+	dw	AH11h_HandlerForRecalibrate						; 11h, Recalibrate (All)
+	dw	Int13h_UnsupportedFunction						; 12h, Controller RAM Diagnostic (XT)
+	dw	Int13h_UnsupportedFunction						; 13h, Drive Diagnostic (XT)
+	dw	Int13h_UnsupportedFunction						; 14h, Controller Internal Diagnostic (All)
+	dw	AH15h_HandlerForReadDiskDriveSize				; 15h, Read Disk Drive Size (AT+)
+	dw	Int13h_UnsupportedFunction						; 16h,
+	dw	Int13h_UnsupportedFunction						; 17h,
+	dw	Int13h_UnsupportedFunction						; 18h,
+	dw	Int13h_UnsupportedFunction						; 19h, Park Heads (PS/2)
+	dw	Int13h_UnsupportedFunction						; 1Ah, Format ESDI Drive (PS/2)
+	dw	Int13h_UnsupportedFunction						; 1Bh, Get ESDI Manufacturing Header (PS/2)
+	dw	Int13h_UnsupportedFunction						; 1Ch, ESDI Special Functions (PS/2)
+	dw	Int13h_UnsupportedFunction						; 1Dh,
+	dw	Int13h_UnsupportedFunction						; 1Eh,
+	dw	Int13h_UnsupportedFunction						; 1Fh,
+	dw	Int13h_UnsupportedFunction						; 20h,
+	dw	Int13h_UnsupportedFunction						; 21h, Read Disk Sectors, Multiple Blocks (PS/1)
+	dw	Int13h_UnsupportedFunction						; 22h, Write Disk Sectors, Multiple Blocks (PS/1)
+	dw	AH23h_HandlerForSetControllerFeatures			; 23h, Set Controller Features Register (PS/1)
+	dw	AH24h_HandlerForSetMultipleBlocks				; 24h, Set Multiple Blocks (PS/1)
+	dw	AH25h_HandlerForGetDriveInformation				; 25h, Get Drive Information (PS/1)
+
+%ifdef MODULE_EBIOS
+g_rgwEbiosFunctionJumpTable:
+	dw	AH41h_HandlerForCheckIfExtensionsPresent		; 41h, Check if Extensions Present (EBIOS)*
+	dw	AH42h_HandlerForExtendedReadSectors				; 42h, Extended Read Sectors (EBIOS)*
+	dw	AH43h_HandlerForExtendedWriteSectors			; 43h, Extended Write Sectors (EBIOS)*
+	dw	AH44h_HandlerForExtendedVerifySectors			; 44h, Extended Verify Sectors (EBIOS)*
+	dw	Int13h_UnsupportedFunction						; 45h, Lock and Unlock Drive (EBIOS)***
+	dw	Int13h_UnsupportedFunction						; 46h, Eject Media Request (EBIOS)***
+	dw	AH47h_HandlerForExtendedSeek					; 47h, Extended Seek (EBIOS)*
+	dw	AH48h_HandlerForGetExtendedDriveParameters		; 48h, Get Extended Drive Parameters (EBIOS)*
+;	dw	Int13h_UnsupportedFunction						; 49h, Get Extended Disk Change Status (EBIOS)***
+;	dw	Int13h_UnsupportedFunction						; 4Ah, Initiate Disk Emulation (Bootable CD-ROM)
+;	dw	Int13h_UnsupportedFunction						; 4Bh, Terminate Disk Emulation (Bootable CD-ROM)
+;	dw	Int13h_UnsupportedFunction						; 4Ch, Initiate Disk Emulation and Boot (Bootable CD-ROM)
+;	dw	Int13h_UnsupportedFunction						; 4Dh, Return Boot Catalog (Bootable CD-ROM)
+;	dw	Int13h_UnsupportedFunction						; 4Eh, Set Hardware Configuration (EBIOS)**
+;
+;   * = Enhanced Drive Access Support (minimum required EBIOS functions)
+;  ** = Enhanced Disk Drive (EDD) Support
+; *** = Drive Locking and Ejecting Support
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH0h_HReset.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH0h_HReset.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH0h_HReset.asm	(revision 352)
@@ -0,0 +1,179 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=0h, Disk Controller Reset.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=0h, Disk Controller Reset.
+;
+; Note: We handle all AH=0h calls, even for drives handled by other
+; BIOSes!
+;
+; AH0h_HandlerForDiskControllerReset
+;	Parameters:
+;		DL:		Translated Drive number (ignored so all drives are reset)
+;				If bit 7 is set all hard disks and floppy disks reset.
+;		DS:DI:	Ptr to DPT (or Null if foreign drive)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns with INTPACK:
+;		AH:		Int 13h return status (from drive requested in DL)
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH0h_HandlerForDiskControllerReset:
+	eMOVZX	bx, dl						; Copy requested drive to BL, zero BH to assume no errors
+	call	ResetFloppyDrivesWithInt40h
+
+%ifdef MODULE_SERIAL_FLOPPY
+;
+; "Reset" emulated serial floppy drives, if any.  There is nothing to actually do for this reset,
+; but record the proper error return code if one of these floppy drives is the drive requested.
+;
+	call	RamVars_UnpackFlopCntAndFirstToAL
+	cbw													; Clears AH (there are flop drives) or ffh (there are not)
+														; Either AH has success code (flop drives are present)
+														; or it doesn't matter because we won't match drive ffh
+
+	cwd													; clears DX (there are flop drives) or ffffh (there are not)
+
+	adc		dl, al										; second drive (CF set) if present
+														; If no drive is present, this will result in ffh which
+														; won't match a drive
+	call	BackupErrorCodeFromTheRequestedDriveToBH
+	mov		dl, al										; We may end up doing the first drive twice (if there is
+	call	BackupErrorCodeFromTheRequestedDriveToBH	; only one drive), but doing it again is not harmful.
+%endif
+
+	test	bl, bl										; If we were called with a floppy disk, then we are done,
+	jns		SHORT .SkipHardDiskReset					; don't do hard disks.
+
+	call	ResetForeignHardDisks
+
+	; Resetting our hard disks will modify dl and bl to be idevars offset based instead of drive number based,
+	; such that this call must be the last in the list of reset routines called.
+	;
+	; This needs to happen after ResetForeignHardDisks, as that call may have set the error code for 80h,
+	; and we need to override that value if we are xlate'd into 80h with one of our drives.
+	;
+	call	ResetHardDisksHandledByOurBIOS
+
+.SkipHardDiskReset:
+	mov		ah, bh
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+
+
+;--------------------------------------------------------------------
+; ResetFloppyDrivesWithInt40h
+;	Parameters:
+;		BL:		Requested drive (DL when entering AH=00h)
+;	Returns:
+;		BH:		Error code from requested drive (if available)
+;	Corrupts registers:
+;		AX, DL, DI
+;--------------------------------------------------------------------
+ResetFloppyDrivesWithInt40h:
+	call	GetDriveNumberForForeignHardDiskHandlerToDL
+	and		dl, 7Fh						; Clear hard disk bit
+	xor		ah, ah						; Disk Controller Reset
+	int		BIOS_DISKETTE_INTERRUPT_40h
+	jmp		SHORT BackupErrorCodeFromTheRequestedDriveToBH
+
+
+;--------------------------------------------------------------------
+; ResetForeignHardDisks
+;	Parameters:
+;		BL:		Requested drive (DL when entering AH=00h)
+;		DS:		RAMVARS segment
+;	Returns:
+;		BH:		Error code from requested drive (if available)
+;	Corrupts registers:
+;		AX, DL, DI
+;--------------------------------------------------------------------
+ResetForeignHardDisks:
+	call	GetDriveNumberForForeignHardDiskHandlerToDL
+	xor		ah, ah						; Disk Controller Reset
+	call	Int13h_CallPreviousInt13hHandler
+;;; fall-through to BackupErrorCodeFromTheRequestedDriveToBH
+
+
+;--------------------------------------------------------------------
+; BackupErrorCodeFromTheRequestedDriveToBH
+;	Parameters:
+;		AH:		Error code from the last resetted drive
+;		DL:		Drive last resetted
+;		BL:		Requested drive (DL when entering AH=00h)
+;	Returns:
+;		BH:		Backuped error code
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+BackupErrorCodeFromTheRequestedDriveToBH:
+	cmp		dl, bl				; Requested drive?
+	eCMOVE	bh, ah
+	ret
+
+
+;--------------------------------------------------------------------
+; GetDriveNumberForForeignHardDiskHandlerToDL
+;	Parameters:
+;		BL:		Requested drive (DL when entering AH=00h)
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to DPT if our drive (or Null if foreign drive)
+;		DL:		BL if foreign drive
+;				80h if our drive
+;--------------------------------------------------------------------
+GetDriveNumberForForeignHardDiskHandlerToDL:
+	mov		dl, bl
+	test	di, di
+	jz		SHORT .Return
+	mov		dl, 80h				; First possible Hard Disk should be safe value
+.Return:
+	ret
+
+AH0h_ResetAllOurHardDisksAtTheEndOfDriveInitialization equ ResetHardDisksHandledByOurBIOS.ErrorCodeNotUsed
+
+;--------------------------------------------------------------------
+; ResetHardDisksHandledByOurBIOS
+;	Parameters:
+;		DS:DI:	Ptr to DPT for requested drive
+;				If DPT pointer is not available, or error result in BH won't be used anyway,
+;				enter through .ErrorCodeNotUsed.
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		BH:		Error code from requested drive (if available)
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+ResetHardDisksHandledByOurBIOS:
+	xor		bl, bl										; Assume Null IdevarsOffset for now, assuming foreign drive
+	test	di, di
+	jz		.ErrorCodeNotUsed
+	mov		bl, [di+DPT.bIdevarsOffset]					; replace drive number with Idevars pointer for cmp with dl
+
+.ErrorCodeNotUsed:										; BH will be garbage on exit if this entry point is used,
+														; but reset of all drives will still happen
+
+	mov		dl, ROMVARS.ideVars0						; starting Idevars offset
+
+    ; Get count of ALL Idevars structures, not just the ones that are configured.  This may seem odd, 
+    ; but it catches the .ideVarsSerialAuto structure, which would not be scanned if the count from
+	; RamVars_GetIdeControllerCountToCX was used.  Unused controllers won't make a difference, since no DPT
+	; will point to them.  Performance isn't an issue, as this is a reset operation.
+    ;
+	mov		cx, (ROMVARS.ideVarsEnd - ROMVARS.ideVarsBegin) / IDEVARS_size
+
+.loop:
+	call	FindDPT_ForIdevarsOffsetInDL				; look for the first drive on this controller, if any
+	jc		.notFound
+
+	call	AHDh_ResetDrive								; reset master and slave on that controller
+	call	BackupErrorCodeFromTheRequestedDriveToBH	; save error code if same controller as drive from entry
+
+.notFound:
+	add		dl, IDEVARS_size							; move Idevars pointer forward
+	loop	.loop
+
+.done:
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH10h_HReady.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH10h_HReady.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH10h_HReady.asm	(revision 352)
@@ -0,0 +1,27 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=10h, Check Drive Ready.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=10h, Check Drive Ready.
+;
+; AH10h_HandlerForCheckDriveReady
+;	Parameters:
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEREGS_AND_INTPACK
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH10h_HandlerForCheckDriveReady:
+%ifdef USE_186
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+	jmp		Device_SelectDrive
+%else
+	call	Device_SelectDrive
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH11h_HRecal.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH11h_HRecal.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH11h_HRecal.asm	(revision 352)
@@ -0,0 +1,46 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=11h, Recalibrate.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=11h, Recalibrate.
+;
+; AH11h_HandlerForRecalibrate
+;	Parameters:
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEREGS_AND_INTPACK
+;	Returns with INTPACK:
+;		AH:		BIOS Error code
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH11h_HandlerForRecalibrate:
+%ifndef USE_186
+	call	AH11h_RecalibrateDrive
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%else
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+	; Fall to AH11h_RecalibrateDrive
+%endif
+
+
+;--------------------------------------------------------------------
+; AH11h_HRecalibrate
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEREGS_AND_INTPACK
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if successful, 1 if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+AH11h_RecalibrateDrive:
+	; Recalibrate command is optional, vendor specific and not even
+	; supported on later ATA-standards. Let's do seek instead.
+	mov		cx, 1						; Seek to Cylinder 0, Sector 1
+	xor		dh, dh						; Head 0
+	jmp		AHCh_SeekToCylinder
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH15h_HSize.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH15h_HSize.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH15h_HSize.asm	(revision 352)
@@ -0,0 +1,85 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=15h, Read Disk Drive Size.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=15h, Read Disk Drive Size.
+;
+; AH15h_HandlerForReadDiskDriveSize
+;	Parameters:
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns with INTPACK:
+;		If successful:
+;			AH:		Hard Disk: 3 (Hard disk accessible)
+;                   Floppy:    1 (Floppy disk, without change detection)
+;			CX:DX:	Total number of sectors
+;			CF:		0
+;		If failed:
+;			AH:		0 (Drive not present)
+;			CX:DX:	0
+;			CF:		1
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH15h_HandlerForReadDiskDriveSize:
+%ifdef MODULE_SERIAL_FLOPPY
+	mov		cl, 1										; 1 = floppy disk, no change detection
+
+	test	dl,dl										; DO NOT store the sector count if this is a
+	jns		.FloppyDrive								; floppy disk, some OS's depend on this not
+														; happening for floppies in order to boot.
+%endif
+
+	call	AH15h_GetSectorCountToBXDXAX
+	mov		[bp+IDEPACK.intpack+INTPACK.cx], dx			; HIWORD to CX
+	xchg	[bp+IDEPACK.intpack+INTPACK.dx], ax			; LOWORD to DX, AL gets drive number
+
+	xor		ah, ah
+%ifdef MODULE_SERIAL_FLOPPY
+	mov		cl, 3										; 3 = Hard Disk Accessible
+.FloppyDrive:
+
+	call	Int13h_SetErrorCodeToBdaAndToIntpackInSSBPfromAH_ALHasDriveNumber	; Store success to BDA and CF
+	mov		[bp+IDEPACK.intpack+INTPACK.ah], cl
+%else
+	call	Int13h_SetErrorCodeToBdaAndToIntpackInSSBPfromAH	; Store success to BDA and CF
+	mov		BYTE [bp+IDEPACK.intpack+INTPACK.ah], 3
+%endif
+
+	jmp		Int13h_ReturnFromHandlerWithoutStoringErrorCode
+
+
+;--------------------------------------------------------------------
+; AH15h_GetSectorCountFromForeignDriveToDXAX:
+; AH15h_GetSectorCountToBXDXAX:
+;	Parameters:
+;		DL:		Drive number (AH15h_GetSectorCountFromForeignDriveToDXAX only)
+;		DS:		RAMVARS segment
+;		DS:DI:	Ptr to DPT (AH15h_GetSectorCountToDXAX only)
+;	Returns:
+;		DX:AX:	Total sector count
+;		BX:		Zero
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+AH15h_GetSectorCountFromForeignDriveToDXAX:
+	mov		ah, GET_DRIVE_PARAMETERS
+	call	Int13h_CallPreviousInt13hHandler
+	jmp		SHORT ConvertAH08hReturnValuesToSectorCount
+
+AH15h_GetSectorCountToBXDXAX:
+	call	AH8h_GetDriveParameters
+	; Fall to ConvertAH08hReturnValuesToSectorCount
+
+ConvertAH08hReturnValuesToSectorCount:
+	call	Address_ExtractLCHSparametersFromOldInt13hAddress
+	mov		al, bh		; AL = Max head number
+	inc		cx			; Max cylinder number to cylinder count
+	inc		ax			; Max head number to head count (AH=8h returns max 254 so no overflow to AH)
+	mul		bl			; AX = Head count * Sectors per track
+	mul		cx			; DX:AX = Total sector count for AH=0xh transfer functions
+	xor		bx, bx
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH1h_HStatus.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH1h_HStatus.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH1h_HStatus.asm	(revision 352)
@@ -0,0 +1,40 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=1h, Read Disk Status.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=1h, Read Disk Status.
+;
+; AH1h_HandlerForReadDiskStatus
+;	Parameters:
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEREGS_AND_INTPACK
+;	Returns with INTPACK:
+;		AH:		Int 13h floppy return status
+;		CF:		0 if AH = RET_HD_SUCCESS, 1 otherwise (error)
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH1h_HandlerForReadDiskStatus:
+	LOAD_BDA_SEGMENT_TO	ds, ax, !
+
+%ifdef MODULE_SERIAL_FLOPPY
+	test	dl, dl
+	js		.HardDisk
+	mov		ah, [BDA.bFDRetST]	; Unlike for hard disks below, floppy version does not clear the status
+	jmp		.done
+.HardDisk:
+%endif
+
+	xchg	ah, [BDA.bHDLastSt]	; Load and clear last error (AH is cleared with the LOAD_BDA_SEGMENT_TO above)
+
+.done:
+%ifndef USE_186
+	call	Int13h_SetErrorCodeToIntpackInSSBPfromAH
+	jmp		Int13h_ReturnFromHandlerWithoutStoringErrorCode
+%else
+	push	Int13h_ReturnFromHandlerWithoutStoringErrorCode
+	jmp		Int13h_SetErrorCodeToIntpackInSSBPfromAH
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH23h_HFeatures.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH23h_HFeatures.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH23h_HFeatures.asm	(revision 352)
@@ -0,0 +1,61 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=23h,
+;					Set Controller Features Register.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=23h, Set Controller Features Register.
+;
+; AH23h_HandlerForSetControllerFeatures
+;	Parameters:
+;		AL, CX:	Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		AL:		Feature Number (parameter to Features Register = subcommand)
+;	(Parameter registers are undocumented, these are specific for this BIOS):
+;		BL:		Parameter to Sector Count Register (subcommand specific)
+;		BH:		Parameter to LBA Low / Sector Number Register (subcommand specific)
+;		CL:		Parameter to LBA Middle / Cylinder Low Register (subcommand specific)
+;		CH:		Parameter to LBA High / Cylinder High Register (subcommand specific)
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH23h_HandlerForSetControllerFeatures:
+	xchg	si, ax		; SI = Feature Number
+	mov		dx, [bp+IDEPACK.intpack+INTPACK.bx]
+%ifndef USE_186
+	call	AH23h_SetControllerFeatures
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%else
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+	; Fall to AH23h_SetControllerFeatures
+%endif
+
+
+;--------------------------------------------------------------------
+; AH23h_SetControllerFeatures
+;	Parameters:
+;		DL:		Parameter to Sector Count Register (subcommand specific)
+;		DH:		Parameter to LBA Low / Sector Number Register (subcommand specific)
+;		CL:		Parameter to LBA Middle / Cylinder Low Register (subcommand specific)
+;		CH:		Parameter to LBA High / Cylinder High Register (subcommand specific)
+;		SI:		Feature Number (parameter to Features Register = subcommand)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+;ALIGN JUMP_ALIGN
+AH23h_SetControllerFeatures:
+	mov		al, COMMAND_SET_FEATURES
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_BSY, FLG_STATUS_BSY)
+	jmp		Idepack_StoreNonExtParametersAndIssueCommandFromAL
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH24h_HSetBlocks.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH24h_HSetBlocks.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH24h_HSetBlocks.asm	(revision 352)
@@ -0,0 +1,57 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=24h, Set Multiple Blocks.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=24h, Set Multiple Blocks.
+;
+; AH24h_HandlerForSetMultipleBlocks
+;	Parameters:
+;		AL:		Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		AL:		Number of Sectors per Block (1, 2, 4, 8, 16, 32, 64 or 128)
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+AH24h_HandlerForSetMultipleBlocks:
+%ifndef USE_186
+	call	AH24h_SetBlockSize
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%else
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+	; Fall to AH24h_SetBlockSize
+%endif
+
+
+;--------------------------------------------------------------------
+; AH24h_SetBlockSize
+;	Parameters:
+;		AL:		Number of Sectors per Block (1, 2, 4, 8, 16, 32, 64 or 128)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+AH24h_SetBlockSize:
+	push	ax
+	xchg	dx, ax			; DL = Block size (Sector Count Register)
+	or		BYTE [di+DPT.bFlagsHigh], FLGH_DPT_BLOCK_MODE_SUPPORTED	; Assume success
+	mov		al, COMMAND_SET_MULTIPLE_MODE
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRDY, FLG_STATUS_DRDY)
+	call	Idepack_StoreNonExtParametersAndIssueCommandFromAL
+	pop		bx
+	jnc		.StoreBlockSize
+	mov		bl, 1	; Disable block mode
+	and		BYTE [di+DPT.bFlagsHigh], ~FLGH_DPT_BLOCK_MODE_SUPPORTED
+.StoreBlockSize:	; Store new block size to DPT and return
+	mov		[di+DPT_ATA.bSetBlock], bl
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH25h_HDrvID.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH25h_HDrvID.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH25h_HDrvID.asm	(revision 352)
@@ -0,0 +1,33 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=25h, Get Drive Information.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=25h, Get Drive Information.
+;
+; AH25h_HandlerForGetDriveInformation
+;	Parameters:
+;		ES:		Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		ES:BX:	Ptr to buffer to receive 512-byte drive information
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH25h_HandlerForGetDriveInformation:
+	mov		ax, (COMMAND_IDENTIFY_DEVICE << 8 | 1)		; Read 1 sector
+	call	Prepare_BufferToESSIforOldInt13hTransfer	; Preserves AX
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
+%ifdef USE_186
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+	jmp		Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH
+%else
+	call	Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH2h_HRead.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH2h_HRead.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH2h_HRead.asm	(revision 352)
@@ -0,0 +1,42 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=2h, Read Disk Sectors.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=2h, Read Disk Sectors.
+;
+; AH2h_HandlerForReadDiskSectors
+;	Parameters:
+;		AL, CX, DH, ES:	Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		AL:		Number of sectors to read (1...128)
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		ES:BX:	Pointer to buffer receiving data
+;	Returns with INTPACK:
+;		AH:		Int 13h/40h floppy return status
+;		AL:		Burst error length if AH returns 11h (we never return error code 11h)
+;				Number of sectors actually read (only valid if CF set for someBIOSes)
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH2h_HandlerForReadDiskSectors:
+	call	Prepare_BufferToESSIforOldInt13hTransfer
+	call	Prepare_GetOldInt13hCommandIndexToBX
+	mov		ah, [cs:bx+g_rgbReadCommandLookup]
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
+%ifdef USE_186
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAHandTransferredSectorsFromCL
+	jmp		Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH
+%else
+	call	Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAHandTransferredSectorsFromCL
+%endif
+
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH3h_HWrite.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH3h_HWrite.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH3h_HWrite.asm	(revision 352)
@@ -0,0 +1,40 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=3h, Write Disk Sectors.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=3h, Write Disk Sectors.
+;
+; AH3h_HandlerForWriteDiskSectors
+;	Parameters:
+;		AL, CX, DH, ES:	Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEREGS_AND_INTPACK
+;	Parameters on INTPACK:
+;		AL:		Number of sectors to write (1...128)
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		ES:BX:	Pointer to source data
+;	Returns with INTPACK:
+;		AH:		Int 13h/40h floppy return status
+;		AL:		Number of sectors actually written (only valid if CF set for someBIOSes)
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH3h_HandlerForWriteDiskSectors:
+	call	Prepare_BufferToESSIforOldInt13hTransfer
+	call	Prepare_GetOldInt13hCommandIndexToBX
+	mov		ah, [cs:bx+g_rgbWriteCommandLookup]
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
+%ifdef USE_186
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAHandTransferredSectorsFromCL
+	jmp		Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH
+%else
+	call	Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAHandTransferredSectorsFromCL
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH4h_HVerify.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH4h_HVerify.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH4h_HVerify.asm	(revision 352)
@@ -0,0 +1,38 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=4h, Verify Disk Sectors.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=4h, Verify Disk Sectors.
+;
+; AH4h_HandlerForVerifyDiskSectors
+;	Parameters:
+;		AL, CX, DH:	Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to INTPACK
+;	Parameters on INTPACK in SS:BP:
+;		AL:		Number of sectors to verify (1...128)
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;	Returns with INTPACK in SS:BP:
+;		AH:		Int 13h/40h floppy return status
+;		AL:		Number of sectors actually verified (only valid if CF set for someBIOSes)
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH4h_HandlerForVerifyDiskSectors:
+	mov		ah, COMMAND_VERIFY_SECTORS
+	call	Prepare_ByValidatingSectorsInALforOldInt13h	; Preserves AX
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRDY)
+%ifdef USE_186
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAHandTransferredSectorsFromCL
+	jmp		Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH
+%else
+	call	Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAHandTransferredSectorsFromCL
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH8h_HParams.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH8h_HParams.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH8h_HParams.asm	(revision 352)
@@ -0,0 +1,174 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=8h, Read Disk Drive Parameters.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=8h, Read Disk Drive Parameters.
+;
+; AH8h_HandlerForReadDiskDriveParameters
+;	Parameters:
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns with INTPACK:
+;       BL:     Drive Type (for floppies only)
+;		CH:		Maximum cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9...8
+;				Bits 5...0:	Maximum sector number (1...63)
+;		DH:		Maximum head number (0...254)
+;		DL:		Number of drives
+;       ES:DI:  Floppy DPT (for floppies only)
+;		AH:		Int 13h/40h floppy return status
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+AH8h_HandlerForReadDiskDriveParameters:
+	test	di, di
+	jz		SHORT .NotOurDrive
+
+	call	AH8h_GetDriveParameters
+
+%ifdef MODULE_SERIAL_FLOPPY
+	push	cs							; setup registers if we are a floppy drive, in all cases
+	pop		es							; if it is not a floppy drive, these values will not be put in INTPACK
+	mov		di, AH8h_FloppyDPT
+%endif
+	;; fall-through
+
+.MidGame:
+	call	RamVars_GetCountOfKnownDrivesToAX		; assume hard disk for now, will discard if for floppies
+
+	test	byte [bp+IDEPACK.intpack+INTPACK.dl], 080h
+	jnz		.Done
+
+	mov		[bp+IDEPACK.intpack+INTPACK.bl], bl
+
+	mov		[bp+IDEPACK.intpack+INTPACK.es], es
+	mov		[bp+IDEPACK.intpack+INTPACK.di], di
+
+	call	FloppyDrive_GetCountToAX
+
+.Done:
+	mov		ah, dh
+
+	mov		[bp+IDEPACK.intpack+INTPACK.cx], cx
+	xchg	[bp+IDEPACK.intpack+INTPACK.dx], ax		; recover DL for BDA last status byte determination
+
+	xor		ah, ah
+%ifdef MODULE_SERIAL_FLOPPY
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH_ALHasDriveNumber
+%else
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%endif
+
+.NotOurDrive:
+	call	Int13h_CallPreviousInt13hHandler
+	jnc		SHORT .MidGame
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+
+
+;--------------------------------------------------------------------
+; Returns L-CHS parameters for drive and total hard disk count.
+;
+; AH8h_GetDriveParameters
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		CH:		Maximum cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9...8
+;				Bits 5...0:	Maximum sector number (1...63)
+;		DH:		Maximum head number (0...254)
+;	Corrupts registers:
+;		AX, BX
+;--------------------------------------------------------------------
+AH8h_GetDriveParameters:
+	call	AccessDPT_GetLCHStoAXBLBH
+	; Fall to .PackReturnValues
+
+;--------------------------------------------------------------------
+; Packs L-CHS values to INT 13h, AH=08h return values.
+;
+; .PackReturnValues
+;	Parameters:
+;		AX:		Number of L-CHS cylinders available (1...1024)
+;		BL:		Number of L-CHS heads (1...255)
+;		BH:		Number of L-CHS sectors per track (1...63)
+;		DS:		RAMVARS segment
+;	Returns:
+;		CH:		Maximum cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9...8
+;				Bits 5...0:	Maximum sector number (1...63)
+;		DH:		Maximum head number (0...254)
+;	Corrupts registers:
+;		AX, BX
+;--------------------------------------------------------------------
+.PackReturnValues:
+	dec		ax						; AX = Number of last cylinder
+	dec		bx						; BL = Number of last head
+	xchg	cx, ax
+	xchg	cl, ch					; CH = Last cylinder bits 0...7
+	eROR_IM	cl, 2					; CL bits 6...7 = Last cylinder bits 8...9
+	or		cl, bh					; CL bits 0...5 = Sectors per track
+	mov		dh, bl					; DH = Maximum head number
+
+%ifdef MODULE_SERIAL_FLOPPY
+	mov		bl, [di+DPT.bFlagsHigh]
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS             ; not sure why this is needed for preprocessor-only
+	eSHR_IM	bl, FLGH_DPT_SERIAL_FLOPPY_TYPE_FIELD_POSITION
+%endif
+%endif
+	ret
+
+%ifdef MODULE_SERIAL_FLOPPY
+;
+; Floppy Disk Parameter Table.  There is no way to specify more than one of these
+; for any given system, so no way to make this drive or media specific.
+; So we return fixed values out of the ROM for callers who might be expecting this information.
+;
+; On AT systems, we return the information for a 1.44 MB disk,
+; and on XT systems, we return the information for a 360 KB disk.
+;
+AH8h_FloppyDPT:
+%ifdef USE_AT
+	db		0ah << 4 | 0fh			; Offset 0: Drive timings, 1.44MB values
+%else
+	db		0dh << 4 | 0fh			; Offset 0: Drive timings, 360KB values
+%endif
+
+	db		1h << 1 | 0				; Offset 1: Typical values of 1 for head load time
+									;           DMA used (although it actually is not, but is more restrictive)
+	db		25h						; Offset 2: Inactivity motor turn-off delay,
+									; 			Typical value of 25h for 2 second delay
+	db		02h						; Offset 3: Sector size, always 512
+
+%ifdef USE_AT
+	db		12h						; Offset 4: Sectors per track, 1.44MB value
+	db		1bh						; Offset 5: Sector gap, 1.44MB value
+%else
+	db		09h						; Offset 4: Sectors per track, 360KB value
+	db		2ah						; Offset 5: Sector gap, 360KB value
+%endif
+
+	db		0ffh					; Offset 6: Data length
+
+%ifdef USE_AT
+	db		6ch						; Offset 7: Format gap length, 1.44MB value
+%else
+	db		50h						; Offset 7: Format gap length, 360KB value
+%endif
+
+	db		0f6h					; Offset 8: Fill byte for format
+	db		0fh						; Offset 9: Head setting time
+	db		08h						; Offset A: Wait for motor startup time
+
+%ifdef USE_AT
+	db		79						; Offset B: Maximum track number, 1.44MB value
+	db		0						; Offset C: Data transfer rate, 1.44MB value
+	db		4						; Offset D: Diskette CMOS drive type, 1.44MB value
+%else
+	db		39						; Offset B: Maximum track number, 360KB value
+	db		80h						; Offset C: Data transfer rate, 360KB value
+	db		1						; Offset D: Diskette CMOS drive type, 360KB value
+%endif
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH9h_HInit.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH9h_HInit.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AH9h_HInit.asm	(revision 352)
@@ -0,0 +1,164 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=9h, Initialize Drive Parameters.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=9h, Initialize Drive Parameters.
+;
+; AH9h_HandlerForInitializeDriveParameters
+;	Parameters:
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+AH9h_HandlerForInitializeDriveParameters:
+%ifndef USE_186
+	call	AH9h_InitializeDriveForUse
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%else
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+	; Fall to AH9h_InitializeDriveForUse
+%endif
+
+
+;--------------------------------------------------------------------
+; Initialized drive to be ready for use.
+;
+; AH9h_InitializeDriveForUse
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;	Corrupts registers:
+;		AL, BX, DX
+;--------------------------------------------------------------------
+AH9h_InitializeDriveForUse:
+	push	si
+	push	cx
+
+%ifdef MODULE_SERIAL
+	;
+	; no need to do this for serial devices, and we use the DPT_RESET flag bits
+	; to store the drive type for serial floppy drives (MODULE_SERIAL_FLOPPY)
+	;
+	xor		ah, ah
+	test	byte [di+DPT.bFlagsHigh], FLGH_DPT_SERIAL_DEVICE	; Clears CF
+	jnz		.ReturnNotSuccessful
+%endif
+
+	; Try to select drive and wait until ready
+	or		BYTE [di+DPT.bFlagsHigh], MASKH_DPT_RESET		; Everything uninitialized
+	call	AccessDPT_GetDriveSelectByteToAL
+	mov		[bp+IDEPACK.bDrvAndHead], al
+	call	Device_SelectDrive
+	jc		SHORT .ReturnNotSuccessful
+	and		BYTE [di+DPT.bFlagsHigh], ~FLGH_DPT_RESET_nDRDY	; Clear since success
+
+	; Initialize CHS parameters if LBA is not used
+	call	InitializeDeviceParameters
+	jc		SHORT .SetWriteCache
+	and		BYTE [di+DPT.bFlagsHigh], ~FLGH_DPT_RESET_nINITPRMS
+
+	; Enable or Disable Write Cache
+.SetWriteCache:
+	call	SetWriteCache
+
+	; Recalibrate drive by seeking to cylinder 0
+.RecalibrateDrive:
+	call	AH11h_RecalibrateDrive
+	jc		SHORT .InitializeBlockMode
+	and		BYTE [di+DPT.bFlagsHigh], ~FLGH_DPT_RESET_nRECALIBRATE
+
+	; Initialize block mode transfers
+.InitializeBlockMode:
+	call	InitializeBlockMode
+	jc		SHORT .ReturnNotSuccessful
+	and		BYTE [di+DPT.bFlagsHigh], ~FLGH_DPT_RESET_nSETBLOCK	; Keeps CF clear
+
+.ReturnNotSuccessful:
+	pop		cx
+	pop		si
+	ret
+
+
+;--------------------------------------------------------------------
+; InitializeDeviceParameters
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		Cleared if successful
+;				Set if any error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+InitializeDeviceParameters:
+	; No need to initialize CHS parameters if LBA mode enabled
+	test	BYTE [di+DPT.bFlagsLow], FLG_DRVNHEAD_LBA	; Clear CF
+	jnz		SHORT ReturnSuccessSinceInitializationNotNeeded
+
+	; Initialize Logical Sectors per Track and Max Head number
+	mov		ah, [di+DPT.bPchsHeads]
+	dec		ah							; Max Head number
+	mov		dl, [di+DPT.bPchsSectors]	; Sectors per Track
+	mov		al, COMMAND_INITIALIZE_DEVICE_PARAMETERS
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_BSY, FLG_STATUS_BSY)
+	jmp		Idepack_StoreNonExtParametersAndIssueCommandFromAL
+
+
+;--------------------------------------------------------------------
+; SetWriteCache
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		Cleared if successful
+;				Set if any error
+;	Corrupts registers:
+;		AL, BX, CX, DX, SI
+;--------------------------------------------------------------------
+SetWriteCache:
+	call	AccessDPT_GetPointerToDRVPARAMStoCSBX
+	mov		bl, [cs:bx+DRVPARAMS.wFlags]
+	and		bx, BYTE MASK_DRVPARAMS_WRITECACHE
+	jz		SHORT ReturnSuccessSinceInitializationNotNeeded		; DEFAULT_WRITE_CACHE
+	mov		si, [cs:bx+.rgbWriteCacheCommands]
+	jmp		AH23h_SetControllerFeatures
+
+.rgbWriteCacheCommands:
+	db		0								; DEFAULT_WRITE_CACHE
+	db		FEATURE_DISABLE_WRITE_CACHE		; DISABLE_WRITE_CACHE
+	db		FEATURE_ENABLE_WRITE_CACHE		; ENABLE_WRITE_CACHE
+
+
+;--------------------------------------------------------------------
+; InitializeBlockMode
+;	Parameters:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		Cleared if successful
+;				Set if any error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+InitializeBlockMode:
+	test	BYTE [di+DPT.bFlagsHigh], FLGH_DPT_BLOCK_MODE_SUPPORTED	; Clear CF
+	jz		SHORT ReturnSuccessSinceInitializationNotNeeded
+
+	call	AccessDPT_GetPointerToDRVPARAMStoCSBX
+	mov		al, 1						; Disable block mode
+	test	BYTE [cs:bx+DRVPARAMS.wFlags], FLG_DRVPARAMS_BLOCKMODE
+	eCMOVNZ	al, [di+DPT_ATA.bMaxBlock]	; Load max block size
+	jmp		AH24h_SetBlockSize
+ReturnSuccessSinceInitializationNotNeeded:
+	xor		ah, ah
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AHCh_HSeek.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AHCh_HSeek.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AHCh_HSeek.asm	(revision 352)
@@ -0,0 +1,53 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=Ch, Seek.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=Ch, Seek.
+;
+; AHCh_HandlerForSeek
+;	Parameters:
+;		CX, DH:	Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEREGS_AND_INTPACK
+;	Parameters on INTPACK:
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;	Returns with INTPACK:
+;		AH:		BIOS Error code
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AHCh_HandlerForSeek:
+%ifndef USE_186
+	call	AHCh_SeekToCylinder
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%else
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+	; Fall to AHCh_SeekToCylinder
+%endif
+
+;--------------------------------------------------------------------
+; AHCh_SeekToCylinder
+;	Parameters:
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEREGS_AND_INTPACK
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if successful, 1 if error
+;	Corrupts registers:
+;		AL, BX, CX, DX
+;--------------------------------------------------------------------
+AHCh_SeekToCylinder:
+	mov		ah, COMMAND_SEEK
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRDY)
+	jmp		Idepack_TranslateOldInt13hAddressAndIssueCommandFromAH
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AHDh_HReset.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AHDh_HReset.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/AHDh_HReset.asm	(revision 352)
@@ -0,0 +1,86 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=Dh, Reset Hard Disk (Alternate reset).
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=Dh, Reset Hard Disk (Alternate reset).
+;
+; AHDh_HandlerForResetHardDisk
+;	Parameters:
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AHDh_HandlerForResetHardDisk:
+%ifndef USE_186
+	call	AHDh_ResetDrive
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%else
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+	; Fall to AHDh_ResetDrive
+%endif
+
+
+;--------------------------------------------------------------------
+; Resets hard disk.
+;
+; AHDh_ResetDrive
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;	Corrupts registers:
+;		AL, SI
+;--------------------------------------------------------------------
+AHDh_ResetDrive:
+	push	dx
+	push	cx
+	push	bx
+	push	di
+
+	call	Interrupts_UnmaskInterruptControllerForDriveInDSDI
+	call	Device_ResetMasterAndSlaveController
+	;jc		SHORT .ReturnError					; CF would be set if slave drive present without master
+												; (error register has special values after reset)
+
+	; Initialize Master and Slave drives
+	eMOVZX	ax, [di+DPT.bIdevarsOffset]			; (AL) pointer to controller we are looking to reset
+												; (AH) initialize error code, assume success
+
+	mov		si, IterateAndResetDrives
+	call	FindDPT_IterateAllDPTs
+
+	shr		ah, 1								; Move error code and CF into proper position
+
+	pop		di
+	pop		bx
+	pop		cx
+	pop		dx
+	ret
+
+;--------------------------------------------------------------------
+; IterateAndResetDrives: Iteration routine for use with IterateAllDPTs.
+;
+; When a drive on the controller is found, it is reset, and the error code
+; merged into overall error code for this controller.  Master will be reset
+; first.  Note that the iteration will go until the end of the DPT list.
+;--------------------------------------------------------------------
+IterateAndResetDrives:
+	cmp		al, [di+DPT.bIdevarsOffset]			; The right controller?
+	jne		.done
+	push	ax
+	call	AH9h_InitializeDriveForUse			; Reset Master and Slave (Master will come first in DPT list)
+	pop		ax
+	jnc		.done
+	or		ah, (RET_HD_RESETFAIL << 1) | 1		; OR in Reset Failed error code and CF, will SHR into position later
+.done:
+	stc											; From IterateAllDPTs perspective, the DPT is never found (continue iteration)
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH41h_CheckIfExtensionsPresent.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH41h_CheckIfExtensionsPresent.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH41h_CheckIfExtensionsPresent.asm	(revision 352)
@@ -0,0 +1,34 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=41h, Check if Extensions Present.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=41h, Check if Extensions Present.
+;
+; AH41h_HandlerForCheckIfExtensionsPresent
+;	Parameters:
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		BX:		55AAh
+;	Returns with INTPACK:
+;		AH:		Major version of EBIOS extensions
+;		BX:		AA55h
+;		CX:		Support bits
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH41h_HandlerForCheckIfExtensionsPresent:
+	cmp		WORD [bp+IDEPACK.intpack+INTPACK.bx], 55AAh
+	jne		SHORT .EbiosNotSupported
+
+	mov		BYTE [bp+IDEPACK.intpack+INTPACK.ah], EBIOS_VERSION
+	mov		WORD [bp+IDEPACK.intpack+INTPACK.bx], 0AA55h
+	mov		WORD [bp+IDEPACK.intpack+INTPACK.cx], ENHANCED_DRIVE_ACCESS_SUPPORT
+	and		BYTE [bp+IDEPACK.intpack+INTPACK.flags], ~FLG_FLAGS_CF	; Return with CF cleared
+	jmp		Int13h_ReturnFromHandlerWithoutStoringErrorCode
+.EbiosNotSupported:
+	jmp		Int13h_UnsupportedFunction
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH42h_ExtendedReadSectors.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH42h_ExtendedReadSectors.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH42h_ExtendedReadSectors.asm	(revision 352)
@@ -0,0 +1,48 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=42h, Extended Read Sectors.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=42h, Extended Read Sectors.
+;
+; AH42h_HandlerForExtendedReadSectors
+;	Parameters:
+;		SI:		Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		DS:SI:	Ptr to Disk Address Packet
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;	Return with Disk Address Packet in INTPACK:
+;		.wSectorCount	Number of sectors read successfully
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH42h_HandlerForExtendedReadSectors:
+	call	Prepare_ByLoadingDapToESSIandVerifyingForTransfer
+	mov		ah, [cs:bx+g_rgbReadCommandLookup]
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
+	call	Idepack_ConvertDapToIdepackAndIssueCommandFromAH
+	; Fall to AH42h_ReturnFromInt13hAfterStoringErrorCodeFromAHandTransferredSectorsFromCX
+
+
+;--------------------------------------------------------------------
+; AH42h_ReturnFromInt13hAfterStoringErrorCodeFromAHandTransferredSectorsFromCX
+;	Parameters:
+;		AH:		INT 13h Error Code
+;		CX:		Number of successfully transferred sectors
+;		SS:BP:	Ptr to IDEPACK
+;	Returns:
+;		Nothing, jumps to Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+;	Corrupts registers:
+;		SI, DS
+;--------------------------------------------------------------------
+AH42h_ReturnFromInt13hAfterStoringErrorCodeFromAHandTransferredSectorsFromCX:
+	mov		ds, [bp+IDEPACK.intpack+INTPACK.ds]
+	mov		si, [bp+IDEPACK.intpack+INTPACK.si]
+	mov		[si+DAP.wSectorCount], cx
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH43h_ExtendedWriteSectors.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH43h_ExtendedWriteSectors.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH43h_ExtendedWriteSectors.asm	(revision 352)
@@ -0,0 +1,40 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=43h, Extended Write Sectors.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=43h, Extended Write Sectors.
+;
+; AH43h_HandlerForExtendedWriteSectors
+;	Parameters:
+;		SI:		Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		AL:		0 or 1 to write with verify off
+;				2 to write with verify (if supported)
+;		DS:SI:	Ptr to Disk Address Packet
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;	Return with Disk Address Packet in INTPACK:
+;		.wSectorCount	Number of sectors written successfully
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH43h_HandlerForExtendedWriteSectors:
+	cmp		BYTE [bp+IDEPACK.intpack+INTPACK.al], 2	; Verify requested?
+	jae		SHORT Prepare_ReturnFromInt13hWithInvalidFunctionError
+
+	call	Prepare_ByLoadingDapToESSIandVerifyingForTransfer
+	mov		ah, [cs:bx+g_rgbWriteCommandLookup]
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
+%ifdef USE_186
+	push	AH42h_ReturnFromInt13hAfterStoringErrorCodeFromAHandTransferredSectorsFromCX
+	jmp		Idepack_ConvertDapToIdepackAndIssueCommandFromAH
+%else
+	call	Idepack_ConvertDapToIdepackAndIssueCommandFromAH
+	jmp		SHORT AH42h_ReturnFromInt13hAfterStoringErrorCodeFromAHandTransferredSectorsFromCX
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH44h_ExtendedVerifySectors.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH44h_ExtendedVerifySectors.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH44h_ExtendedVerifySectors.asm	(revision 352)
@@ -0,0 +1,35 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=44h, Extended Verify Sectors.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=44h, Extended Verify Sectors.
+;
+; AH44h_HandlerForExtendedVerifySectors
+;	Parameters:
+;		SI:		Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		DS:SI:	Ptr to Disk Address Packet
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;	Return with Disk Address Packet in INTPACK:
+;		.wSectorCount	Number of sectors verified successfully
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH44h_HandlerForExtendedVerifySectors:
+	call	Prepare_ByLoadingDapToESSIandVerifyingForTransfer
+	mov		ah, [cs:bx+g_rgbVerifyCommandLookup]
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRDY)
+%ifdef USE_186
+	push	AH42h_ReturnFromInt13hAfterStoringErrorCodeFromAHandTransferredSectorsFromCX
+	jmp		Idepack_ConvertDapToIdepackAndIssueCommandFromAH
+%else
+	call	Idepack_ConvertDapToIdepackAndIssueCommandFromAH
+	jmp		SHORT AH42h_ReturnFromInt13hAfterStoringErrorCodeFromAHandTransferredSectorsFromCX
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH47h_ExtendedSeek.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH47h_ExtendedSeek.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH47h_ExtendedSeek.asm	(revision 352)
@@ -0,0 +1,37 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=47h, Extended Seek.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=47h, Extended Seek.
+;
+; AH47h_HandlerForExtendedSeek
+;	Parameters:
+;		SI:		Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		DS:SI:	Ptr to Disk Address Packet
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH47h_HandlerForExtendedSeek:
+	; Note that there is no Seek command for LBA48 addressing!
+	mov		es, [bp+IDEPACK.intpack+INTPACK.ds]	; ES:SI to point Disk Address Packet
+	cmp		BYTE [es:si+DAP.bSize], MINIMUM_DAP_SIZE
+	jb		SHORT Prepare_ReturnFromInt13hWithInvalidFunctionError
+
+	mov		ah, COMMAND_SEEK
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRDY)
+%ifdef USE_186
+	push	Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+	jmp		Idepack_ConvertDapToIdepackAndIssueCommandFromAH
+%else
+	call	Idepack_ConvertDapToIdepackAndIssueCommandFromAH
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH48h_GetExtendedDriveParameters.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH48h_GetExtendedDriveParameters.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/EBIOS/AH48h_GetExtendedDriveParameters.asm	(revision 352)
@@ -0,0 +1,56 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 13h function AH=48h, Get Extended Drive Parameters.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Int 13h function AH=48h, Get Extended Drive Parameters.
+;
+; AH48h_GetExtendedDriveParameters
+;	Parameters:
+;		SI:		Same as in INTPACK
+;		DL:		Translated Drive number
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		DS:SI:	Ptr to Extended Drive Information Table to fill
+;	Returns with INTPACK:
+;		AH:		Int 13h return status
+;		DS:SI:	Ptr to Extended Drive Information Table
+;		CF:		0 if successful, 1 if error
+;--------------------------------------------------------------------
+AH48h_HandlerForGetExtendedDriveParameters:
+	call	AccessDPT_GetPointerToDRVPARAMStoCSBX
+	push	bx
+	call	AccessDPT_GetLbaSectorCountToBXDXAX
+	pop		di			; CS:DI now points to DRVPARAMS
+
+	; Point DS:SI to Extended Drive Information Table to fill
+	mov		ds, [bp+IDEPACK.intpack+INTPACK.ds]
+	mov		cx, MINIMUM_EDRIVEINFO_SIZE
+	cmp		[si+EDRIVE_INFO.wSize], cx
+	jb		Prepare_ReturnFromInt13hWithInvalidFunctionError
+	je		SHORT .SkipEddConfigurationParameters
+
+	; We do not support EDD Configuration Parameters so set to FFFF:FFFFh
+	mov		cx, -1		; FFFFh
+	mov		[si+EDRIVE_INFO.fpEDDparams], cx
+	mov		[si+EDRIVE_INFO.fpEDDparams+2], cx
+	mov		cx, EDRIVE_INFO_size
+
+	; Fill Extended Drive Information Table in DS:SI
+.SkipEddConfigurationParameters:
+	mov		[si+EDRIVE_INFO.wSize], cx
+	mov		WORD [si+EDRIVE_INFO.wFlags], FLG_DMA_BOUNDARY_ERRORS_HANDLED_BY_BIOS
+
+	; Store total sector count
+	mov		[si+EDRIVE_INFO.qwTotalSectors], ax
+	xor		ax, ax									; Return with success
+	mov		[si+EDRIVE_INFO.qwTotalSectors+2], dx
+	mov		[si+EDRIVE_INFO.qwTotalSectors+4], bx
+	mov		[si+EDRIVE_INFO.qwTotalSectors+6], ax	; Always zero
+	mov		WORD [si+EDRIVE_INFO.wSectorSize], 512
+
+.ReturnWithError:
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/Tools/Address.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/Tools/Address.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/Tools/Address.asm	(revision 352)
@@ -0,0 +1,165 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for address translations.
+
+; Section containing code
+SECTION .text
+
+;---------------------------------------------------------------------
+; Address_ExtractLCHSparametersFromOldInt13hAddress
+;	Parameters:
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Sector number
+;		DH:		Head number
+;	Returns:
+;		BL:		Sector number (1...63)
+;		BH:		Head number (0...255)
+;		CX:		Cylinder number (0...1023)
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Address_ExtractLCHSparametersFromOldInt13hAddress:
+	mov		bl, cl				; Copy sector number...
+	and		bl, 3Fh				; ...and limit to 1...63
+	sub		cl, bl				; Remove from cylinder number high
+	eROL_IM	cl, 2				; High bits to beginning
+	mov		bh, dh				; Copy Head number
+	xchg	cl, ch				; Cylinder number now in CX
+	ret
+
+
+;---------------------------------------------------------------------
+; Converts LCHS parameters to IDE P-CHS parameters.
+; PCylinder	= (LCylinder << n) + (LHead / PHeadCount)
+; PHead		= LHead % PHeadCount
+; PSector	= LSector
+;
+; Address_ConvertLCHStoPCHS:
+;	Parameters:
+;		BL:		Sector number (1...63)
+;		BH:		Head number (0...255)
+;		CX:		Cylinder number (0...1023)
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		BL:		Sector number (1...63)
+;		BH:		Head number (0...15)
+;		CX:		Cylinder number (0...16382)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+ConvertLCHStoPCHS:
+	; LHead / PHeadCount and LHead % PHeadCount
+	eMOVZX	ax, bh					; Copy L-CHS Head number to AX
+	div		BYTE [di+DPT.bPchsHeads]; AL = LHead / PHeadCount, AH = LHead % PHeadCount
+	mov		bh, ah					; Copy P-CHS Head number to BH
+	xor		ah, ah					; AX = LHead / PHeadCount
+
+	; (LCylinder << n) + (LHead / PHeadCount)
+	mov		dx, cx					; Copy L-CHS Cylinder number to DX
+	mov		cl, [di+DPT.bFlagsLow]	; Load shift count
+	and		cl, MASKL_DPT_CHS_SHIFT_COUNT
+	shl		dx, cl					; DX = LCylinder << n
+	add		ax, dx					; AX = P-CHS Cylinder number
+	xchg	cx, ax					; Move P-CHS Cylinder number to CX
+DoNotConvertLCHS:
+	ret
+
+;--------------------------------------------------------------------
+; Address_OldInt13hAddressToIdeAddress
+;	Parameters:
+;		CH:		Cylinder number, bits 7...0
+;		CL:		Bits 7...6: Cylinder number bits 9 and 8
+;				Bits 5...0:	Starting sector number (1...63)
+;		DH:		Starting head number (0...255)
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		BL:		LBA Low Register / Sector Number Register (LBA 7...0)
+;		CL:		LBA Mid Register / Low Cylinder Register (LBA 15...8)
+;		CH:		LBA High Register / High Cylinder Register (LBA 23...16)
+;		BH:		Drive and Head Register (LBA 27...24)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Address_OldInt13hAddressToIdeAddress:
+		call	Address_ExtractLCHSparametersFromOldInt13hAddress
+
+		AccessDPT_GetUnshiftedAddressModeToALZF
+
+;;; 0: ADDR_DPT_LCHS
+		jz		DoNotConvertLCHS
+
+;;; 1: ADDR_DPT_PCHS
+		;
+		; Since we are only checking for zero, we can do our math in the high order bits,
+		; in this case effectively subtracting 1 from the address mode.
+		;
+		sub		al,(1<<ADDRESSING_MODE_FIELD_POSITION)
+		jz		ConvertLCHStoPCHS
+
+;;; 2: ADDR_DPT_LBA28 and 3: ADDR_DPT_LBA48
+		; Fall through to ConvertLCHStoLBARegisterValues
+
+;---------------------------------------------------------------------
+; Converts LCHS parameters to 28-bit LBA address.
+; Only 24-bits are used since LHCS to LBA28 conversion has 8.4GB limit.
+; LBA = ((cylToSeek*headsPerCyl+headToSeek)*sectPerTrack)+sectToSeek-1
+;
+; Returned address is in same registers that
+; Address_DoNotConvertLCHS and Address_ConvertLCHStoPCHS returns.
+;
+; ConvertLCHStoLBARegisterValues:
+;	Parameters:
+;		BL:		Sector number (1...63)
+;		BH:		Head number (0...255)
+;		CX:		Cylinder number (0...1023)
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		BL:		LBA Low Register / Sector Number Register (LBA 7...0)
+;		CL:		LBA Mid Register / Low Cylinder Register (LBA 15...8)
+;		CH:		LBA High Register / High Cylinder Register (LBA 23...16)
+;		BH:		Drive and Head Register (LBA 27...24)
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+ConvertLCHStoLBARegisterValues:
+	; cylToSeek*headsPerCyl (18-bit result)
+	mov		ax, LBA_ASSIST_SPT		; Load Sectors per Track
+	xchg	cx, ax					; Cylinder number to AX, Sectors per Track to CX
+
+%ifdef USE_386
+	movzx	dx, [di+DPT.bLbaHeads]
+%else
+	cwd
+	mov		dl, [di+DPT.bLbaHeads]
+%endif
+	mul		dx						; DX:AX = cylToSeek*headsPerCyl
+
+	; +=headToSeek (18-bit result)
+	add		al, bh					; Add Head number to DX:AX
+	adc		ah, dh					; DH = Zero after previous multiplication
+	adc		dl, dh
+
+	; *=sectPerTrack (18-bit by 6-bit multiplication with 24-bit result)
+	xchg	ax, dx					; Hiword to AX, loword to DX
+	mul		cl						; AX = hiword * Sectors per Track
+	mov		bh, al					; Backup hiword * Sectors per Track
+	xchg	ax, dx					; Loword back to AX
+	mul		cx						; DX:AX = loword * Sectors per Track
+	add		dl, bh					; DX:AX = (cylToSeek*headsPerCyl+headToSeek)*sectPerTrack
+
+	; +=sectToSeek-1 (24-bit result)
+	xor		bh, bh					; Sector number now in BX
+	dec		bx						; sectToSeek-=1
+	add		ax, bx					; Add to loword
+	adc		dl, bh					; Add possible carry to byte2, BH=zero
+
+	; Copy DX:AX to proper return registers
+	xchg	bx, ax					; BL = Sector Number Register (LBA 7...0)
+	mov		cl, bh					; Low Cylinder Register (LBA 15...8)
+	mov		ch, dl					; High Cylinder Register (LBA 23...16)
+	mov		bh, dh					; Drive and Head Register (LBA 27...24)
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/Tools/Prepare.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/Tools/Prepare.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int13h/Tools/Prepare.asm	(revision 352)
@@ -0,0 +1,146 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for preparing data buffer for transfer.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Prepare_ByLoadingDapToESSIandVerifyingForTransfer
+;	Parameters:
+;		SI:		Offset to DAP
+;		DS:DI:	Ptr to DPT
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		DS:SI:	Ptr to Disk Address Packet
+;	Returns:
+;		BX:		Index to command lookup table
+;		ES:SI:	Ptr to Disk Address Packet (DAP)
+;		Exits from INT 13h if invalid DAP
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+%ifdef MODULE_EBIOS
+ALIGN JUMP_ALIGN
+Prepare_ByLoadingDapToESSIandVerifyingForTransfer:
+	; Load pointer to DAP to ES:SI and make sure it is valid
+	mov		es, [bp+IDEPACK.intpack+INTPACK.ds]	; ES:SI to point Disk Address Packet
+	cmp		BYTE [es:si+DAP.bSize], MINIMUM_DAP_SIZE
+	jb		SHORT InvalidDAP
+
+	; Make sure that sector count is valid
+	mov		ax, [es:si+DAP.wSectorCount]
+	test	ax, ax
+	jz		SHORT ZeroSectorsRequestedSoNoErrors
+	cmp		ax, BYTE 127
+	ja		SHORT InvalidNumberOfSectorsRequested
+
+	; Get EBIOS command index to BX
+	; LBA28 or LBA48 command
+	cwd
+	mov		al, [es:si+DAP.qwLBA+3]	; Load LBA48 byte 3 (bits 24...31)
+	and		al, 0F0h				; Clear LBA28 bits 24...27
+	or		ax, [es:si+DAP.qwLBA+4]	; Set bits from LBA bytes 4 and 5
+	cmp		dx, ax					; Set CF if any of bits 28...47 set
+	rcl		dx, 1					; DX = 0 for LBA28, DX = 1 for LBA48
+	call	Prepare_GetOldInt13hCommandIndexToBX
+	or		bx, dx					; Set block mode / single sector bit
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Prepare_GetOldInt13hCommandIndexToBX
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		BX:		Index to command lookup table
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Prepare_GetOldInt13hCommandIndexToBX:
+	; Block mode or single sector
+	mov		bl, [di+DPT.bFlagsHigh]
+	and		bx, BYTE FLGH_DPT_BLOCK_MODE_SUPPORTED	; Bit 1
+	ret
+
+
+;---------------------------------------------------------------------
+; Prepare_BufferToESSIforOldInt13hTransfer
+;	Parameters:
+;		AL:		Number of sectors to transfer
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		ES:BX:	Ptr to data buffer
+;	Returns:
+;		ES:SI:	Ptr to normalized data buffer
+;		Exits INT 13h if error
+;	Corrupts registers:
+;		BX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Prepare_BufferToESSIforOldInt13hTransfer:
+	; Normalize buffer pointer
+	mov		bx, [bp+IDEPACK.intpack+INTPACK.bx]	; Load offset
+	mov		si, bx
+	eSHR_IM	bx, 4								; Divide offset by 16
+	add		bx, [bp+IDEPACK.intpack+INTPACK.es]
+	mov		es, bx								; Segment normalized
+	and		si, BYTE 0Fh						; Offset normalized
+	; Fall to Prepare_ByValidatingSectorsInALforOldInt13h
+
+
+;---------------------------------------------------------------------
+; Prepare_ByValidatingSectorsInALforOldInt13h
+;	Parameters:
+;		AL:		Number of sectors to transfer
+;	Returns:
+;		Exits INT 13h if invalid number of sectors in AL
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Prepare_ByValidatingSectorsInALforOldInt13h:
+	test	al, al
+	js		SHORT .CheckZeroOffsetFor128Sectors		; 128 or more
+	jz		SHORT InvalidNumberOfSectorsRequested	; Zero not allowed for old INT 13h
+	ret		; Continue with transfer
+
+ALIGN JUMP_ALIGN
+.CheckZeroOffsetFor128Sectors:
+	cmp		al, 128
+	ja		SHORT InvalidNumberOfSectorsRequested
+	test	si, si								; Offset must be zero to xfer 128 sectors
+	jnz		SHORT CannotAlignPointerProperly
+	ret		; Continue with transfer
+
+InvalidDAP:
+InvalidNumberOfSectorsRequested:
+Prepare_ReturnFromInt13hWithInvalidFunctionError:
+	mov		ah, RET_HD_INVALID
+	SKIP2B	f
+CannotAlignPointerProperly:
+	mov		ah, RET_HD_BOUNDARY
+ZeroSectorsRequestedSoNoErrors:
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
+
+
+
+; Command lookup tables
+g_rgbReadCommandLookup:
+	db		COMMAND_READ_SECTORS		; 00b, CHS or LBA28 single sector
+	db		COMMAND_READ_SECTORS_EXT	; 01b, LBA48 single sector
+	db		COMMAND_READ_MULTIPLE		; 10b, CHS or LBA28 block mode
+	db		COMMAND_READ_MULTIPLE_EXT	; 11b, LBA48 block mode
+
+g_rgbWriteCommandLookup:
+	db		COMMAND_WRITE_SECTORS
+	db		COMMAND_WRITE_SECTORS_EXT
+	db		COMMAND_WRITE_MULTIPLE
+	db		COMMAND_WRITE_MULTIPLE_EXT
+
+g_rgbVerifyCommandLookup:
+	db		COMMAND_VERIFY_SECTORS
+	db		COMMAND_VERIFY_SECTORS_EXT
+	db		COMMAND_VERIFY_SECTORS
+	db		COMMAND_VERIFY_SECTORS_EXT
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int19h.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int19h.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Handlers/Int19h.asm	(revision 352)
@@ -0,0 +1,151 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Int 19h Handler (Boot Loader).
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; INT 19h handler that properly reboots the computer when
+; INT 19h is called.
+;
+; Int19h_ResetHandler
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Never returns (reboots computer)
+;--------------------------------------------------------------------
+Int19h_ResetHandler:
+	mov		ax, BOOT_FLAG_WARM				; Skip memory tests
+	jmp		Reboot_ComputerWithBootFlagInAX
+
+
+;--------------------------------------------------------------------
+; Int19h_BootLoaderHandler
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Never returns (loads operating system)
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19h_BootLoaderHandler:
+	sti
+	; Install INT 19h handler for proper reboot
+	LOAD_BDA_SEGMENT_TO	es, ax
+	mov		al, BIOS_BOOT_LOADER_INTERRUPT_19h	; INT 19h interrupt vector offset
+	mov		si, Int19h_ResetHandler				; INT 19h handler to reboot the system
+	call	Interrupts_InstallHandlerToVectorInALFromCSSI
+	call	Initialize_AndDetectDrives			; Installs new boot menu loader
+	; Fall to .PrepareStackAndSelectDriveFromBootMenu
+
+;--------------------------------------------------------------------
+; .PrepareStackAndSelectDriveFromBootMenu
+;	Parameters:
+;		ES:		BDA and interrupt vector segment (zero)
+;	Returns:
+;		Never returns (loads operating system)
+;--------------------------------------------------------------------
+.PrepareStackAndSelectDriveFromBootMenu:
+	STORE_POST_STACK_POINTER
+	SWITCH_TO_BOOT_MENU_STACK
+	; Fall to .InitializeDisplay
+
+;--------------------------------------------------------------------
+; .InitializeDisplay
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Never returns (loads operating system)
+;--------------------------------------------------------------------
+.InitializeDisplay:
+	; Change display mode if necessary
+	mov		ax, [cs:ROMVARS.wDisplayMode]	; AH 00h = Set Video Mode
+	cmp		al, DEFAULT_TEXT_MODE
+	je		SHORT .InitializeDisplayLibrary
+	int		BIOS_VIDEO_INTERRUPT_10h
+.InitializeDisplayLibrary:
+	call	BootMenuPrint_InitializeDisplayContext
+	; Fall to .SelectDriveToBootFrom
+
+;--------------------------------------------------------------------
+; .SelectDriveToBootFrom
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Never returns (loads operating system)
+;--------------------------------------------------------------------
+.SelectDriveToBootFrom:
+	call	RamVars_GetSegmentToDS
+	cmp		WORD [cs:ROMVARS.wfDisplayBootMenu], BYTE 0
+	jne		SHORT ProcessBootMenuSelectionsUntilBootableDriveSelected	; Display boot menu
+	; Fall to BootFromDriveAthenTryDriveC
+
+;--------------------------------------------------------------------
+; BootFromDriveAthenTryDriveC
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Never returns (loads operating system)
+;--------------------------------------------------------------------
+BootFromDriveAthenTryDriveC:
+	xor		dx, dx				; DL = 00h = Floppy Drive A
+	call	BootSector_TryToLoadFromDriveDL
+	jc		SHORT Int19hMenu_JumpToBootSector_or_RomBoot
+	mov		dl, 80h				; DL = 80h = First Hard Drive (usually C)
+	call	BootSector_TryToLoadFromDriveDL
+	jmp		SHORT Int19hMenu_JumpToBootSector_or_RomBoot	; ROM Boot if error
+
+
+;--------------------------------------------------------------------
+; ProcessBootMenuSelectionsUntilBootableDriveSelected
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Never returns
+;--------------------------------------------------------------------
+ProcessBootMenuSelectionsUntilBootableDriveSelected:
+	call	BootMenu_DisplayAndReturnSelectionInDX
+	call	DriveXlate_ToOrBack											; Translate drive number
+	call	BootSector_TryToLoadFromDriveDL
+	jnc		SHORT ProcessBootMenuSelectionsUntilBootableDriveSelected	; Boot failure, show menu again
+	; Fall to Int19hMenu_JumpToBootSector_or_RomBoot
+	; (CF is set or we wouldn't be here, see "jnc" immediately above)
+
+;--------------------------------------------------------------------
+; Int19hMenu_JumpToBootSector_or_RomBoot
+;
+; Switches back to the POST stack, clears the DS and ES registers,
+; and either jumps to the MBR (Master Boot Record) that was just read,
+; or calls the ROM's boot routine on interrupt 18.
+;
+;	Parameters:
+;		DL:		Drive to boot from (translated, 00h or 80h)
+;       CF:     Set for Boot Sector Boot 
+;               Clear for Rom Boot
+;	   	ES:BX:	(if CF set) Ptr to boot sector
+;
+;	Returns:
+;		Never returns
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+Int19hMenu_JumpToBootSector_or_RomBoot:
+	mov		cx, es		; Preserve MBR segment (can't push because of stack change)
+	mov		ax, 0		; NOTE: can't use XOR (LOAD_BDA_SEGMENT_TO) as it impacts CF
+	SWITCH_BACK_TO_POST_STACK
+
+; clear segment registers before boot sector or rom call
+	mov		ds, ax		
+	mov		es, ax
+%ifdef USE_386
+	mov		fs, ax
+	mov		gs, ax
+%endif
+	jnc		SHORT .romboot
+
+; jump to boot sector
+	push	cx			; sgment address for MBR
+	push	bx			; offset address for MBR
+	retf				; NOTE:	DL is set to the drive number
+
+; Boot by calling INT 18h (ROM Basic of ROM DOS)
+.romboot:
+	int		BIOS_BOOT_FAILURE_INTERRUPT_18h	; Never returns		
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/AtaID.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/AtaID.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/AtaID.asm	(revision 352)
@@ -0,0 +1,73 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for accessing ATA information read with
+;					IDENTIFY DEVICE command.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; AtaID_GetPCHStoAXBLBHfromAtaInfoInESSI
+;	Parameters:
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		AX:		Number of user specified P-CHS cylinders
+;		BH:		Number of user specified P-CHS sectors per track
+;		BL:		Number of user specified P-CHS heads
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+AtaID_GetPCHStoAXBLBHfromAtaInfoInESSI:
+	mov		ax, [es:si+ATA1.wCylCnt]	; Cylinders (1...16383)
+	mov		bl, [es:si+ATA1.wHeadCnt]	; Heads (1...16)
+	mov		bh, [es:si+ATA1.wSPT]		; Sectors per Track (1...63)
+	ret
+
+
+;--------------------------------------------------------------------
+; AtaID_GetTotalSectorCountToBXDXAXfromAtaInfoInESSI
+;	Parameters:
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		BX:DX:AX:	48-bit sector count
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+AtaID_GetTotalSectorCountToBXDXAXfromAtaInfoInESSI:
+	mov		bx, Registers_ExchangeDSSIwithESDI
+	call	bx	; ATA info now in DS:DI
+	push	bx	; We will return via Registers_ExchangeDSSIwithESDI
+	xor		bx, bx
+	test	BYTE [di+ATA1.wCaps+1], A1_wCaps_LBA>>8
+	jz		SHORT .GetChsSectorCount
+	; Fall to .GetLbaSectorCount
+
+;--------------------------------------------------------------------
+; .GetLbaSectorCount
+; .GetLba28SectorCount
+; .GetChsSectorCount
+;	Parameters:
+;		BX:		Zero
+;		DS:DI:	Ptr to 512-byte ATA information read from the drive
+;	Returns:
+;		BX:DX:AX:	48-bit sector count
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+.GetLbaSectorCount:
+	test	BYTE [di+ATA6.wSetSup83+1], A6_wSetSup83_LBA48>>8
+	jz		SHORT .GetLba28SectorCount
+	mov		ax, [di+ATA6.qwLBACnt]
+	mov		dx, [di+ATA6.qwLBACnt+2]
+	mov		bx, [di+ATA6.qwLBACnt+4]
+	ret
+
+.GetLba28SectorCount:
+	mov		ax, [di+ATA1.dwLBACnt]
+	mov		dx, [di+ATA1.dwLBACnt+2]
+	ret
+
+.GetChsSectorCount:
+	mov		al, [di+ATA1.wSPT]		; AL=Sectors per track
+	mul		BYTE [di+ATA1.wHeadCnt]	; AX=Sectors per track * number of heads
+	mul		WORD [di+ATA1.wCylCnt]	; DX:AX=Sectors per track * number of heads * number of cylinders
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/DetectDrives.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/DetectDrives.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/DetectDrives.asm	(revision 352)
@@ -0,0 +1,207 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for detecting drive for the BIOS.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Detects all IDE hard disks to be controlled by this BIOS.
+;
+; DetectDrives_FromAllIDEControllers
+;	Parameters:
+;		DS:		RAMVARS segment
+;		ES:		BDA segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		All (not segments)
+;--------------------------------------------------------------------
+DetectDrives_FromAllIDEControllers:
+	call	RamVars_GetIdeControllerCountToCX
+	mov		bp, ROMVARS.ideVars0			; CS:BP now points to first IDEVARS
+
+.DriveDetectLoop:							; Loop through IDEVARS
+	push	cx
+
+	mov		cx, g_szDetectMaster
+	mov		bh, MASK_DRVNHEAD_SET								; Select Master drive
+	call	StartDetectionWithDriveSelectByteInBHandStringInCX	; Detect and create DPT + BOOTNFO
+
+	mov		cx, g_szDetectSlave
+	mov		bh, MASK_DRVNHEAD_SET | FLG_DRVNHEAD_DRV
+	call	StartDetectionWithDriveSelectByteInBHandStringInCX
+
+	pop		cx
+
+	add		bp, BYTE IDEVARS_size			; Point to next IDEVARS
+
+%ifdef MODULE_SERIAL
+	jcxz	.AddHardDisks					; Set to zero on .ideVarsSerialAuto iteration (if any)
+%endif
+
+	loop	.DriveDetectLoop
+
+%ifdef MODULE_SERIAL
+;----------------------------------------------------------------------
+;
+; if serial drive detected, do not scan (avoids duplicate drives and isn't needed - we already have a connection)
+;
+	call	FindDPT_ToDSDIforSerialDevice
+	jnc		.AddHardDisks
+
+	mov		bp, ROMVARS.ideVarsSerialAuto	; Point to our special IDEVARS structure, just for serial scans
+
+	mov		al,[cs:ROMVARS.wFlags]			; Configurator set to always scan?
+	or		al,[es:BDA.bKBFlgs1]			; Or, did the user hold down the ALT key?
+	and		al,8							; 8 = alt key depressed, same as FLG_ROMVARS_SERIAL_ALWAYSDETECT
+	jnz		.DriveDetectLoop
+%endif
+
+.AddHardDisks:
+;----------------------------------------------------------------------
+;
+; Add in hard disks to BDA, finalize our Count and First variables
+;
+; Note that we perform the add to bHDCount and store bFirstDrv even if the count is zero.
+; This is done because we use the value of .bFirstDrv to know how many drives were in the system
+; at the time of boot, and to return that number on int13h/8h calls.  Because the count is zero,
+; FindDPT_ForDriveNumber will not find any drives that are ours.
+;
+	mov		cx, [RAMVARS.wDrvCntAndFlopCnt]		; Our count of hard disks
+
+	mov		al, [es:BDA.bHDCount]
+	add		cl, al						; Add our drives to the system count
+	mov		[es:BDA.bHDCount], cl
+	or		al, 80h						; Or in hard disk flag
+	mov		[RAMVARS.bFirstDrv], al		; Store first drive number
+
+.AddFloppies:
+%ifdef MODULE_SERIAL_FLOPPY
+;----------------------------------------------------------------------
+;
+; Add in any emulated serial floppy drives, finalize our packed Count and First variables
+;
+	dec		ch
+	mov		al, ch
+	js		.NoFloppies						; if no drives are present, we store 0ffh
+
+	call	FloppyDrive_GetCountFromBIOS_or_BDA
+
+	push	ax
+
+	add		al, ch							; Add our drives to existing drive count
+	cmp		al, 3							; For BDA, max out at 4 drives (ours is zero based)
+	jb		.MaxBDAFloppiesExceeded
+	mov		al, 3
+.MaxBDAFloppiesExceeded:
+	eROR_IM	al, 2							; move to bits 6-7
+	inc		ax								; low order bit, indicating floppy drive exists
+
+	mov		ah, [es:BDA.wEquipment]			; Load Equipment WORD low byte
+	and		ah, 03eh						; Mask off drive number and drives present bit
+	or		al, ah							; Or in new values
+	mov		[es:BDA.wEquipment], al			; and store
+
+	mov		al, 1eh							; BDA pointer to Floppy DPT
+	mov		si, AH8h_FloppyDPT
+	call	Interrupts_InstallHandlerToVectorInALFromCSSI
+
+	pop		ax
+
+	shr		ch, 1							; number of drives, 1 or 2 only, to CF flag (clear=1, set=2)
+	rcl		al, 1							; starting drive number in upper 7 bits, number of drives in low bit
+.NoFloppies:
+	mov		[RAMVARS.xlateVars+XLATEVARS.bFlopCntAndFirst], al
+%endif
+
+	ret
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if FLG_ROMVARS_SERIAL_SCANDETECT != 8
+		%error "DetectDrives is currently coded to assume that FLG_ROMVARS_SERIAL_SCANDETECT is the same bit as the ALT key code in the BDA.  Changes in the code will be needed if these values are no longer the same."
+	%endif
+%endif
+
+
+;--------------------------------------------------------------------
+; StartDetectionWithDriveSelectByteInBHandStringInCX
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		CX:		Offset to "Master" or "Slave" string
+;		CS:BP:	Ptr to IDEVARS for the drive
+;		DS:		RAMVARS segment
+;		ES:		Zero (BDA segment)
+;	Returns:
+;       None
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+StartDetectionWithDriveSelectByteInBHandStringInCX:
+	call	DetectPrint_StartDetectWithMasterOrSlaveStringInCXandIdeVarsInCSBP
+	; Fall to .ReadAtaInfoFromHardDisk
+
+;--------------------------------------------------------------------
+; .ReadAtaInfoFromHardDisk
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		CS:BP:	Ptr to IDEVARS for the drive
+;		DS:		RAMVARS segment
+;		ES:		Zero (BDA segment)
+;	Returns:
+;		CF:		Cleared if ATA-information read successfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, BL, CX, DX, SI, DI
+;--------------------------------------------------------------------
+.ReadAtaInfoFromHardDisk:
+	mov		si, BOOTVARS.rgbAtaInfo		; ES:SI now points to ATA info location
+	push	es
+	push	si
+	push	bx
+	call	Device_IdentifyToBufferInESSIwithDriveSelectByteInBH
+	pop		bx
+	pop		si
+	pop		es
+	jnc		SHORT CreateBiosTablesForHardDisk
+	; Fall to .ReadAtapiInfoFromDrive
+
+.ReadAtapiInfoFromDrive:				; Not yet implemented
+	;call	ReadAtapiInfoFromDrive		; Assume CD-ROM
+	;jnc	SHORT _CreateBiosTablesForCDROM
+
+	;jmp	short DetectDrives_DriveNotFound
+;;; fall-through instead of previous jmp instruction
+;--------------------------------------------------------------------
+; DetectDrives_DriveNotFound
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CF:     Set (from BootMenuPrint_NullTerminatedStringFromCSSIandSetCF)
+;	Corrupts registers:
+;		AX, SI
+;--------------------------------------------------------------------
+DetectDrives_DriveNotFound:
+	mov		si, g_szNotFound
+	jmp		BootMenuPrint_NullTerminatedStringFromCSSIandSetCF
+
+
+;--------------------------------------------------------------------
+; CreateBiosTablesForHardDisk
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		CS:BP:	Ptr to IDEVARS for the drive
+;		ES:SI	Ptr to ATA information for the drive
+;		DS:		RAMVARS segment
+;		ES:		BDA/Bootnfo segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+CreateBiosTablesForHardDisk:
+	call	CreateDPT_FromAtaInformation
+	jc		SHORT DetectDrives_DriveNotFound
+	call	BootMenuInfo_CreateForHardDisk
+	jmp		short DetectPrint_DriveNameFromBootnfoInESBX
+
+
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/DetectPrint.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/DetectPrint.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/DetectPrint.asm	(revision 352)
@@ -0,0 +1,131 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for printing drive detection strings.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Prints BIOS name and segment address where it is found.
+;
+; DetectPrint_RomFoundAtSegment
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, SI, DI
+;--------------------------------------------------------------------
+DetectPrint_RomFoundAtSegment:
+	push	bp
+	mov		bp, sp
+	mov		si, g_szRomAt
+	ePUSH_T	ax, ROMVARS.szTitle			; Bios title string
+	push	cs							; BIOS segment
+
+DetectPrint_BootMenuPrint_FormatCSSIfromParamsInSSBP_Relay:
+	jmp		BootMenuPrint_FormatCSSIfromParamsInSSBP
+
+
+;--------------------------------------------------------------------
+; DetectPrint_StartDetectWithMasterOrSlaveStringInCXandIdeVarsInCSBP
+;	Parameters:
+;		CS:CX:	Ptr to "Master" or "Slave" string
+;		CS:BP:	Ptr to IDEVARS
+;       SI:		Ptr to template string
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, SI, DI, CX
+;--------------------------------------------------------------------
+DetectPrint_StartDetectWithMasterOrSlaveStringInCXandIdeVarsInCSBP:
+	mov		ax, [cs:bp+IDEVARS.wPort]    	; for IDE: AX=port address, DH=.bDevice
+	mov		dx, [cs:bp+IDEVARS.bDevice-1]   ; for Serial: AL=port address>>2, AH=baud rate
+											;			  DL=COM number character, DH=.bDevice
+%ifdef MODULE_JRIDE
+	cmp		dh, DEVICE_JRIDE_ISA
+	eCMOVE	ax, cs							; Use segment address for JR-IDE/ISA
+%endif
+
+	push	bp								; setup stack for call to
+	mov		bp, sp							; BootMenuPrint_FormatCSSIfromParamsInSSBP
+
+	push 	cx								; Push "Master" or "Slave"
+
+	mov		cl, (g_szDetectPort-$$) & 0xff	; Setup print string for standard IDE
+											; Note that we modify only the low order bits of CX a lot here,
+											; saving code space rather than reloading CX completely.
+											; This optimization requires that all the g_szDetect* strings are
+											; on the same 256 byte page, which is checked in strings.asm.
+
+%ifdef MODULE_SERIAL
+	cmp		dh, DEVICE_SERIAL_PORT		  	; Check if this is a serial device
+
+	jnz		.pushAndPrint					; CX = string to print, AX = port address, DX won't be used
+
+	mov		cl, (g_szDetectCOM-$$) & 0xff	; Setup print string for COM ports
+	push	cx								; And push now.  We use the fact that format strings can contain
+											; themselves format strings.
+
+	push	dx								; Push COM number character
+											; If the string is going to be "Auto", we will push a NULL (zero)
+											; here for the COM port number, which will be eaten by the
+											; print routine (DisplayPrint_CharacterFromAL), resulting in
+											; just "COM" being printed without a character after it.
+
+ 	mov		cl, (g_szDetectCOMAuto-$$) & 0xff	; Setup secondary print string for "Auto"
+
+	test	dl, dl							; Check if serial port "Auto"
+	jz		.pushAndPrintSerial				; CX = string to print, AX and DX won't be used
+
+	mov		cl, (g_szDetectCOMLarge-$$) & 0xff	; Setup secondary print string for "COMn/xx.yK"
+
+	mov		al,ah							; baud rate divisor to AL
+	cbw										; clear AH, AL will always be less than 128
+	xchg	si,ax							; move AX to SI for divide
+	mov		ax,1152							; baud rate to display is 115200/divisor, the "00" is handled
+											; in the print strings
+	cwd										; clear top 16-bits of dividend
+	div		si								; and divide...  Now AX = baud rate/100, DX = 0 (always a clean divide)
+
+	mov		si,10							; Now separate the whole portion from the fractional for "K" display
+	div		si								; and divide...  Now AX = baud rate/1000, DX = low order digit
+
+	cmp		ax,si							; < 10: "2400", "9600", etc.; >= 10: "19.2K", "38.4K", etc.
+	jae		.pushAndPrintSerial
+
+	mov		cl, (g_szDetectCOMSmall-$$) & 0xff	; Setup secondary print string for "COMn/XXy00"
+
+.pushAndPrintSerial:
+.pushAndPrint:
+%endif
+
+	push	cx								; Push print string
+	push	ax								; Push high order digits, or port address, or N/A
+	push	dx								; Push low order digit, or N/A
+
+	mov		si, g_szDetectOuter				; Load SI with default wrapper string "IDE %s at %s: "
+
+	jmp		short DetectPrint_BootMenuPrint_FormatCSSIfromParamsInSSBP_Relay
+
+
+;--------------------------------------------------------------------
+; DetectPrint_DriveNameFromBootnfoInESBX
+;	Parameters:
+;		ES:BX:	Ptr to BOOTMENUINFO (if drive found)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, SI
+;--------------------------------------------------------------------
+DetectPrint_DriveNameFromBootnfoInESBX:
+	push	di
+	push	bx
+
+	lea		si, [bx+BOOTMENUINFO.szDrvName]
+	mov		bx, es
+	CALL_DISPLAY_LIBRARY PrintNullTerminatedStringFromBXSI
+	CALL_DISPLAY_LIBRARY PrintNewlineCharacters
+
+	pop		bx
+	pop		di
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/DriveXlate.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/DriveXlate.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/DriveXlate.asm	(revision 352)
@@ -0,0 +1,87 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for swapping drive letters.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; DriveXlate_ToOrBack
+;	Parameters:
+;		DL:		Drive number to be possibly translated
+;		DS:		RAMVARS segment
+;	Returns:
+;		DL:		Translated drive number
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DriveXlate_ToOrBack:
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_DRVXLAT
+	jz		SHORT .Return			; Return if translation disabled
+	xchg	di, ax					; Backup AX
+
+	mov		ah, 80h					; Assume hard disk
+	mov		al, [RAMVARS.xlateVars+XLATEVARS.bHDSwap]
+	test	dl, ah					; Hard disk?
+	jnz		SHORT .SwapDrive		; If so, jump to swap
+	mov		al, [RAMVARS.xlateVars+XLATEVARS.bFDSwap]
+	cbw
+
+ALIGN JUMP_ALIGN
+.SwapDrive:
+	cmp		ah, dl					; Swap DL from 00h/80h to xxh?
+	je		SHORT .SwapToXXhInAL
+	cmp		al, dl					; Swap DL from xxh to 00h/80h?
+	jne		SHORT .RestoreAXandReturn
+	mov		al, ah
+ALIGN JUMP_ALIGN
+.SwapToXXhInAL:
+	mov		dl, al
+ALIGN JUMP_ALIGN
+.RestoreAXandReturn:
+	xchg	ax, di					; Restore AX
+ALIGN JUMP_ALIGN, ret
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; Resets drive swapping variables to defaults (no swapping).
+;
+; DriveXlate_Reset
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DriveXlate_Reset:
+	mov		WORD [RAMVARS.xlateVars+XLATEVARS.wFDandHDswap], 8000h
+	ret
+
+
+;--------------------------------------------------------------------
+; Stores drive to be swapped.
+;
+; DriveXlate_SetDriveToSwap
+;	Parameters:
+;		DL:		Drive to swap to 00h or 80h
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+DriveXlate_SetDriveToSwap:
+	test	dl, dl				; Floppy drive?
+	js		SHORT .SetHardDiskToSwap
+.SetFloppyDriveToSwap:
+	mov		[RAMVARS.xlateVars+XLATEVARS.bFDSwap], dl
+	ret
+ALIGN JUMP_ALIGN
+.SetHardDiskToSwap:
+	mov		[RAMVARS.xlateVars+XLATEVARS.bHDSwap], dl
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/FloppyDrive.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/FloppyDrive.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/FloppyDrive.asm	(revision 352)
@@ -0,0 +1,210 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Various floppy drive related functions that
+;					Boot Menu uses.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Checks is floppy drive handler installed to interrupt vector 40h.
+;
+; FloppyDrive_IsInt40hInstalled
+;	Parameters:
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		CF:		Set if INT 40h is installed
+;				Cleared if INT 40h is not installed
+;	Corrupts registers:
+;		BX, CX, DI
+;--------------------------------------------------------------------
+FloppyDrive_IsInt40hInstalled:
+	cmp		WORD [es:BIOS_DISKETTE_INTERRUPT_40h*4+2], 0C000h	; Any ROM segment?
+%ifdef USE_AT	; No need to verify on XT systems.
+	jb		SHORT .Int40hHandlerIsNotInstalled
+	call	.VerifyInt40hHandlerSinceSomeBiosesSimplyReturnFromInt40h
+.Int40hHandlerIsNotInstalled:
+%endif
+	cmc
+	ret
+
+;--------------------------------------------------------------------
+; .VerifyInt40hHandlerSinceSomeBiosesSimplyReturnFromInt40h
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CF:		Cleared if INT 40h is installed
+;				Set if INT 40h is not installed
+;	Corrupts registers:
+;		BX, CX, DI
+;--------------------------------------------------------------------
+%ifdef USE_AT
+.VerifyInt40hHandlerSinceSomeBiosesSimplyReturnFromInt40h:
+	push	es
+	push	dx
+	push	ax
+
+	call	.LoadInt40hVerifyParameters
+	int		BIOS_DISK_INTERRUPT_13h
+	jc		SHORT .Int40hIsInstalled	; Maybe there are not any floppy drives at all
+	push	es
+	push	di
+
+	call	.LoadInt40hVerifyParameters
+	int		BIOS_DISKETTE_INTERRUPT_40h
+
+	pop		dx
+	pop		cx
+	cmp		dx, di						; Difference in offsets?
+	jne		SHORT .Int40hNotInstalled
+	mov		dx, es
+	cmp		cx, dx						; Difference in segments?
+	je		SHORT .Int40hIsInstalled
+.Int40hNotInstalled:
+	stc
+.Int40hIsInstalled:
+	pop		ax
+	pop		dx
+	pop		es
+	ret
+
+;--------------------------------------------------------------------
+; .LoadInt40hVerifyParameters
+;	Parameters:
+;		Nothing
+;	Returns:
+;		AH:		08h (Get Drive Parameters)
+;		DL:		00h (floppy drive)
+;		ES:DI:	0:0h (to guard against BIOS bugs)
+;	Corrupts registers:
+;		DH
+;--------------------------------------------------------------------
+.LoadInt40hVerifyParameters:
+	mov		ah, 08h				; Get Drive Parameters
+	cwd							; Floppy drive 0
+	mov		di, dx
+	mov		es, dx				; ES:DI = 0000:0000h to guard against BIOS bugs
+	ret
+%endif
+
+
+;--------------------------------------------------------------------
+; Returns floppy drive type.
+; PC/XT system do not support AH=08h but FLOPPY_TYPE_525_OR_35_DD
+; is still returned for them.
+;
+; FloppyDrive_GetType
+;	Parameters:
+;		DL:		Floppy Drive number
+;	Returns:
+;		BX:		Floppy Drive Type:
+;					FLOPPY_TYPE_525_OR_35_DD
+;					FLOPPY_TYPE_525_DD
+;					FLOPPY_TYPE_525_HD
+;					FLOPPY_TYPE_35_DD
+;					FLOPPY_TYPE_35_HD
+;					FLOPPY_TYPE_35_ED
+;		CF:		Set if AH=08h not supported (XT systems) or error
+;				Cleared if type read correctly (AT systems)
+;	Corrupts registers:
+;		AX, CX, DX, DI, ES
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FloppyDrive_GetType:
+	mov		ah, 08h			; Get Drive Parameters
+	xor		bx, bx			; FLOPPY_TYPE_525_OR_35_DD when function not supported
+	int		BIOS_DISKETTE_INTERRUPT_40h
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns number of Floppy Drives in system.
+;
+; FloppyDrive_GetCountToAX
+;	Parameters:
+;		DS:		RAMVARS Segment
+;	Returns:
+;		AX:		Number of Floppy Drives
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FloppyDrive_GetCountToAX:
+%ifdef MODULE_SERIAL_FLOPPY
+	call	RamVars_UnpackFlopCntAndFirstToAL
+	js		.UseBIOSorBDA				; We didn't add in any drives, counts here are not valid
+
+	adc		al,1						; adds in the drive count bit, and adds 1 for count vs. 0-index,
+	jmp		.FinishCalc					; need to clear AH on the way out, and add in minimum drive numbers
+
+.UseBIOSorBDA:
+%endif
+	call	FloppyDrive_GetCountFromBIOS_or_BDA
+
+.FinishCalc:
+	mov		ah, [cs:ROMVARS.bMinFddCnt]
+	MAX_U	al, ah
+	cbw
+
+	ret
+
+ALIGN JUMP_ALIGN
+FloppyDrive_GetCountFromBIOS_or_BDA:
+	push	es
+
+;--------------------------------------------------------------------
+; Reads Floppy Drive Count from BIOS.
+; Does not work on most XT systems. Call .GetCountFromBDA
+; if this function fails.
+;
+; .GetCountFromBIOS
+;	Parameters:
+;		Nothing
+;	Returns:
+;		AL:		Number of Floppy Drives
+;		CF:		Cleared if successful
+;				Set if BIOS function not supported
+;	Corrupts registers:
+;		ES
+;--------------------------------------------------------------------
+%ifdef USE_AT
+ALIGN JUMP_ALIGN
+.GetCountFromBIOS:
+	push	di
+	push	bx
+	push	cx
+	push	dx
+
+	mov		ah, 08h					; Get Drive Parameters
+	cwd								; Floppy Drive 00h
+	int		BIOS_DISKETTE_INTERRUPT_40h
+	mov		al, dl					; Number of Floppy Drives to AL
+
+	pop		dx
+	pop		cx
+	pop		bx
+	pop		di
+%endif
+
+;--------------------------------------------------------------------
+; Reads Floppy Drive Count (0...4) from BIOS Data Area.
+; This function should be used only if .GetCountFromBIOS fails.
+;
+; .GetCountFromBDA
+;	Parameters:
+;		Nothing
+;	Returns:
+;		AL:		Number of Floppy Drives
+;	Corrupts registers:
+;		AH, ES
+;--------------------------------------------------------------------
+%ifndef USE_AT
+ALIGN JUMP_ALIGN
+.GetCountFromBDA:
+	LOAD_BDA_SEGMENT_TO	es, ax
+	mov		al, [es:BDA.wEquipment]			; Load Equipment WORD low byte
+	mov		ah, al							; Copy it to AH
+	and		ax, 0C001h						; Leave bits 15..14 and 0
+	eROL_IM	ah, 2							; EW low byte bits 7..6 to 1..0
+	add		al, ah							; AL = Floppy Drive count
+%endif
+
+	pop		es
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/Initialize.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/Initialize.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/Initialize.asm	(revision 352)
@@ -0,0 +1,100 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for initializing the BIOS.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Initializes the BIOS.
+; This function is called from main BIOS ROM search routine.
+;
+; Initialize_FromMainBiosRomSearch
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+Initialize_FromMainBiosRomSearch:			; unused entrypoint ok
+	pushf
+	push	es
+	push	ds
+	ePUSHA
+
+	LOAD_BDA_SEGMENT_TO	es, ax
+	sti										; Enable interrupts
+	test	BYTE [es:BDA.bKBFlgs1], (1<<2)	; Clears ZF if CTRL is held down
+	jnz		SHORT .SkipRomInitialization
+
+	; Install INT 19h handler (boot loader) where drives are detected
+	mov		al, BIOS_BOOT_LOADER_INTERRUPT_19h
+	mov		si, Int19h_BootLoaderHandler
+	call	Interrupts_InstallHandlerToVectorInALFromCSSI
+
+.SkipRomInitialization:
+	ePOPA
+	pop		ds
+	pop		es
+	popf
+	retf
+
+
+;--------------------------------------------------------------------
+; Initializes the BIOS variables and detects IDE drives.
+;
+; Initialize_AndDetectDrives
+;	Parameters:
+;		ES:		BDA Segment
+;	Returns:
+;		DS:		RAMVARS segment
+;	Corrupts registers:
+;		All
+;--------------------------------------------------------------------
+Initialize_AndDetectDrives:
+	call	BootMenuPrint_InitializeDisplayContext
+	call	DetectPrint_RomFoundAtSegment
+	call	RamVars_Initialize
+	call	Interrupts_InitializeInterruptVectors
+	call	DetectDrives_FromAllIDEControllers
+	; Fall to .StoreDptPointersToIntVectors
+
+;--------------------------------------------------------------------
+; .StoreDptPointersToIntVectors
+;	Parameters:
+;		DS:		RAMVARS segment
+;		ES:		BDA and interrupt vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		DX, DI
+;--------------------------------------------------------------------
+.StoreDptPointersToIntVectors:
+	mov		dl, 80h
+	call	FindDPT_ForDriveNumberInDL   ; DPT to DS:DI
+	jc		SHORT .FindForDrive81h	; Store nothing if not our drive
+	mov		[es:HD0_DPT_POINTER_41h*4], di
+	mov		[es:HD0_DPT_POINTER_41h*4+2], ds
+.FindForDrive81h:
+	inc		dx
+	call	FindDPT_ForDriveNumberInDL
+	jc		SHORT .ResetDetectedDrives
+	mov		[es:HD1_DPT_POINTER_46h*4], di
+	mov		[es:HD1_DPT_POINTER_46h*4+2], ds
+	; Fall to .ResetDetectedDrives
+
+;--------------------------------------------------------------------
+; .ResetDetectedDrives
+;	Parameters:
+;		DS:		RAMVARS segment
+;		ES:		BDA and interrupt vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		All, except DS and ES
+;--------------------------------------------------------------------
+.ResetDetectedDrives:
+	call	Idepack_FakeToSSBP
+	call	AH0h_ResetAllOurHardDisksAtTheEndOfDriveInitialization
+	add		sp, BYTE EXTRA_BYTES_FOR_INTPACK
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/Interrupts.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/Interrupts.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Initialization/Interrupts.asm	(revision 352)
@@ -0,0 +1,207 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for initializing the BIOS.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Interrupts_InitializeInterruptVectors
+;	Parameters:
+;		DS:		RAMVARS segment
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		All except segments
+;--------------------------------------------------------------------
+Interrupts_InitializeInterruptVectors:
+	; Fall to .InitializeInt13hAnd40h
+
+;--------------------------------------------------------------------
+; .InitializeInt13hAnd40h
+;	Parameters:
+;		DS:		RAMVARS segment
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX, SI, DI
+;--------------------------------------------------------------------
+.InitializeInt13hAnd40h:
+	mov		ax, [es:BIOS_DISK_INTERRUPT_13h*4+2]; Load old INT 13h segment
+	mov		[RAMVARS.fpOldI13h+2], ax			; Store old INT 13h segment
+	xchg	dx, ax
+	mov		ax, [es:BIOS_DISK_INTERRUPT_13h*4]	; Load old INT 13h offset
+	mov		[RAMVARS.fpOldI13h], ax				; Store old INT 13h offset
+
+	; Only store INT 13h handler to 40h if 40h is not already installed.
+	; At least AMI BIOS for 286 stores 40h handler by itself and calls
+	; 40h from 13h. That system locks to infinite loop if we copy 13h to 40h.
+	call	FloppyDrive_IsInt40hInstalled
+	jc		SHORT .Int40hAlreadyInstalled
+	mov		[es:BIOS_DISKETTE_INTERRUPT_40h*4], ax		; Store old INT 13h offset
+	mov		[es:BIOS_DISKETTE_INTERRUPT_40h*4+2], dx	; Store old INT 13h segment
+.Int40hAlreadyInstalled:
+
+	mov		al, BIOS_DISK_INTERRUPT_13h			; INT 13h interrupt vector offset
+	mov		si, Int13h_DiskFunctionsHandler		; Interrupt handler offset
+	call	Interrupts_InstallHandlerToVectorInALFromCSSI
+	; Fall to .InitializeHardwareIrqHandlers
+
+;--------------------------------------------------------------------
+; .InitializeHardwareIrqHandlers
+;	Parameters:
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, CX, DX, SI, DI, AX
+;--------------------------------------------------------------------
+.InitializeHardwareIrqHandlers:
+	call	RamVars_GetIdeControllerCountToCX
+	mov		di, ROMVARS.ideVars0			; CS:SI points to first IDEVARS
+.IdeControllerLoop:
+	mov		al, [cs:di+IDEVARS.bIRQ]
+	add		di, BYTE IDEVARS_size			; Increment to next controller
+	call	.InstallLowOrHighIrqHandler
+	loop	.IdeControllerLoop
+.Return:
+	ret		; This ret is shared with .InstallLowOrHighIrqHandler
+
+;--------------------------------------------------------------------
+; .InstallLowOrHighIrqHandler
+;	Parameters:
+;		AL:		IRQ number, 0 if IRQ disabled
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		BX, SI
+;--------------------------------------------------------------------
+.InstallLowOrHighIrqHandler:
+	test	al, al
+	jz		SHORT .Return	; IRQ not used
+	cmp		al, 8
+	jb		SHORT .InstallLowIrqHandler
+	; Fall to .InstallHighIrqHandler
+
+;--------------------------------------------------------------------
+; .InstallHighIrqHandler
+;	Parameters:
+;		BX:		IRQ number (8...15)
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AL, BX, SI
+;--------------------------------------------------------------------
+.InstallHighIrqHandler:
+	add		al, BYTE HARDWARE_IRQ_8_INTERRUPT_70h - 8	; Interrupt vector number
+	mov		si, IdeIrq_InterruptServiceRoutineForIrqs8to15
+	jmp		SHORT Interrupts_InstallHandlerToVectorInALFromCSSI
+
+;--------------------------------------------------------------------
+; .InstallLowIrqHandler
+;	Parameters:
+;		AL:		IRQ number (0...7)
+;		ES:		BDA and Interrupt Vector segment (zero)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AL, BX, SI
+;--------------------------------------------------------------------
+.InstallLowIrqHandler:
+	add		al, BYTE HARDWARE_IRQ_0_INTERRUPT_08h		; Interrupt vector number
+	mov		si, IdeIrq_InterruptServiceRoutineForIrqs2to7
+	; Fall to Interrupts_InstallHandlerToVectorInALFromCSSI
+
+
+;--------------------------------------------------------------------
+; Interrupts_InstallHandlerToVectorInALFromCSSI
+;	Parameters:
+;		AL:		Interrupt vector number (for example 13h)
+;		ES:		BDA and Interrupt Vector segment (zero)
+;		CS:SI:	Ptr to interrupt handler
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX
+;--------------------------------------------------------------------
+Interrupts_InstallHandlerToVectorInALFromCSSI:
+	mov		bl, 4					; Shift for DWORD offset, MUL smaller than other alternatives
+	mul		bl
+	xchg	ax, bx
+	mov		[es:bx], si				; Store offset
+	mov		[es:bx+2], cs			; Store segment
+	ret
+
+
+;--------------------------------------------------------------------
+; Interrupts_UnmaskInterruptControllerForDriveInDSDI
+;	Parameters:
+;		DS:DI:	Ptr to DPT
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, DX
+;--------------------------------------------------------------------
+Interrupts_UnmaskInterruptControllerForDriveInDSDI:
+	eMOVZX	bx, [di+DPT.bIdevarsOffset]
+	mov		al, [cs:bx+IDEVARS.bIRQ]
+	test	al, al
+	jz		SHORT .Return	; Interrupts disabled
+	cmp		al, 8
+	jb		SHORT .UnmaskLowIrqController
+	; Fall to .UnmaskHighIrqController
+
+;--------------------------------------------------------------------
+; .UnmaskHighIrqController
+;	Parameters:
+;		AL:		IRQ number (8...15)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+.UnmaskHighIrqController:
+	sub		al, 8				; Slave interrupt number
+	mov		dx, SLAVE_8259_IMR
+	call	.ClearBitFrom8259MaskRegister
+	mov		al, 2				; Master IRQ 2 to allow slave IRQs
+	; Fall to .UnmaskLowIrqController
+
+;--------------------------------------------------------------------
+; .UnmaskLowIrqController
+;	Parameters:
+;		AL:		IRQ number (0...7)
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, DX
+;--------------------------------------------------------------------
+.UnmaskLowIrqController:
+	mov		dx, MASTER_8259_IMR
+	; Fall to .ClearBitFrom8259MaskRegister
+
+;--------------------------------------------------------------------
+; .ClearBitFrom8259MaskRegister
+;	Parameters:
+;		AL:		8259 interrupt index (0...7)
+;		DX:		Port address to Interrupt Mask Register
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+.ClearBitFrom8259MaskRegister:
+	push	cx
+	xchg	ax, cx				; IRQ index to CL
+	mov		ch, 1				; Load 1 to be shifted
+	shl		ch, cl				; Shift bit to correct position
+	not		ch					; Invert to create bit mask for clearing
+	in		al, dx				; Read Interrupt Mask Register
+	and		al, ch				; Clear wanted bit
+	out		dx, al				; Write modified Interrupt Mask Register
+	pop		cx
+.Return:
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Main.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Main.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Main.asm	(revision 352)
@@ -0,0 +1,270 @@
+; Project name	:	XTIDE Universal BIOS
+; Authors		:	Tomi Tilli
+;				:	aitotat@gmail.com
+;				:
+;				:	Greg Lindhorst
+;				:	gregli@hotmail.com
+;				;
+;				:	Krister Nordvall
+;				:	krille_n_@hotmail.com
+;				:
+; Description	:	Main file for BIOS. This is the only file that needs
+;					to be compiled since other files are included to this
+;					file (so no linker needed, Nasm does it all).
+
+	ORG 0							; Code start offset 0000h
+
+%define MENUEVENT_INLINE_OFFSETS    ; Only one menu required, save space and inline offsets
+
+	; Included .inc files
+	%include "AssemblyLibrary.inc"	; Assembly Library. Must be included first!
+	%include "IntController.inc"	; For Interrupt Controller equates
+	%include "ATA_ID.inc"			; For ATA Drive Information structs
+	%include "IdeRegisters.inc"		; For ATA Registers, flags and commands
+	%include "Int13h.inc"			; Equates for INT 13h functions
+%ifdef MODULE_EBIOS
+	%include "EBIOS.inc"			; Equates for EBIOS functions
+%endif
+	%include "CustomDPT.inc"		; For Disk Parameter Table
+	%include "RomVars.inc"			; For ROMVARS and IDEVARS structs
+	%include "RamVars.inc"			; For RAMVARS struct
+	%include "BootVars.inc"			; For BOOTVARS struct
+	%include "BootMenu.inc"			; For Boot Menu
+	%include "IDE_8bit.inc"			; For IDE 8-bit data port macros
+	%include "DeviceIDE.inc"		; For IDE device equates
+
+
+; Section containing code
+SECTION .text
+
+; ROM variables (must start at offset 0)
+CNT_ROM_BLOCKS		EQU		ROMSIZE / 512		; number of 512B blocks, 16 = 8kB BIOS
+istruc ROMVARS
+	at	ROMVARS.wRomSign,	dw	0AA55h			; PC ROM signature
+	at	ROMVARS.bRomSize,	db	CNT_ROM_BLOCKS	; ROM size in 512B blocks
+	at	ROMVARS.rgbJump,	jmp	Initialize_FromMainBiosRomSearch
+	at	ROMVARS.rgbSign,	db	"XTIDE200"		; Signature for flash program
+	at	ROMVARS.szTitle
+		db	"-=XTIDE Universal BIOS"
+%ifdef USE_AT
+		db	" (AT)=-",NULL
+%elifdef USE_186
+		db	" (XT+)=-",NULL
+%else
+		db	" (XT)=-",NULL
+%endif
+	at	ROMVARS.szVersion,	db	"v2.0.0",BETA,"1 (",__DATE__,")",NULL
+
+;;; For OR'ing into wFlags below
+;;;
+%ifdef MODULE_SERIAL
+	MAIN_FLG_MODULE_SERIAL	equ	FLG_ROMVARS_MODULE_SERIAL
+%else
+	MAIN_FLG_MODULE_SERIAL	equ	0
+%endif
+
+%ifdef MODULE_EBIOS
+	MAIN_FLG_MODULE_EBIOS	equ	FLG_ROMVARS_MODULE_EBIOS
+%else
+	MAIN_FLG_MODULE_EBIOS	equ	0
+%endif
+
+%ifdef MODULE_JRIDE
+	MAIN_FLG_MODULE_JRIDE	equ	FLG_ROMVARS_MODULE_JRIDE
+%else
+	MAIN_FLG_MODULE_JRIDE	equ	0
+%endif
+
+
+;---------------------------;
+; AT Build default settings ;
+;---------------------------;
+%ifdef USE_AT
+	at	ROMVARS.wFlags,			dw	FLG_ROMVARS_FULLMODE | FLG_ROMVARS_DRVXLAT | MAIN_FLG_MODULE_SERIAL | MAIN_FLG_MODULE_EBIOS | MAIN_FLG_MODULE_JRIDE
+	at	ROMVARS.wDisplayMode,	dw	DEFAULT_TEXT_MODE
+	at	ROMVARS.wBootTimeout,	dw	BOOT_MENU_DEFAULT_TIMEOUT
+	at	ROMVARS.bIdeCnt,		db	4						; Number of supported controllers
+	at	ROMVARS.bBootDrv,		db	80h						; Boot Menu default drive
+	at	ROMVARS.bMinFddCnt, 	db	0						; Do not force minimum number of floppy drives
+	at	ROMVARS.bStealSize,		db	1						; Steal 1kB from base memory
+
+	at	ROMVARS.ideVars0+IDEVARS.wPort,			dw	DEVICE_ATA_DEFAULT_PORT 		; Controller Command Block base port
+	at	ROMVARS.ideVars0+IDEVARS.wPortCtrl,		dw	DEVICE_ATA_DEFAULT_PORTCTRL 	; Controller Control Block base port
+	at	ROMVARS.ideVars0+IDEVARS.bDevice,		db	DEVICE_16BIT_ATA
+	at	ROMVARS.ideVars0+IDEVARS.bIRQ,			db	0
+	at	ROMVARS.ideVars0+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars0+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+
+	at	ROMVARS.ideVars1+IDEVARS.wPort,			dw	170h			; Controller Command Block base port
+	at	ROMVARS.ideVars1+IDEVARS.wPortCtrl,		dw	370h			; Controller Control Block base port
+	at	ROMVARS.ideVars1+IDEVARS.bDevice,		db	DEVICE_16BIT_ATA
+	at	ROMVARS.ideVars1+IDEVARS.bIRQ,			db	0
+	at	ROMVARS.ideVars1+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars1+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+
+	at	ROMVARS.ideVars2+IDEVARS.wPort,			dw	DEVICE_XTIDE_DEFAULT_PORT			; Controller Command Block base port
+	at	ROMVARS.ideVars2+IDEVARS.wPortCtrl,		dw	DEVICE_XTIDE_DEFAULT_PORTCTRL		; Controller Control Block base port
+	at	ROMVARS.ideVars2+IDEVARS.bDevice,		db	DEVICE_8BIT_DUAL_PORT_XTIDE
+	at	ROMVARS.ideVars2+IDEVARS.bIRQ,			db	0
+	at	ROMVARS.ideVars2+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars2+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+
+	at	ROMVARS.ideVars3+IDEVARS.wPort,			dw	168h			; Controller Command Block base port
+	at	ROMVARS.ideVars3+IDEVARS.wPortCtrl,		dw	368h			; Controller Control Block base port
+	at	ROMVARS.ideVars3+IDEVARS.bDevice,		db	DEVICE_16BIT_ATA
+	at	ROMVARS.ideVars3+IDEVARS.bIRQ,			db	0
+	at	ROMVARS.ideVars3+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars3+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+
+%ifdef MODULE_SERIAL
+	at	ROMVARS.ideVarsSerialAuto+IDEVARS.bDevice,		db	DEVICE_SERIAL_PORT
+%endif
+%else
+;-----------------------------------;
+; XT and XT+ Build default settings ;
+;-----------------------------------;
+	at	ROMVARS.wFlags,			dw	FLG_ROMVARS_DRVXLAT | MAIN_FLG_MODULE_SERIAL | MAIN_FLG_MODULE_EBIOS | MAIN_FLG_MODULE_JRIDE
+	at	ROMVARS.wDisplayMode,	dw	DEFAULT_TEXT_MODE
+	at	ROMVARS.wBootTimeout,	dw	BOOT_MENU_DEFAULT_TIMEOUT
+	at	ROMVARS.bIdeCnt,		db	1						; Number of supported controllers
+	at	ROMVARS.bBootDrv,		db	80h						; Boot Menu default drive
+	at	ROMVARS.bMinFddCnt, 	db	1						; Assume at least 1 floppy drive present if autodetect fails
+	at	ROMVARS.bStealSize,		db	1						; Steal 1kB from base memory in full mode
+
+	at	ROMVARS.ideVars0+IDEVARS.wPort,			dw	DEVICE_XTIDE_DEFAULT_PORT			; Controller Command Block base port
+	at	ROMVARS.ideVars0+IDEVARS.wPortCtrl,		dw	DEVICE_XTIDE_DEFAULT_PORTCTRL		; Controller Control Block base port
+%ifdef MODULE_JRIDE
+	at	ROMVARS.ideVars0+IDEVARS.bDevice,		db	DEVICE_JRIDE_ISA
+%else
+	at	ROMVARS.ideVars0+IDEVARS.bDevice,		db	DEVICE_8BIT_DUAL_PORT_XTIDE
+%endif
+	at	ROMVARS.ideVars0+IDEVARS.bIRQ,			db	0				; IRQ
+	at	ROMVARS.ideVars0+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars0+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+
+	at	ROMVARS.ideVars1+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars1+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+
+	at	ROMVARS.ideVars2+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars2+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+
+	at	ROMVARS.ideVars3+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+	at	ROMVARS.ideVars3+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	db	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE
+
+%ifdef MODULE_SERIAL
+	at	ROMVARS.ideVarsSerialAuto+IDEVARS.bDevice,		db	DEVICE_SERIAL_PORT
+%endif
+%endif
+iend
+
+	; Strings are first to avoid them moving unnessarily when code is turned on and off with %ifdef's
+	; since some groups of strings need to be on the same 256-byte page.
+	;
+%ifdef MODULE_STRINGS_COMPRESSED
+	%define STRINGSCOMPRESSED_STRINGS
+	%include "StringsCompressed.asm" 
+%else
+	%include "Strings.asm"			; For BIOS message strings
+%endif
+
+	; Libraries, data, Initialization and drive detection
+
+	%include "AssemblyLibrary.asm"
+
+	; String compression tables need to come after the AssemblyLibrary (since they depend on addresses
+	; established in the assembly library), and are unncessary if strings are not compressed.
+	;
+%ifdef MODULE_STRINGS_COMPRESSED
+	%undef  STRINGSCOMPRESSED_STRINGS		
+	%define STRINGSCOMPRESSED_TABLES
+	%include "StringsCompressed.asm"
+%endif
+		
+	%include "Initialize.asm"		; For BIOS initialization
+	%include "Interrupts.asm"		; For Interrupt initialization
+	%include "RamVars.asm"			; For RAMVARS initialization and access
+	%include "CreateDPT.asm"		; For creating DPTs
+	%include "FindDPT.asm"			; For finding DPTs
+	%include "AccessDPT.asm"		; For accessing DPTs
+	%include "BootMenuInfo.asm"		; For creating BOOTMENUINFO structs
+	%include "AtaID.asm"			; For ATA Identify Device information
+	%include "DetectDrives.asm"		; For detecting IDE drives
+	%include "DetectPrint.asm"		; For printing drive detection strings
+
+	; Boot menu
+	%include "BootMenu.asm"			; For Boot Menu operations
+	%include "BootMenuEvent.asm"	; For menu library event handling
+									; NOTE: BootMenuPrint needs to come immediately after BootMenuEvent
+									;       so that jump table entries in BootMenuEvent stay within 8-bits
+	%include "BootMenuPrint.asm"	; For printing Boot Menu strings, also includes "BootMenuPrintCfg.asm"
+	%include "BootPrint.asm"		; For printing boot information
+	%include "FloppyDrive.asm"		; Floppy Drive related functions
+	%include "BootSector.asm"		; For loading boot sector
+
+	; Boot loader
+	%include "Int19h.asm"			; For Int 19h, Boot Loader
+
+	; For all device types
+	%include "Idepack.asm"
+	%include "Device.asm"
+	%include "Timer.asm"			; For timeout and delay
+
+	; IDE Device support
+%define IDEDEVICE Ide
+%define ASSEMBLE_SHARED_IDE_DEVICE_FUNCTIONS
+	%include "IOMappedIDE.inc"		; Assembly IDE support for normal I/O mapped controllers
+	%include "IdeCommand.asm"
+	%include "IdeTransfer.asm"		; Must be included after IdeCommand.asm
+	%include "IdeWait.asm"
+	%include "IdeError.asm"			; Must be included after IdeWait.asm
+	%include "IdeDPT.asm"
+	%include "IdeIO.asm"
+	%include "IdeIrq.asm"
+%undef IDEDEVICE
+%undef ASSEMBLE_SHARED_IDE_DEVICE_FUNCTIONS
+
+	; JR-IDE support
+%ifdef MODULE_JRIDE
+%define IDEDEVICE MemIde
+	%include "MemMappedIDE.inc"		; Assembly IDE support for memory mapped controllers
+	%include "IdeCommand.asm"
+	%include "MemIdeTransfer.asm"	; Must be included after IdeCommand.asm
+	%include "IdeWait.asm"
+	%include "IdeError.asm"			; Must be included after IdeWait.asm
+%undef IDEDEVICE
+%endif
+
+
+%ifdef MODULE_SERIAL				; Serial Port Device support
+	%include "SerialCommand.asm"
+	%include "SerialDPT.asm"
+%endif
+
+	; INT 13h Hard Disk BIOS functions
+	%include "Int13h.asm"			; For Int 13h, Disk functions
+	%include "AH0h_HReset.asm"		; Required by Int13h_Jump.asm
+	%include "AH1h_HStatus.asm"		; Required by Int13h_Jump.asm
+	%include "AH2h_HRead.asm"		; Required by Int13h_Jump.asm
+	%include "AH3h_HWrite.asm"		; Required by Int13h_Jump.asm
+	%include "AH4h_HVerify.asm"		; Required by Int13h_Jump.asm
+	%include "AH8h_HParams.asm"		; Required by Int13h_Jump.asm
+	%include "AH9h_HInit.asm"		; Required by Int13h_Jump.asm
+	%include "AHCh_HSeek.asm"		; Required by Int13h_Jump.asm
+	%include "AHDh_HReset.asm"		; Required by Int13h_Jump.asm
+	%include "AH10h_HReady.asm"		; Required by Int13h_Jump.asm
+	%include "AH11h_HRecal.asm"		; Required by Int13h_Jump.asm
+	%include "AH15h_HSize.asm"		; Required by Int13h_Jump.asm
+	%include "AH23h_HFeatures.asm"	; Required by Int13h_Jump.asm
+	%include "AH24h_HSetBlocks.asm"	; Required by Int13h_Jump.asm
+	%include "AH25h_HDrvID.asm"		; Required by Int13h_Jump.asm
+	%include "DriveXlate.asm"		; For swapping drive numbers
+	%include "Address.asm"			; For sector address translations
+	%include "Prepare.asm"			; For buffer pointer normalization
+%ifdef MODULE_EBIOS
+	%include "AH42h_ExtendedReadSectors.asm"
+	%include "AH43h_ExtendedWriteSectors.asm"
+	%include "AH44h_ExtendedVerifySectors.asm"
+	%include "AH47h_ExtendedSeek.asm"
+	%include "AH48h_GetExtendedDriveParameters.asm"
+	%include "AH41h_CheckIfExtensionsPresent.asm"
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Strings.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Strings.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/Strings.asm	(revision 352)
@@ -0,0 +1,214 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Strings and equates for BIOS messages.
+
+%ifdef MODULE_STRINGS_COMPRESSED_PRECOMPRESS
+	%include "Display.inc"
+%endif
+
+; Section containing code
+SECTION .text
+
+; The following strings are used by DetectPrint_StartDetectWithMasterOrSlaveStringInCXandIdeVarsInCSBP
+; To support an optimization in that code, these strings must start on the same 256 byte page,
+; which is checked at assembly time below.
+;
+g_szDetectStart:
+g_szDetectMaster:		db	"Master",NULL
+g_szDetectSlave:		db	"Slave ",NULL
+g_szDetectOuter:		db	"%s at %s: ",NULL
+;%%; %ifdef MODULE_SERIAL		;%%; is stripped off after string compression, %ifdef won't compress properly
+g_szDetectCOM:			db  "COM%c%s",NULL
+g_szDetectCOMAuto:		db	" Detect",NULL
+g_szDetectCOMSmall:		db	"/%u%u00",NULL					; IDE Master at COM1/9600:
+g_szDetectCOMLarge:		db	"/%u.%uK",NULL					; IDE Master at COM1/19.2K:
+;%%; %endif						;%%; is stripped off after string compression, %ifdef won't compress properly
+g_szDetectEnd:
+g_szDetectPort:			db	"%x",NULL					   	; IDE Master at 1F0h:
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if ((g_szDetectEnd-$$) & 0xff00) <> ((g_szDetectStart-$$) & 0xff00)
+		%error "g_szDetect* strings must start on the same 256 byte page, required by DetectPrint_StartDetectWithMasterOrSlaveStringInCXandIdeVarsInCSBP.  Please move this block up or down within strings.asm"
+	%endif
+%endif
+
+; Boot Menu Floppy Disk strings
+;
+; The following strings are used by BootMenuPrint_RefreshInformation
+; To support optimizations in that code, these strings must start on the same 256 byte page,
+; which is checked at assembly time below.
+;
+g_szFddStart:
+g_szFddUnknown:	db	"Unknown",NULL
+g_szFddSizeOr:	db	"5",ONE_QUARTER,QUOTATION_MARK," or 3",ONE_HALF,QUOTATION_MARK," DD",NULL
+g_szFddSize:	db	"%s",QUOTATION_MARK,", %u kiB",NULL	; 3½", 1440 kiB
+g_szFddThreeHalf:		db  "3",ONE_HALF,NULL
+g_szFddEnd:
+g_szFddFiveQuarter:		db  "5",ONE_QUARTER,NULL
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if ((g_szFddStart-$$) & 0xff00) <> ((g_szFddEnd-$$) & 0xff00)
+		%error "g_szFdd* strings must start on the same 256 byte page, required by the BootMenuPrint_RefreshInformation routines for floppy drives.  Please move this block up or down within strings.asm"
+	%endif
+%endif
+
+; POST drive detection strings
+g_szRomAt:		db	"%s @ %x",LF,CR
+				db  "Released under GNU GPL v2",LF,CR,LF,CR,NULL
+
+; Boot loader strings
+g_szTryToBoot:			db	"Booting from %s %x",ANGLE_QUOTE_RIGHT,"%x",LF,CR,NULL
+g_szBootSectorNotFound:	db	"Boot sector "
+g_szNotFound:			db	"not found",LF,CR,NULL
+g_szReadError:			db	"Error %x!",LF,CR,NULL
+
+g_szAddressingModes:
+g_szLCHS:		db	"L-CHS",NULL
+g_szPCHS:		db	"P-CHS",NULL
+g_szLBA28:		db	"LBA28",NULL
+g_szLBA48:		db	"LBA48",NULL
+g_szAddressingModes_Displacement equ (g_szPCHS - g_szAddressingModes)
+;
+; Ensure that addressing modes are correctly spaced in memory
+;
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if g_szLCHS <> g_szAddressingModes
+		%error "g_szAddressingModes Displacement Incorrect 1"
+	%endif
+	%if g_szPCHS <> g_szLCHS + g_szAddressingModes_Displacement
+		%error "g_szAddressingModes Displacement Incorrect 2"
+	%endif
+	%if g_szLBA28 <> g_szPCHS + g_szAddressingModes_Displacement
+		%error "g_szAddressingModes Displacement Incorrect 3"
+	%endif
+	%if g_szLBA48 <> g_szLBA28 + g_szAddressingModes_Displacement
+		%error "g_szAddressingModes Displacement Incorrect 4"
+	%endif
+%endif
+
+g_szBusTypeValues:
+g_szBusTypeValues_8Dual:		db		"D8 ",NULL
+g_szBusTypeValues_8Reversed:	db		"X8 ",NULL
+g_szBusTypeValues_8Single:		db		"S8 ",NULL
+g_szBusTypeValues_16:			db		" 16",NULL
+g_szBusTypeValues_32:			db		" 32",NULL
+g_szBusTypeValues_Serial:		db		"SER",NULL
+g_szBusTypeValues_8MemMapped:	db		"M8 ",NULL
+g_szBusTypeValues_Displacement equ (g_szBusTypeValues_8Reversed - g_szBusTypeValues)
+;
+; Ensure that bus type strings are correctly spaced in memory
+;
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if g_szBusTypeValues_8Dual <> g_szBusTypeValues
+		%error "g_szBusTypeValues Displacement Incorrect 1"
+	%endif
+	%if g_szBusTypeValues_8Reversed <> g_szBusTypeValues + g_szBusTypeValues_Displacement
+		%error "g_szBusTypeValues Displacement Incorrect 2"
+	%endif
+	%if g_szBusTypeValues_8Single <> g_szBusTypeValues_8Reversed + g_szBusTypeValues_Displacement
+		%error "g_szBusTypeValues Displacement Incorrect 3"
+	%endif
+	%if g_szBusTypeValues_16 <> g_szBusTypeValues_8Single + g_szBusTypeValues_Displacement
+		%error "g_szBusTypeValues Displacement Incorrect 4"
+	%endif
+	%if g_szBusTypeValues_32 <> g_szBusTypeValues_16 + g_szBusTypeValues_Displacement
+		%error "g_szBusTypeValues Displacement Incorrect 5"
+	%endif
+	%if g_szBusTypeValues_Serial <> g_szBusTypeValues_32 + g_szBusTypeValues_Displacement
+		%error "g_szBusTypeValues Displacement Incorrect 6"
+	%endif
+	%if g_szBusTypeValues_8MemMapped <> g_szBusTypeValues_Serial + g_szBusTypeValues_Displacement
+		%error "g_szBusTypeValues Displacement Incorrect 7"
+	%endif
+%endif
+
+g_szSelectionTimeout:	db		DOUBLE_BOTTOM_LEFT_CORNER,DOUBLE_LEFT_HORIZONTAL_TO_SINGLE_VERTICAL,"%ASelection in %2-u s",NULL
+
+g_szDashForZero:		db		"- ",NULL
+
+; Boot menu bottom of screen strings
+g_szFDD:		db	"FDD     ",NULL
+g_szHDD:		db	"HDD     ",NULL
+g_szRomBoot:	db	"ROM Boot",NULL
+g_szHotkey:		db	"%A%c%c%A%s%A ",NULL
+
+; Boot Menu information strings
+g_szCapacity:			db	"Capacity : %s",NULL
+g_szCapacityNum:		db	"%5-u.%u %ciB",NULL
+g_szInformation:		db	"%s",LF,CR
+	db	"Addr.",SINGLE_VERTICAL,"Block",SINGLE_VERTICAL,"Bus",SINGLE_VERTICAL,  "IRQ",SINGLE_VERTICAL,"Reset",LF,CR
+	db	   "%s",SINGLE_VERTICAL, "%5-u",SINGLE_VERTICAL, "%s",SINGLE_VERTICAL," %2-I",SINGLE_VERTICAL,"%5-x" ,NULL
+
+; Boot Menu menuitem strings
+;
+; The following strings are used by BootMenuPrint_* routines.
+; To support optimizations in that code, these strings must start on the same 256 byte page,
+; which is checked at assembly time below.
+;
+g_szBootMenuPrintStart:
+g_szDriveNum:			db	"%x %s",NULL
+g_szDriveNumBOOTNFO:	db	"%x %z",NULL
+g_szFloppyDrv:			db	"Floppy Drive %c",NULL
+g_szBootMenuPrintEnd:
+g_szForeignHD:			db	"Foreign Hard Disk",NULL
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+	%if ((g_szBootMenuPrintStart-$$) & 0xff00) <> ((g_szBootMenuPrintEnd-$$) & 0xff00)
+		%error "g_szBootMenuPrint* strings must start on the same 256 byte page, required by the BootMenuPrint_* routines.  Please move this block up or down within strings.asm"
+	%endif
+%endif
+		
+;------------------------------------------------------------------------------------------
+;
+; Tables for StringsCompress.pl
+;
+;$translate{ord(' ')} = 0;
+;$translate{172}      = 1;     # ONE_QUARTER
+;$translate{171}      = 2;     # ONE_HALF
+;$translate{179}      = 3;     # SINGLE_VERTICAL
+;$translate{175}      = 4;     # ANGLE_QUOTE_RIGHT
+;$translate{ord('!')} = 5;
+;$translate{ord('"')} = 6;
+;$translate{ord(',')} = 7;
+;$translate{ord('-')} = 8;
+;$translate{ord('.')} = 9;
+;$translate{ord('/')} = 10;
+;$translate{ord('1')} = 11;
+;$translate{ord('2')} = 12;
+;$translate{ord('3')} = 13;
+;$translate{ord('4')} = 14;
+;$translate{ord('5')} = 15;
+;$translate{ord('6')} = 16;
+;$translate{ord('8')} = 17;
+;$translate{200}      = 18;    # DOUBLE_BOTTOM_LEFT_CORNER
+;$translate{181}      = 19;    # DOUBLE_LEFT_HORIZONTAL_TO_SINGLE_VERTICAL
+;$translate{ord('0')} = 20;
+;
+; Formats begin immediately after the last Translated character (they are in the same table)
+;
+;$format_begin = 21;
+;
+;$format{"c"}   = 21;        # n/a
+;$format{"2-I"} = 22;        # must be even
+;$format{"u"}   = 23;        # must be odd
+;$format{"5-u"} = 24;        # must be even
+;$format{"x"}   = 25;        # must be odd
+;$format{"5-x"} = 26;        # must be even
+;$format{"nl"}  = 27;        # n/a
+;$format{"2-u"} = 28;        # must be even
+;$format{"A"}   = 29;        # n/a
+;$format{"s"}   = 30;        # n/a, normal string from DS
+;$format{"z"}   = 31;        # n/a, boot string from BDA
+;
+; NOTE: The last $format cannot exceed 31 (stored in a 5-bit quantity).
+;
+; Starting point for the "normal" range, typically around 0x40 to cover upper and lower case
+; letters.  If lower case 'z' is not used, 0x3a can be a good choice as it adds ':' to the
+; front end.
+;
+;$normal_base = 0x3a;
+;
+; End of StringsCompress.pl information
+;
+;------------------------------------------------------------------------------------------
+
+
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/StringsCompressed.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/StringsCompressed.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/StringsCompressed.asm	(revision 352)
@@ -0,0 +1,544 @@
+;;;======================================================================
+;;;
+;;; This file is generated by StringsCompress.pl from source in Strings.asm
+;;; DO NOT EDIT DIRECTLY - See the makefile for how to rebuild this file.
+;;; This file only needs to be rebuilt if Strings.asm is changed.
+;;;
+;;;======================================================================
+
+%ifdef STRINGSCOMPRESSED_STRINGS
+
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Strings and equates for BIOS messages.
+
+%ifdef MODULE_STRINGS_COMPRESSED_PRECOMPRESS
+%include "Display.inc"
+%endif
+
+; Section containing code
+SECTION .text
+
+; The following strings are used by DetectPrint_StartDetectWithMasterOrSlaveStringInCXandIdeVarsInCSBP
+; To support an optimization in that code, these strings must start on the same 256 byte page,
+; which is checked at assembly time below.
+;
+g_szDetectStart:
+g_szDetectMaster:		; db	"Master",NULL
+                 		; db	 4dh,  61h,  73h,  74h,  65h,  72h,  00h    ; uncompressed
+                 		  db	 53h,  67h,  79h,  7ah,  6bh, 0b8h          ; compressed
+
+g_szDetectSlave:		; db	"Slave ",NULL
+                		; db	 53h,  6ch,  61h,  76h,  65h,  20h,  00h    ; uncompressed
+                		  db	 59h,  72h,  67h,  7ch,  6bh,  00h          ; compressed
+
+g_szDetectOuter:		; db	"%s at %s: ",NULL
+                		; db	 25h,  73h,  20h,  61h,  74h,  20h,  25h,  73h,  3ah,  20h,  00h    ; uncompressed
+                		  db	 3eh,  20h,  67h, 0fah,  3eh,  40h,  00h                            ; compressed
+
+%ifdef MODULE_SERIAL		;%%; is stripped off after string compression, %ifdef won't compress properly
+g_szDetectCOM:			; db  "COM%c%s",NULL
+              			; db   43h,  4fh,  4dh,  25h,  63h,  25h,  73h,  00h    ; uncompressed
+              			  db   49h,  55h,  53h,  35h,  1eh                      ; compressed
+
+g_szDetectCOMAuto:		; db	" Detect",NULL
+                  		; db	 20h,  44h,  65h,  74h,  65h,  63h,  74h,  00h    ; uncompressed
+                  		  db	 20h,  4ah,  6bh,  7ah,  6bh,  69h, 0bah          ; compressed
+
+g_szDetectCOMSmall:		; db	"/%u%u00",NULL					; IDE Master at COM1/9600:
+                   		; db	 2fh,  25h,  75h,  25h,  75h,  30h,  30h,  00h    ; uncompressed
+                   		  db	 2ah,  37h,  37h,  34h,  14h                      ; compressed
+
+g_szDetectCOMLarge:		; db	"/%u.%uK",NULL					; IDE Master at COM1/19.2K:
+                   		; db	 2fh,  25h,  75h,  2eh,  25h,  75h,  4bh,  00h    ; uncompressed
+                   		  db	 2ah,  37h,  29h,  37h,  91h                      ; compressed
+
+%endif						;%%; is stripped off after string compression, %ifdef won't compress properly
+g_szDetectEnd:
+g_szDetectPort:			; db	"%x",NULL					   	; IDE Master at 1F0h:
+               			; db	 25h,  78h,  00h    ; uncompressed
+               			  db	 19h                ; compressed
+
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+%if ((g_szDetectEnd-$$) & 0xff00) <> ((g_szDetectStart-$$) & 0xff00)
+%error "g_szDetect* strings must start on the same 256 byte page, required by DetectPrint_StartDetectWithMasterOrSlaveStringInCXandIdeVarsInCSBP.  Please move this block up or down within strings.asm"
+%endif
+%endif
+
+; Boot Menu Floppy Disk strings
+;
+; The following strings are used by BootMenuPrint_RefreshInformation
+; To support optimizations in that code, these strings must start on the same 256 byte page,
+; which is checked at assembly time below.
+;
+g_szFddStart:
+g_szFddUnknown:	; db	"Unknown",NULL
+               	; db	 55h,  6eh,  6bh,  6eh,  6fh,  77h,  6eh,  00h    ; uncompressed
+               	  db	 5bh,  74h,  71h,  74h,  75h,  7dh, 0b4h          ; compressed
+
+g_szFddSizeOr:	; db	"5",ONE_QUARTER,QUOTATION_MARK," or 3",ONE_HALF,QUOTATION_MARK," DD",NULL
+              	; db	 35h, 0ach,  22h,  20h,  6fh,  72h,  20h,  33h, 0abh,  22h,  20h,  44h,  44h,  00h    ; uncompressed
+              	  db	 2fh,  21h,  26h,  20h,  75h, 0f8h,  2dh,  22h,  26h,  20h,  4ah,  8ah                ; compressed
+
+g_szFddSize:	; db	"%s",QUOTATION_MARK,", %u kiB",NULL	; 3½", 1440 kiB
+            	; db	 25h,  73h,  22h,  2ch,  20h,  25h,  75h,  20h,  6bh,  69h,  42h,  00h    ; uncompressed
+            	  db	 3eh,  26h,  27h,  20h,  37h,  20h,  71h,  6fh,  88h                      ; compressed
+
+g_szFddThreeHalf:		; db  "3",ONE_HALF,NULL
+                 		; db   33h, 0abh,  00h    ; uncompressed
+                 		  db   2dh,  02h          ; compressed
+
+g_szFddEnd:
+g_szFddFiveQuarter:		; db  "5",ONE_QUARTER,NULL
+                   		; db   35h, 0ach,  00h    ; uncompressed
+                   		  db   2fh,  01h          ; compressed
+
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+%if ((g_szFddStart-$$) & 0xff00) <> ((g_szFddEnd-$$) & 0xff00)
+%error "g_szFdd* strings must start on the same 256 byte page, required by the BootMenuPrint_RefreshInformation routines for floppy drives.  Please move this block up or down within strings.asm"
+%endif
+%endif
+
+; POST drive detection strings
+g_szRomAt:		; db	"%s @ %x",LF,CR
+          		; db	 25h,  73h,  20h,  40h,  20h,  25h,  78h,  0ah,  0dh    ; uncompressed
+          		  db	 3eh,  20h, 0c6h,  39h,  3bh                            ; compressed
+
+	; db  "Released under GNU GPL v2",LF,CR,LF,CR,NULL
+	; db   52h,  65h,  6ch,  65h,  61h,  73h,  65h,  64h,  20h,  75h,  6eh,  64h,  65h,  72h,  20h,  47h,  4eh,  55h,  20h,  47h,  50h,  4ch,  20h,  76h,  32h,  0ah,  0dh,  0ah,  0dh,  00h    ; uncompressed
+	  db   58h,  6bh,  72h,  6bh,  67h,  79h,  6bh, 0eah,  7bh,  74h,  6ah,  6bh, 0f8h,  4dh,  54h, 0dbh,  4dh,  56h, 0d2h,  7ch,  2ch,  3bh,  1bh                                              ; compressed
+
+
+; Boot loader strings
+g_szTryToBoot:			; db	"Booting from %s %x",ANGLE_QUOTE_RIGHT,"%x",LF,CR,NULL
+              			; db	 42h,  6fh,  6fh,  74h,  69h,  6eh,  67h,  20h,  66h,  72h,  6fh,  6dh,  20h,  25h,  73h,  20h,  25h,  78h, 0afh,  25h,  78h,  0ah,  0dh,  00h    ; uncompressed
+              			  db	 48h,  75h,  75h,  7ah,  6fh,  74h, 0edh,  6ch,  78h,  75h, 0f3h,  3eh,  20h,  39h,  24h,  39h,  1bh                                              ; compressed
+
+g_szBootSectorNotFound:	; db	"Boot sector "
+                       	; db	 42h,  6fh,  6fh,  74h,  20h,  73h,  65h,  63h,  74h,  6fh,  72h,  20h    ; uncompressed
+                       	  db	 48h,  75h,  75h, 0fah,  79h,  6bh,  69h,  7ah,  75h, 0f8h                ; compressed
+
+g_szNotFound:			; db	"not found",LF,CR,NULL
+             			; db	 6eh,  6fh,  74h,  20h,  66h,  6fh,  75h,  6eh,  64h,  0ah,  0dh,  00h    ; uncompressed
+             			  db	 74h,  75h, 0fah,  6ch,  75h,  7bh,  74h,  6ah,  1bh                      ; compressed
+
+g_szReadError:			; db	"Error %x!",LF,CR,NULL
+              			; db	 45h,  72h,  72h,  6fh,  72h,  20h,  25h,  78h,  21h,  0ah,  0dh,  00h    ; uncompressed
+              			  db	 4bh,  78h,  78h,  75h, 0f8h,  39h,  25h,  1bh                            ; compressed
+
+
+g_szAddressingModes:
+g_szLCHS:		; db	"L-CHS",NULL
+         		; db	 4ch,  2dh,  43h,  48h,  53h,  00h    ; uncompressed
+         		  db	 52h,  28h,  49h,  4eh,  99h          ; compressed
+
+g_szPCHS:		; db	"P-CHS",NULL
+         		; db	 50h,  2dh,  43h,  48h,  53h,  00h    ; uncompressed
+         		  db	 56h,  28h,  49h,  4eh,  99h          ; compressed
+
+g_szLBA28:		; db	"LBA28",NULL
+          		; db	 4ch,  42h,  41h,  32h,  38h,  00h    ; uncompressed
+          		  db	 52h,  48h,  47h,  2ch,  11h          ; compressed
+
+g_szLBA48:		; db	"LBA48",NULL
+          		; db	 4ch,  42h,  41h,  34h,  38h,  00h    ; uncompressed
+          		  db	 52h,  48h,  47h,  2eh,  11h          ; compressed
+
+g_szAddressingModes_Displacement equ (g_szPCHS - g_szAddressingModes)
+;
+; Ensure that addressing modes are correctly spaced in memory
+;
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+%if g_szLCHS <> g_szAddressingModes
+%error "g_szAddressingModes Displacement Incorrect 1"
+%endif
+%if g_szPCHS <> g_szLCHS + g_szAddressingModes_Displacement
+%error "g_szAddressingModes Displacement Incorrect 2"
+%endif
+%if g_szLBA28 <> g_szPCHS + g_szAddressingModes_Displacement
+%error "g_szAddressingModes Displacement Incorrect 3"
+%endif
+%if g_szLBA48 <> g_szLBA28 + g_szAddressingModes_Displacement
+%error "g_szAddressingModes Displacement Incorrect 4"
+%endif
+%endif
+
+g_szBusTypeValues:
+g_szBusTypeValues_8Dual:		; db		"D8 ",NULL
+                        		; db		 44h,  38h,  20h,  00h    ; uncompressed
+                        		  db		 4ah,  31h,  00h          ; compressed
+
+g_szBusTypeValues_8Reversed:	; db		"X8 ",NULL
+                            	; db		 58h,  38h,  20h,  00h    ; uncompressed
+                            	  db		 5eh,  31h,  00h          ; compressed
+
+g_szBusTypeValues_8Single:		; db		"S8 ",NULL
+                          		; db		 53h,  38h,  20h,  00h    ; uncompressed
+                          		  db		 59h,  31h,  00h          ; compressed
+
+g_szBusTypeValues_16:			; db		" 16",NULL
+                     			; db		 20h,  31h,  36h,  00h    ; uncompressed
+                     			  db		 20h,  2bh,  10h          ; compressed
+
+g_szBusTypeValues_32:			; db		" 32",NULL
+                     			; db		 20h,  33h,  32h,  00h    ; uncompressed
+                     			  db		 20h,  2dh,  0ch          ; compressed
+
+g_szBusTypeValues_Serial:		; db		"SER",NULL
+                         		; db		 53h,  45h,  52h,  00h    ; uncompressed
+                         		  db		 59h,  4bh,  98h          ; compressed
+
+g_szBusTypeValues_8MemMapped:	; db		"M8 ",NULL
+                             	; db		 4dh,  38h,  20h,  00h    ; uncompressed
+                             	  db		 53h,  31h,  00h          ; compressed
+
+g_szBusTypeValues_Displacement equ (g_szBusTypeValues_8Reversed - g_szBusTypeValues)
+;
+; Ensure that bus type strings are correctly spaced in memory
+;
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+%if g_szBusTypeValues_8Dual <> g_szBusTypeValues
+%error "g_szBusTypeValues Displacement Incorrect 1"
+%endif
+%if g_szBusTypeValues_8Reversed <> g_szBusTypeValues + g_szBusTypeValues_Displacement
+%error "g_szBusTypeValues Displacement Incorrect 2"
+%endif
+%if g_szBusTypeValues_8Single <> g_szBusTypeValues_8Reversed + g_szBusTypeValues_Displacement
+%error "g_szBusTypeValues Displacement Incorrect 3"
+%endif
+%if g_szBusTypeValues_16 <> g_szBusTypeValues_8Single + g_szBusTypeValues_Displacement
+%error "g_szBusTypeValues Displacement Incorrect 4"
+%endif
+%if g_szBusTypeValues_32 <> g_szBusTypeValues_16 + g_szBusTypeValues_Displacement
+%error "g_szBusTypeValues Displacement Incorrect 5"
+%endif
+%if g_szBusTypeValues_Serial <> g_szBusTypeValues_32 + g_szBusTypeValues_Displacement
+%error "g_szBusTypeValues Displacement Incorrect 6"
+%endif
+%if g_szBusTypeValues_8MemMapped <> g_szBusTypeValues_Serial + g_szBusTypeValues_Displacement
+%error "g_szBusTypeValues Displacement Incorrect 7"
+%endif
+%endif
+
+g_szSelectionTimeout:	; db		DOUBLE_BOTTOM_LEFT_CORNER,DOUBLE_LEFT_HORIZONTAL_TO_SINGLE_VERTICAL,"%ASelection in %2-u s",NULL
+                     	; db		0c8h, 0b5h,  25h,  41h,  53h,  65h,  6ch,  65h,  63h,  74h,  69h,  6fh,  6eh,  20h,  69h,  6eh,  20h,  25h,  32h,  2dh,  75h,  20h,  73h,  00h    ; uncompressed
+                     	  db		 32h,  33h,  3dh,  59h,  6bh,  72h,  6bh,  69h,  7ah,  6fh,  75h, 0f4h,  6fh, 0f4h,  3ch,  20h, 0b9h                                              ; compressed
+
+
+g_szDashForZero:		; db		"- ",NULL
+                		; db		 2dh,  20h,  00h    ; uncompressed
+                		  db		 28h,  00h          ; compressed
+
+
+; Boot menu bottom of screen strings
+g_szFDD:		; db	"FDD     ",NULL
+        		; db	 46h,  44h,  44h,  20h,  20h,  20h,  20h,  20h,  00h    ; uncompressed
+        		  db	 4ch,  4ah, 0cah,  20h,  20h,  20h,  00h                ; compressed
+
+g_szHDD:		; db	"HDD     ",NULL
+        		; db	 48h,  44h,  44h,  20h,  20h,  20h,  20h,  20h,  00h    ; uncompressed
+        		  db	 4eh,  4ah, 0cah,  20h,  20h,  20h,  00h                ; compressed
+
+g_szRomBoot:	; db	"ROM Boot",NULL
+            	; db	 52h,  4fh,  4dh,  20h,  42h,  6fh,  6fh,  74h,  00h    ; uncompressed
+            	  db	 58h,  55h, 0d3h,  48h,  75h,  75h, 0bah                ; compressed
+
+g_szHotkey:		; db	"%A%c%c%A%s%A ",NULL
+           		; db	 25h,  41h,  25h,  63h,  25h,  63h,  25h,  41h,  25h,  73h,  25h,  41h,  20h,  00h    ; uncompressed
+           		  db	 3dh,  35h,  35h,  3dh,  3eh,  3dh,  00h                                              ; compressed
+
+
+; Boot Menu information strings
+g_szCapacity:			; db	"Capacity : %s",NULL
+             			; db	 43h,  61h,  70h,  61h,  63h,  69h,  74h,  79h,  20h,  3ah,  20h,  25h,  73h,  00h    ; uncompressed
+             			  db	 49h,  67h,  76h,  67h,  69h,  6fh,  7ah, 0ffh, 0c0h,  1eh                            ; compressed
+
+g_szCapacityNum:		; db	"%5-u.%u %ciB",NULL
+                		; db	 25h,  35h,  2dh,  75h,  2eh,  25h,  75h,  20h,  25h,  63h,  69h,  42h,  00h    ; uncompressed
+                		  db	 38h,  29h,  37h,  20h,  35h,  6fh,  88h                                        ; compressed
+
+g_szInformation:		; db	"%s",LF,CR
+                		; db	 25h,  73h,  0ah,  0dh    ; uncompressed
+                		  db	 3eh,  3bh                ; compressed
+
+	; db	"Addr.",SINGLE_VERTICAL,"Block",SINGLE_VERTICAL,"Bus",SINGLE_VERTICAL,  "IRQ",SINGLE_VERTICAL,"Reset",LF,CR
+	; db	 41h,  64h,  64h,  72h,  2eh, 0b3h,  42h,  6ch,  6fh,  63h,  6bh, 0b3h,  42h,  75h,  73h, 0b3h,  49h,  52h,  51h, 0b3h,  52h,  65h,  73h,  65h,  74h,  0ah,  0dh    ; uncompressed
+	  db	 47h,  6ah,  6ah,  78h,  29h,  23h,  48h,  72h,  75h,  69h,  71h,  23h,  48h,  7bh,  79h,  23h,  4fh,  58h,  57h,  23h,  58h,  6bh,  79h,  6bh,  7ah,  3bh          ; compressed
+
+	; db	   "%s",SINGLE_VERTICAL, "%5-u",SINGLE_VERTICAL, "%s",SINGLE_VERTICAL," %2-I",SINGLE_VERTICAL,"%5-x" ,NULL
+	; db	    25h,  73h, 0b3h,  25h,  35h,  2dh,  75h, 0b3h,  25h,  73h, 0b3h,  20h,  25h,  32h,  2dh,  49h, 0b3h,  25h,  35h,  2dh,  78h,  00h    ; uncompressed
+	  db	    3eh,  23h,  38h,  23h,  3eh,  23h,  20h,  36h,  23h,  1ah                                                                            ; compressed
+
+
+; Boot Menu menuitem strings
+;
+; The following strings are used by BootMenuPrint_* routines.
+; To support optimizations in that code, these strings must start on the same 256 byte page,
+; which is checked at assembly time below.
+;
+g_szBootMenuPrintStart:
+g_szDriveNum:			; db	"%x %s",NULL
+             			; db	 25h,  78h,  20h,  25h,  73h,  00h    ; uncompressed
+             			  db	 39h,  20h,  1eh                      ; compressed
+
+g_szDriveNumBOOTNFO:	; db	"%x %z",NULL
+                    	; db	 25h,  78h,  20h,  25h,  7ah,  00h    ; uncompressed
+                    	  db	 39h,  20h,  1fh                      ; compressed
+
+g_szFloppyDrv:			; db	"Floppy Drive %c",NULL
+              			; db	 46h,  6ch,  6fh,  70h,  70h,  79h,  20h,  44h,  72h,  69h,  76h,  65h,  20h,  25h,  63h,  00h    ; uncompressed
+              			  db	 4ch,  72h,  75h,  76h,  76h, 0ffh,  4ah,  78h,  6fh,  7ch, 0ebh,  15h                            ; compressed
+
+g_szBootMenuPrintEnd:
+g_szForeignHD:			; db	"Foreign Hard Disk",NULL
+              			; db	 46h,  6fh,  72h,  65h,  69h,  67h,  6eh,  20h,  48h,  61h,  72h,  64h,  20h,  44h,  69h,  73h,  6bh,  00h    ; uncompressed
+              			  db	 4ch,  75h,  78h,  6bh,  6fh,  6dh, 0f4h,  4eh,  67h,  78h, 0eah,  4ah,  6fh,  79h, 0b1h                      ; compressed
+
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+%if ((g_szBootMenuPrintStart-$$) & 0xff00) <> ((g_szBootMenuPrintEnd-$$) & 0xff00)
+%error "g_szBootMenuPrint* strings must start on the same 256 byte page, required by the BootMenuPrint_* routines.  Please move this block up or down within strings.asm"
+%endif
+%endif
+
+;------------------------------------------------------------------------------------------
+;
+; Tables for StringsCompress.pl
+;
+;$translate{ord(' ')} = 0;    [StringsCompress Processed]
+;$translate{172}      = 1;     # ONE_QUARTER    [StringsCompress Processed]
+;$translate{171}      = 2;     # ONE_HALF    [StringsCompress Processed]
+;$translate{179}      = 3;     # SINGLE_VERTICAL    [StringsCompress Processed]
+;$translate{175}      = 4;     # ANGLE_QUOTE_RIGHT    [StringsCompress Processed]
+;$translate{ord('!')} = 5;    [StringsCompress Processed]
+;$translate{ord('"')} = 6;    [StringsCompress Processed]
+;$translate{ord(',')} = 7;    [StringsCompress Processed]
+;$translate{ord('-')} = 8;    [StringsCompress Processed]
+;$translate{ord('.')} = 9;    [StringsCompress Processed]
+;$translate{ord('/')} = 10;    [StringsCompress Processed]
+;$translate{ord('1')} = 11;    [StringsCompress Processed]
+;$translate{ord('2')} = 12;    [StringsCompress Processed]
+;$translate{ord('3')} = 13;    [StringsCompress Processed]
+;$translate{ord('4')} = 14;    [StringsCompress Processed]
+;$translate{ord('5')} = 15;    [StringsCompress Processed]
+;$translate{ord('6')} = 16;    [StringsCompress Processed]
+;$translate{ord('8')} = 17;    [StringsCompress Processed]
+;$translate{200}      = 18;    # DOUBLE_BOTTOM_LEFT_CORNER    [StringsCompress Processed]
+;$translate{181}      = 19;    # DOUBLE_LEFT_HORIZONTAL_TO_SINGLE_VERTICAL    [StringsCompress Processed]
+;$translate{ord('0')} = 20;    [StringsCompress Processed]
+;
+; Formats begin immediately after the last Translated character (they are in the same table)
+;
+;$format_begin = 21;    [StringsCompress Processed]
+;
+;$format{"c"}   = 21;        # n/a    [StringsCompress Processed]
+;$format{"2-I"} = 22;        # must be even    [StringsCompress Processed]
+;$format{"u"}   = 23;        # must be odd    [StringsCompress Processed]
+;$format{"5-u"} = 24;        # must be even    [StringsCompress Processed]
+;$format{"x"}   = 25;        # must be odd    [StringsCompress Processed]
+;$format{"5-x"} = 26;        # must be even    [StringsCompress Processed]
+;$format{"nl"}  = 27;        # n/a    [StringsCompress Processed]
+;$format{"2-u"} = 28;        # must be even    [StringsCompress Processed]
+;$format{"A"}   = 29;        # n/a    [StringsCompress Processed]
+;$format{"s"}   = 30;        # n/a, normal string from DS    [StringsCompress Processed]
+;$format{"z"}   = 31;        # n/a, boot string from BDA    [StringsCompress Processed]
+;
+; NOTE: The last $format cannot exceed 31 (stored in a 5-bit quantity).
+;
+; Starting point for the "normal" range, typically around 0x40 to cover upper and lower case
+; letters.  If lower case 'z' is not used, 0x3a can be a good choice as it adds ':' to the
+; front end.
+;
+;$normal_base = 0x3a;    [StringsCompress Processed]
+;
+; End of StringsCompress.pl information
+;
+;------------------------------------------------------------------------------------------
+
+;;; end of input stream
+
+%endif ; STRINGSCOMPRESSED_STRINGS
+
+%ifdef STRINGSCOMPRESSED_TABLES
+
+StringsCompressed_NormalBase     equ   58
+
+StringsCompressed_FormatsBegin   equ   21
+
+StringsCompressed_TranslatesAndFormats: 
+        db     32  ; 0
+        db     172  ; 1
+        db     171  ; 2
+        db     179  ; 3
+        db     175  ; 4
+        db     33  ; 5
+        db     34  ; 6
+        db     44  ; 7
+        db     45  ; 8
+        db     46  ; 9
+        db     47  ; 10
+        db     49  ; 11
+        db     50  ; 12
+        db     51  ; 13
+        db     52  ; 14
+        db     53  ; 15
+        db     54  ; 16
+        db     56  ; 17
+        db     200  ; 18
+        db     181  ; 19
+        db     48  ; 20
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_c)    ; 21
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_2_I)    ; 22
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_u)    ; 23
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_5_u)    ; 24
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_x)    ; 25
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_5_x)    ; 26
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_nl)    ; 27
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_2_u)    ; 28
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_A)    ; 29
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_s)    ; 30
+        db     (DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_z)    ; 31
+
+%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_c || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_c > 255
+%error "DisplayFormatCompressed_Format_c is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_2_I || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_2_I > 255
+%error "DisplayFormatCompressed_Format_2_I is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_u || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_u > 255
+%error "DisplayFormatCompressed_Format_u is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_5_u || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_5_u > 255
+%error "DisplayFormatCompressed_Format_5_u is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_x || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_x > 255
+%error "DisplayFormatCompressed_Format_x is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_5_x || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_5_x > 255
+%error "DisplayFormatCompressed_Format_5_x is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_nl || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_nl > 255
+%error "DisplayFormatCompressed_Format_nl is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_2_u || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_2_u > 255
+%error "DisplayFormatCompressed_Format_2_u is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_A || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_A > 255
+%error "DisplayFormatCompressed_Format_A is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_s || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_s > 255
+%error "DisplayFormatCompressed_Format_s is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%if DisplayFormatCompressed_BaseFormatOffset < DisplayFormatCompressed_Format_z || DisplayFormatCompressed_BaseFormatOffset - DisplayFormatCompressed_Format_z > 255
+%error "DisplayFormatCompressed_Format_z is out of range of DisplayFormatCompressed_BaseFormatOffset"
+%endif
+%endif
+
+;; translated usage stats
+;; 33:1
+;; 32:31
+;; 181:1
+;; 53:2
+;; 48:2
+;; 200:1
+;; 46:3
+;; 179:8
+;; 44:1
+;; 50:3
+;; 51:3
+;; 47:2
+;; 52:1
+;; 172:2
+;; 34:3
+;; 49:1
+;; 56:6
+;; 45:3
+;; 175:1
+;; 171:2
+;; 54:1
+;; total translated: 21
+
+;; format usage stats
+;; A:4
+;; 2-u:1
+;; 5-u:2
+;; x:7
+;; s:12
+;; 5-x:1
+;; nl:8
+;; 2-I:1
+;; c:5
+;; u:6
+;; z:1
+;; total format: 11
+
+;; alphabet usage stats
+;; 58,::2
+;; 59,;:
+;; 60,<:
+;; 61,=:
+;; 62,>:
+;; 63,?:
+;; 64,@:1
+;; 65,A:3
+;; 66,B:9
+;; 67,C:4
+;; 68,D:10
+;; 69,E:2
+;; 70,F:3
+;; 71,G:2
+;; 72,H:4
+;; 73,I:1
+;; 74,J:
+;; 75,K:1
+;; 76,L:4
+;; 77,M:4
+;; 78,N:1
+;; 79,O:2
+;; 80,P:2
+;; 81,Q:1
+;; 82,R:5
+;; 83,S:6
+;; 84,T:
+;; 85,U:2
+;; 86,V:
+;; 87,W:
+;; 88,X:1
+;; 89,Y:
+;; 90,Z:
+;; 91,[:
+;; 92,\:
+;; 93,]:
+;; 94,^:
+;; 95,_:
+;; 96,`:
+;; 97,a:7
+;; 98,b:
+;; 99,c:5
+;; 100,d:6
+;; 101,e:15
+;; 102,f:2
+;; 103,g:2
+;; 104,h:
+;; 105,i:9
+;; 106,j:
+;; 107,k:4
+;; 108,l:5
+;; 109,m:1
+;; 110,n:10
+;; 111,o:17
+;; 112,p:3
+;; 113,q:
+;; 114,r:12
+;; 115,s:7
+;; 116,t:12
+;; 117,u:3
+;; 118,v:3
+;; 119,w:1
+;; 120,x:
+;; 121,y:2
+;; alphabet used count: 42
+%endif ; STRINGSCOMPRESSED_TABLES
+
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/AccessDPT.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/AccessDPT.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/AccessDPT.asm	(revision 352)
@@ -0,0 +1,245 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for accessing DPT data.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; AccessDPT_GetDriveSelectByteToAL
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		AL:		Drive Select Byte
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AccessDPT_GetDriveSelectByteToAL:
+	mov		al, [di+DPT.wFlags]
+	and		al, FLG_DRVNHEAD_LBA | FLG_DRVNHEAD_DRV
+	or		al, MASK_DRVNHEAD_SET	; Bits set to 1 for old drives
+	ret
+
+
+;--------------------------------------------------------------------
+; AccessDPT_GetDeviceControlByteToAL
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		AL:		Device Control Byte
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AccessDPT_GetDeviceControlByteToAL:
+	xor		al, al
+	test	BYTE [di+DPT.bFlagsLow], FLGL_DPT_ENABLE_IRQ
+	jnz		SHORT .EnableDeviceIrq
+	or		al, FLG_DEVCONTROL_nIEN	; Disable IRQ
+.EnableDeviceIrq:
+	ret
+
+
+;--------------------------------------------------------------------
+; AccessDPT_GetLCHStoAXBLBH
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		AX:		Number of L-CHS cylinders
+;		BL:		Number of L-CHS heads
+;		BH:		Number of L-CHS sectors per track
+;	Corrupts registers:
+;		CX, DX
+;--------------------------------------------------------------------
+AccessDPT_GetLCHStoAXBLBH:
+	; Return LBA-assisted CHS if LBA addressing used
+	test	BYTE [di+DPT.bFlagsLow], FLG_DRVNHEAD_LBA
+	jz		SHORT .ConvertPchsToLchs
+
+	call	AccessDPT_GetLbaSectorCountToBXDXAX
+	call	AccessDPT_ConvertSectorCountFromBXDXAXtoLbaAssistedCHSinDXAXBLBH
+	test	dx, dx
+	jnz		SHORT .LimitAXtoMaxLCHScylinders
+	cmp		ax, MAX_LCHS_CYLINDERS
+	jb		SHORT .returnLCHS
+.LimitAXtoMaxLCHScylinders:
+	mov		ax, MAX_LCHS_CYLINDERS
+.returnLCHS:
+	ret
+
+.ConvertPchsToLchs:
+	mov		ax, [di+DPT.wPchsCylinders]
+	mov		bx, [di+DPT.wPchsHeadsAndSectors]
+	; Fall to AccessDPT_ShiftPCHinAXBLtoLCH
+
+
+;--------------------------------------------------------------------
+; AccessDPT_ShiftPCHinAXBLtoLCH
+;	Parameters:
+;		AX:		P-CHS cylinders (1...16383)
+;		BL:		P-CHS heads (1...16)
+;	Returns:
+;		AX:		Number of L-CHS cylinders (1...1024)
+;		BL:		Number of L-CHS heads (1...255)
+;		CX:		Number of bits shifted (4 at most)
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+AccessDPT_ShiftPCHinAXBLtoLCH:
+	xor		cx, cx
+.ShiftLoop:
+	cmp		ax, MAX_LCHS_CYLINDERS		; Need to shift?
+	jbe		SHORT .Return				;  If not, return
+	inc		cx							; Increment shift count
+	shr		ax, 1						; Halve cylinders
+	shl		bl, 1						; Double heads
+	jnz		SHORT .ShiftLoop			; Falls through only on the last (4th) iteration and only if BL was 16 on entry
+	dec		bl							; DOS doesn't support drives with 256 heads so we limit heads to 255
+	; We can save a byte here by using DEC BX if we don't care about BH
+.Return:
+	ret
+
+
+;--------------------------------------------------------------------
+; AccessDPT_GetLbaSectorCountToBXDXAX
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		BX:DX:AX:	48-bit sector count
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+AccessDPT_GetLbaSectorCountToBXDXAX:
+	mov		ax, [di+DPT.twLbaSectors]
+	mov		dx, [di+DPT.twLbaSectors+2]
+	mov		bx, [di+DPT.twLbaSectors+4]
+	ret
+
+
+;--------------------------------------------------------------------
+; Returns pointer to DRVPARAMS for master or slave drive.
+;
+; AccessDPT_GetPointerToDRVPARAMStoCSBX
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		CS:BX:	Ptr to DRVPARAMS
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AccessDPT_GetPointerToDRVPARAMStoCSBX:
+	eMOVZX	bx, [di+DPT.bIdevarsOffset]			; CS:BX points to IDEVARS
+	add		bx, BYTE IDEVARS.drvParamsMaster	; CS:BX points to Master Drive DRVPARAMS
+	test	BYTE [di+DPT.bFlagsLow], FLGL_DPT_SLAVE
+	jz		SHORT .ReturnPointerToDRVPARAMS
+	add		bx, BYTE DRVPARAMS_size				; CS:BX points to Slave Drive DRVPARAMS
+.ReturnPointerToDRVPARAMS:
+	ret
+
+;--------------------------------------------------------------------
+; AccessDPT_GetUnshiftedAddressModeToALZF
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;	Returns:
+;		AL:		Addressing Mode (L-CHS, P-CHS, LBA28, LBA48)
+;               unshifted (still shifted where it is in bFlagsLow)
+;       ZF:     Set based on value in AL
+;	Corrupts registers:
+;		AL
+;--------------------------------------------------------------------
+;
+; Converted to a macro since only called in two places, and the call/ret overhead
+; is not worth it for these two instructions (4 bytes total)
+;
+%macro AccessDPT_GetUnshiftedAddressModeToALZF 0
+	mov		al, [di+DPT.bFlagsLow]
+	and		al, MASKL_DPT_ADDRESSING_MODE
+%endmacro
+
+
+;--------------------------------------------------------------------
+; LBA assist calculation:
+; this is how to fit a big drive into INT13's skimpy size requirements,
+; with a maximum of 8.4G available.
+;
+; total LBAs (as obtained by words 60+61)
+; divided by 63 (sectors per track) (save as value A)
+; Sub 1 from A
+; divide A by 1024 + truncate.
+; == total number of heads to use.
+; add 1
+; this value must be either 16, 32, 64, 128, or 256 (round up)
+; then take the value A above and divide by # of heads
+; to get the # of cylinders to use.
+;
+;
+; so a LBA28 drive will have 268,435,456 as maximum LBAs
+;
+; 10000000h / 63   = 410410h (total cylinders or tracks)
+;   410410h / 1024 = 1041h, which is way more than 256 heads, but 256 is max.
+;   410410h / 256  = 4104h cylinders
+;
+; there's a wealth of information at: http://www.mossywell.com/boot-sequence
+; they show a slightly different approach to LBA assist calulations, but
+; the method here provides compatibility with phoenix BIOS
+;
+; we're using the values from 60+61 here because we're topping out at 8.4G
+; anyway, so there's no need to use the 48bit LBA values.
+;
+; AccessDPT_ConvertSectorCountFromBXDXAXtoLbaAssistedCHStoDXAXBLBH:
+;	Parameters:
+;		BX:DX:AX:	Total number of sectors
+;	Returns:
+;		DX:AX:	Number of cylinders
+;		BH:		Number of sectors per track (always 63)
+;		BL:		Number of heads (16, 32, 64, 128 or 255)
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+AccessDPT_ConvertSectorCountFromBXDXAXtoLbaAssistedCHSinDXAXBLBH:
+	push	bp
+	push	si
+
+	; Value A = Total sector count / 63
+	xor		cx, cx
+	push	cx		; Push zero for bits 48...63
+	push	bx
+	push	dx
+	push	ax						; 64-bit sector count now in stack
+	mov		cl, LBA_ASSIST_SPT
+	mov		bp, sp					; SS:BP now points sector count
+	call	Math_DivQWatSSBPbyCX	; Temporary value A now in stack
+
+	; BX = Number of heads =  A / 1024
+	mov		ax, [bp]
+	mov		dx, [bp+2]
+	mov		bx, [bp+4]
+	call	Size_DivideSizeInBXDXAXby1024andIncrementMagnitudeInCX
+
+	; Heads must be 16, 32, 64, 128 or 256 (round up)
+	mov		bx, 256						; Max number of heads
+	test	dx, dx						; 65536 or more heads?
+	jnz		SHORT .GetNumberOfCylinders
+	mov		cx, 128						; Half BX for rounding up
+.FindMostSignificantBitForHeadSize:
+	cmp		ax, cx
+	jae		SHORT .GetNumberOfCylinders
+	shr		cx, 1
+	shr		bx, 1						; Halve number of heads
+	jmp		SHORT .FindMostSignificantBitForHeadSize
+
+	; DX:AX = Number of cylinders = A / number of heads
+.GetNumberOfCylinders:
+	mov		cx, bx
+	call	Math_DivQWatSSBPbyCX
+	mov		ax, [bp]
+	mov		dx, [bp+2]					; Cylinders now in DX:AX
+
+	; Return LBA assisted CHS
+	add		sp, BYTE 8					; Clean stack
+	sub		bl, bh						; Limit heads to 255
+	mov		bh, LBA_ASSIST_SPT
+	pop		si
+	pop		bp
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/CreateDPT.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/CreateDPT.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/CreateDPT.asm	(revision 352)
@@ -0,0 +1,279 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for creating Disk Parameter Table.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Creates new Disk Parameter Table for detected hard disk.
+; Drive is then fully accessible using any BIOS function.
+;
+; CreateDPT_FromAtaInformation
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;		DS:		RAMVARS segment
+;		ES:		BDA Segment
+;	Returns:
+;		DL:		Drive number for new drive
+;		DS:DI:	Ptr to Disk Parameter Table (if successful)
+;		CF:		Cleared if DPT created successfully
+;				Set if any error
+;	Corrupts registers:
+;		AX, BX, CX, DH
+;--------------------------------------------------------------------
+CreateDPT_FromAtaInformation:
+	call	FindDPT_ForNewDriveToDSDI
+	; Fall to .InitializeDPT
+
+;--------------------------------------------------------------------
+; .InitializeDPT
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		DS:DI:	Ptr to Disk Parameter Table
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+.InitializeDPT:
+	mov		[di+DPT.bIdevarsOffset], bp	; IDEVARS must start in first 256 bytes of ROM
+	; Fall to .StoreDriveSelectAndDriveControlByte
+
+;--------------------------------------------------------------------
+; .StoreDriveSelectAndDriveControlByte
+;	Parameters:
+;		BH:		Drive Select byte for Drive and Head Register
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+.StoreDriveSelectAndDriveControlByte:
+	mov		al, bh
+	and		ax, BYTE FLG_DRVNHEAD_DRV		; AL now has Master/Slave bit
+	cmp		[cs:bp+IDEVARS.bIRQ], ah		; Interrupts enabled?
+	jz		SHORT .StoreFlags				;  If not, do not set interrupt flag
+	or		al, FLGL_DPT_ENABLE_IRQ
+.StoreFlags:
+	mov		[di+DPT.wFlags], ax
+	; Fall to .StoreAddressing
+
+;--------------------------------------------------------------------
+; .StoreAddressing
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+.StoreAddressing:
+	; Check if CHS defined in ROMVARS
+	call	AccessDPT_GetPointerToDRVPARAMStoCSBX
+	test	byte [cs:bx+DRVPARAMS.wFlags], FLG_DRVPARAMS_USERCHS    ; User specified CHS?
+	jnz		SHORT .StoreUserDefinedPCHS
+
+	; Check if LBA supported
+	call	AtaID_GetPCHStoAXBLBHfromAtaInfoInESSI
+	test	BYTE [es:si+ATA1.wCaps+1], A1_wCaps_LBA>>8
+	jz		SHORT .StoreCHSfromAXBHBL		; Small old drive with CHS addressing only
+
+	; Store LBA 28/48 addressing and total sector count
+	call	AtaID_GetTotalSectorCountToBXDXAXfromAtaInfoInESSI
+	call	StoreLbaAddressingAndTotalSectorCountFromBXDXAX
+
+	; Replace sector count with user defined if necessary
+	call	AccessDPT_GetPointerToDRVPARAMStoCSBX
+	test	BYTE [cs:bx+DRVPARAMS.wFlags], FLG_DRVPARAMS_USERLBA
+	jz		SHORT .KeepTotalSectorsFromAtaID
+	mov		ax, [cs:bx+DRVPARAMS.dwMaximumLBA]
+	mov		dx, [cs:bx+DRVPARAMS.dwMaximumLBA+2]
+	xor		bx, bx
+
+	; Compare user defined and ATA-ID sector count and select smaller
+	cmp		bx, [di+DPT.twLbaSectors+4]
+	jb		SHORT .StoreUserDefinedSectorCountToDPT
+	cmp		dx, [di+DPT.twLbaSectors+2]
+	jb		SHORT .StoreUserDefinedSectorCountToDPT
+	ja		SHORT .KeepTotalSectorsFromAtaID
+	cmp		ax, [di+DPT.twLbaSectors]
+	jae		SHORT .KeepTotalSectorsFromAtaID
+.StoreUserDefinedSectorCountToDPT:
+	call	StoreLbaAddressingAndTotalSectorCountFromBXDXAX
+
+	; Calculate L-CHS for old INT 13h
+.KeepTotalSectorsFromAtaID:
+	mov		bx, [di+DPT.twLbaSectors+4]		; Restore BX
+	call	AccessDPT_ConvertSectorCountFromBXDXAXtoLbaAssistedCHSinDXAXBLBH
+	mov		[di+DPT.bLbaHeads], bl
+	jmp		SHORT .StoreBlockMode
+
+;--------------------------------------------------------------------
+; .StoreUserDefinedPCHS
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		AX:		Number of P-CHS cylinders
+;		BH:		Number of P-CHS sectors per track
+;		BL:		Number of P-CHS heads
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+.StoreUserDefinedPCHS:
+	call	AccessDPT_GetPointerToDRVPARAMStoCSBX
+	mov		ax, [cs:bx+DRVPARAMS.wCylinders]
+	mov		bx, [cs:bx+DRVPARAMS.wHeadsAndSectors]
+	; Fall to .StoreCHSfromAXBHBL
+
+;--------------------------------------------------------------------
+; .StoreCHSfromAXBHBL
+;	Parameters:
+;		AX:		Number of P-CHS cylinders
+;		BH:		Number of P-CHS sectors per track
+;		BL:		Number of P-CHS heads
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		AX:		Number of P-CHS cylinders
+;		BH:		Number of P-CHS sectors per track
+;		BL:		Number of P-CHS heads
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+.StoreCHSfromAXBHBL:
+	push	ax
+	push	bx
+	call	AccessDPT_ShiftPCHinAXBLtoLCH	; Get number of bits to shift
+	pop		bx
+	pop		ax
+	jcxz	.StorePCHSfromAXDX				; Small drive so use L-CHS addressing
+
+	; Store P-CHS addressing mode and number of bits to shift in L-CHS to P-CHS translation
+	or		cl, ADDRESSING_MODE_PCHS<<ADDRESSING_MODE_FIELD_POSITION
+	or		[di+DPT.bFlagsLow], cl
+	; Fall to .StoreChsFromAXBLBH
+
+;--------------------------------------------------------------------
+; .StoreChsFromAXBLBH
+;	Parameters:
+;		AX:		Number of P-CHS cylinders
+;		BH:		Number of P-CHS sectors per track
+;		BL:		Number of P-CHS heads
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+.StorePCHSfromAXDX:
+	mov		[di+DPT.wPchsCylinders], ax
+	mov		[di+DPT.wPchsHeadsAndSectors], bx
+	; Fall to .StoreBlockMode
+
+;--------------------------------------------------------------------
+; .StoreBlockMode
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+.StoreBlockMode:
+	cmp		BYTE [es:si+ATA1.bBlckSize], 1	; Max block size in sectors
+	jbe		SHORT .BlockModeTransfersNotSupported
+	or		BYTE [di+DPT.bFlagsHigh], FLGH_DPT_BLOCK_MODE_SUPPORTED
+.BlockModeTransfersNotSupported:
+	; Fall to .StoreDeviceSpecificParameters
+
+;--------------------------------------------------------------------
+; .StoreDeviceSpecificParameters
+;	Parameters:
+;		DS:DI:	Ptr to Disk Parameter Table
+;		ES:SI:	Ptr to 512-byte ATA information read from the drive
+;		CS:BP:	Ptr to IDEVARS for the controller
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX, BX, CX, DX
+;--------------------------------------------------------------------
+.StoreDeviceSpecificParameters:
+	call	Device_FinalizeDPT
+
+;----------------------------------------------------------------------
+; Update drive counts (hard and floppy)
+;----------------------------------------------------------------------
+
+%ifdef MODULE_SERIAL_FLOPPY
+;
+; These two instructions serve two purposes:
+; 1. If the drive is a floppy drive (CF set), then we effectively increment the counter.
+; 2. If this is a hard disk, and there have been any floppy drives previously added, then the hard disk is
+;    effectively discarded.  This is more of a safety check then code that should ever normally be hit (see below).
+;    Since the floppy DPT's come after the hard disk DPT's, without expensive (code size) code to relocate a DPT,
+;    this was necessary.  Now, this situation shouldn't happen in normal operation, for a couple of reasons:
+; 		A. xtidecfg always puts configured serial ports at the end of the IDEVARS list
+;       B. the auto serial code is always executed last
+;       C. the serial server always returns floppy drives last
+;
+	adc		byte [RAMVARS.xlateVars+XLATEVARS.bFlopCreateCnt], 0
+	jnz		.AllDone
+%else
+;
+; Even without floppy support enabled, we shouldn't try to mount a floppy image as a hard disk, which
+; could lead to unpredictable results since no MBR will be present, etc.  The server doesn't know that
+; floppies are supported, so it is important to still fail here if a floppy is seen during the drive scan.
+;
+	jc		.AllDone
+%endif
+
+	inc		BYTE [RAMVARS.bDrvCnt]		; Increment drive count to RAMVARS
+
+.AllDone:
+	clc
+	ret
+
+
+;--------------------------------------------------------------------
+; StoreLbaAddressingAndTotalSectorCountFromBXDXAX
+;	Parameters:
+;		BX:DX:AX:	Total Sector Count
+;		DS:DI:		Ptr to Disk Parameter Table
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+StoreLbaAddressingAndTotalSectorCountFromBXDXAX:
+	mov		[di+DPT.twLbaSectors], ax
+	mov		[di+DPT.twLbaSectors+2], dx
+	mov		[di+DPT.twLbaSectors+4], bx
+
+	and		BYTE [di+DPT.bFlagsLow], ~MASKL_DPT_ADDRESSING_MODE
+	test	bx, bx
+	jnz		SHORT .SetLba48AddressingToDPT	; Must be LBA48
+
+	; Drives can report at most 0FFF FFFFh LBA28 sectors according to ATA specification.
+	; That is (2^28)-1 so we can simply check if DH is zero or not.
+	test	dh, dh
+	jz		SHORT .SetLba28AddressingToDPT
+.SetLba48AddressingToDPT:
+	or		BYTE [di+DPT.bFlagsLow], ADDRESSING_MODE_LBA48<<ADDRESSING_MODE_FIELD_POSITION
+.SetLba28AddressingToDPT:
+	or		BYTE [di+DPT.bFlagsLow], ADDRESSING_MODE_LBA28<<ADDRESSING_MODE_FIELD_POSITION
+	ret
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/FindDPT.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/FindDPT.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/FindDPT.asm	(revision 352)
@@ -0,0 +1,277 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for finding Disk Parameter Table.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Checks if drive is handled by this BIOS, and return DPT pointer.
+;
+; FindDPT_ForDriveNumberInDL
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;	Returns:
+;		CF:		Cleared if drive is handled by this BIOS
+;				Set if drive belongs to some other BIOS
+;		DI:		DPT Pointer if drive is handled by this BIOS
+;				Zero if drive belongs to some other BIOS
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_ForDriveNumberInDL:
+	xchg	di, ax								; Save the contents of AX in DI
+
+;
+; Check Our Hard Disks
+;
+	mov		ax, [RAMVARS.wDrvCntAndFirst]		; Drive count to AH, First number to AL
+	add		ah, al								; One past last drive to AH
+
+%ifdef MODULE_SERIAL_FLOPPY
+	cmp		dl, ah								; Above last supported?
+	jae		SHORT .HardDiskNotHandledByThisBIOS
+
+	cmp		dl, al								; Below first supported?
+	jae		SHORT .CalcDPTForDriveNumber
+
+ALIGN JUMP_ALIGN
+.HardDiskNotHandledByThisBIOS:
+;
+; Check Our Floppy Disks
+;
+	call	RamVars_UnpackFlopCntAndFirstToAL
+	js		SHORT .DiskIsNotHandledByThisBIOS
+
+	cbw											; Always 0h (no floppy drive covered above)
+	adc		ah, al								; Add in first drive number and number of drives
+
+	cmp		ah, dl								; Check second drive if two, first drive if only one
+	jz		SHORT .CalcDPTForDriveNumber
+	cmp		al, dl								; Check first drive in all cases, redundant but OK to repeat
+	jnz		SHORT .DiskIsNotHandledByThisBIOS
+%else
+	cmp		dl, ah								; Above last supported?
+	jae		SHORT .DiskIsNotHandledByThisBIOS
+
+	cmp		dl, al								; Below first supported?
+	jb		SHORT .DiskIsNotHandledByThisBIOS
+%endif
+	; fall-through to CalcDPTForDriveNumber
+
+;--------------------------------------------------------------------
+; Finds Disk Parameter Table for drive number.
+; Not intended to be called except by FindDPT_ForDriveNumberInDL
+;
+; CalcDPTForDriveNumber
+;	Parameters:
+;		DL:		Drive number
+;		DS:		RAMVARS segment
+;       DI:     Saved copy of AX from entry at FindDPT_ForDriveNumberInDL
+;	Returns:
+;		DS:DI:	Ptr to DPT
+;       CF:     Clear
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+.CalcDPTForDriveNumber:
+	push	dx
+
+%ifdef MODULE_SERIAL_FLOPPY
+	mov		ax, [RAMVARS.wDrvCntAndFirst]
+
+	test	dl, dl
+	js		.harddisk
+
+	call	RamVars_UnpackFlopCntAndFirstToAL
+	add		dl, ah						; add in end of hard disk DPT list, floppies start immediately after
+
+ALIGN JUMP_ALIGN
+.harddisk:
+	sub		dl, al						; subtract off beginning of either hard disk or floppy list (as appropriate)
+%else
+	sub		dl, [RAMVARS.bFirstDrv]		; subtract off beginning of hard disk list
+%endif
+
+.CalcDPTForNewDrive:
+	mov		al, LARGEST_DPT_SIZE
+
+	mul		dl
+	add		ax, BYTE RAMVARS_size		; Clears CF (will not overflow)
+
+	pop		dx
+
+	xchg	di, ax						; Restore AX from entry at FindDPT_ForDriveNumber, put DPT pointer in DI
+	ret
+
+ALIGN JUMP_ALIGN
+.DiskIsNotHandledByThisBIOS:
+;
+; Drive not found...
+;
+	xor		ax, ax								; Clear DPT pointer
+	stc											; Is not supported by our BIOS
+
+	xchg	di, ax								; Restore AX from save at top
+	ret
+
+
+;--------------------------------------------------------------------
+; FindDPT_ForIdevarsOffsetInDL
+;	Parameters:
+;		DL:		Offset to IDEVARS to search for
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:		Ptr to first DPT with same IDEVARS as in DL
+;		CF:			Clear if wanted DPT found
+;					Set if DPT not found, or no DPTs present
+;	Corrupts registers:
+;		SI
+;--------------------------------------------------------------------
+FindDPT_ForIdevarsOffsetInDL:
+	mov		si, IterateFindFirstDPTforIdevars			; iteration routine (see below)
+	jmp		SHORT FindDPT_IterateAllDPTs				; look for the first drive on this controller, if any
+
+;--------------------------------------------------------------------
+; Iteration routine for FindDPT_ForIdevarsOffsetInDL,
+; for use with IterateAllDPTs
+;
+; Returns when DPT is found on the controller with Idevars offset in DL
+;
+; IterateFindFirstDPTforIdevars
+;       DL:		Offset to IDEVARS to search from DPTs
+;		DS:DI:	Ptr to DPT to examine
+;	Returns:
+;		CF:		Clear if wanted DPT found
+;				Set if wrong DPT
+;--------------------------------------------------------------------
+IterateFindFirstDPTforIdevars:
+	cmp		dl, [di+DPT.bIdevarsOffset]			; Clears CF if matched
+	je		.done
+	stc											; Set CF for not found
+.done:
+	ret
+
+
+;--------------------------------------------------------------------
+; Finds pointer to first unused Disk Parameter Table.
+; Should only be used before DetectDrives is complete (not valid after this time).
+;
+; FindDPT_ForNewDriveToDSDI
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to first unused DPT
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_ForNewDriveToDSDI:
+	push	dx
+
+%ifdef MODULE_SERIAL_FLOPPY
+	mov		dx, [RAMVARS.wDrvCntAndFlopCnt]
+	add		dl, dh
+%else
+	mov		dl, [RAMVARS.bDrvCnt]
+%endif
+
+	jmp		short FindDPT_ForDriveNumberInDL.CalcDPTForNewDrive
+
+;--------------------------------------------------------------------
+; IterateToDptWithFlagsHighInBL
+;	Parameters:
+;		DS:DI:	Ptr to DPT to examine
+;       BL:		Bit(s) to test in DPT.bFlagsHigh
+;	Returns:
+;		CF:		Clear if wanted DPT found
+;				Set if wrong DPT
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+IterateToDptWithFlagsHighInBL:
+	test	[di+DPT.bFlagsHigh], bl				; Clears CF
+	jnz		SHORT .ReturnRightDPT
+	stc
+.ReturnRightDPT:
+	ret
+
+;--------------------------------------------------------------------
+; FindDPT_ToDSDIforSerialDevice
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		DS:DI:	Ptr to DPT
+;		CF:		Set if wanted DPT found
+;				Cleared if DPT not found
+;	Corrupts registers:
+;		SI
+;--------------------------------------------------------------------
+%ifdef MODULE_SERIAL
+ALIGN JUMP_ALIGN
+FindDPT_ToDSDIforSerialDevice:
+	mov		bl, FLGH_DPT_SERIAL_DEVICE
+; fall-through
+%endif
+
+;--------------------------------------------------------------------
+; FindDPT_ToDSDIforFlagsHigh
+;	Parameters:
+;		DS:		RAMVARS segment
+;       BL:		Bit(s) to test in DPT.bFlagsHigh
+;	Returns:
+;		DS:DI:	Ptr to DPT
+;		CF:		Set if wanted DPT found
+;				Cleared if DPT not found
+;	Corrupts registers:
+;		SI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_ToDSDIforFlagsHighInBL:
+	mov		si, IterateToDptWithFlagsHighInBL
+	; Fall to IterateAllDPTs
+
+;--------------------------------------------------------------------
+; Iterates all Disk Parameter Tables.
+;
+; FindDPT_IterateAllDPTs
+;	Parameters:
+;		AX,BX,DX:	Parameters to callback function
+;		CS:SI:		Ptr to callback function
+;                   Callback routine should return CF=clear if found
+;		DS:			RAMVARS segment
+;	Returns:
+;		DS:DI:		Ptr to wanted DPT (if found)
+;					If not found, points to first empty DPT
+;		CF:			Clear if wanted DPT found
+;					Set if DPT not found, or no DPTs present
+;	Corrupts registers:
+;		Nothing unless corrupted by callback function
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+FindDPT_IterateAllDPTs:
+	push	cx
+
+	mov		di, RAMVARS_size			; Point DS:DI to first DPT
+	eMOVZX	cx, [RAMVARS.bDrvCnt]
+	jcxz	.NotFound					; Return if no drives
+
+ALIGN JUMP_ALIGN
+.LoopWhileDPTsLeft:
+	call	si							; Is wanted DPT?
+	jnc		SHORT .Found				;  If so, return
+	add		di, BYTE LARGEST_DPT_SIZE	; Point to next DPT
+	loop	.LoopWhileDPTsLeft
+
+ALIGN JUMP_ALIGN
+.NotFound:
+	stc
+
+ALIGN JUMP_ALIGN
+.Found:
+	pop		cx
+	ret
+
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/RamVars.asm
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/RamVars.asm	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/Src/VariablesAndDPTs/RamVars.asm	(revision 352)
@@ -0,0 +1,183 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for accessings RAMVARS.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; Initializes RAMVARS.
+; Drive detection can be started after this function returns.
+;
+; RamVars_Initialize
+;	Parameters:
+;		Nothing
+;	Returns:
+;		DS:		RAMVARS segment
+;	Corrupts registers:
+;		AX, CX, DI
+;--------------------------------------------------------------------
+RamVars_Initialize:
+	push	es
+	; Fall to .StealMemoryForRAMVARS
+
+;--------------------------------------------------------------------
+; .StealMemoryForRAMVARS
+;	Parameters:
+;		Nothing
+;	Returns:
+;		DS:		RAMVARS segment
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+.StealMemoryForRAMVARS:
+	mov		ax, LITE_MODE_RAMVARS_SEGMENT
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_FULLMODE
+	jz		SHORT .InitializeRamvars	; No need to steal RAM
+
+	LOAD_BDA_SEGMENT_TO	ds, ax, !		; Zero AX
+	mov		al, [cs:ROMVARS.bStealSize]
+	sub		[BDA.wBaseMem], ax
+	mov		ax, [BDA.wBaseMem]
+	eSHL_IM	ax, 6						; Segment to first stolen kB (*=40h)
+	; Fall to .InitializeRamvars
+
+;--------------------------------------------------------------------
+; .InitializeRamvars
+;	Parameters:
+;		AX:		RAMVARS segment
+;	Returns:
+;		DS:		RAMVARS segment
+;	Corrupts registers:
+;		AX, CX, DI, ES
+;--------------------------------------------------------------------
+.InitializeRamvars:
+	mov		ds, ax
+	mov		es, ax
+	mov		cx, RAMVARS_size
+	xor		di, di
+	call	Memory_ZeroESDIwithSizeInCX
+	mov		WORD [RAMVARS.wSignature], RAMVARS_SIGNATURE
+	; Fall to .InitializeDriveTranslationAndReturn
+
+;--------------------------------------------------------------------
+; .InitializeDriveTranslationAndReturn
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+.InitializeDriveTranslationAndReturn:
+	pop		es
+	jmp		DriveXlate_Reset
+
+
+;--------------------------------------------------------------------
+; Returns segment to RAMVARS.
+; RAMVARS might be located at the top of interrupt vectors (0030:0000h)
+; or at the top of system base RAM.
+;
+; RamVars_GetSegmentToDS
+;	Parameters:
+;		Nothing
+;	Returns:
+;		DS:		RAMVARS segment
+;	Corrupts registers:
+;		DI
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+RamVars_GetSegmentToDS:
+	test	BYTE [cs:ROMVARS.wFlags], FLG_ROMVARS_FULLMODE
+	jnz		SHORT .GetStolenSegmentToDS
+%ifndef USE_186
+	mov		di, LITE_MODE_RAMVARS_SEGMENT
+	mov		ds, di
+%else
+	push	LITE_MODE_RAMVARS_SEGMENT
+	pop		ds
+%endif
+	ret
+
+ALIGN JUMP_ALIGN
+.GetStolenSegmentToDS:
+	LOAD_BDA_SEGMENT_TO	ds, di
+	mov		di, [BDA.wBaseMem]		; Load available base memory size in kB
+	eSHL_IM	di, 6					; Segment to first stolen kB (*=40h)
+ALIGN JUMP_ALIGN
+.LoopStolenKBs:
+	mov		ds, di					; EBDA segment to DS
+	add		di, BYTE 64				; DI to next stolen kB
+	cmp		WORD [RAMVARS.wSignature], RAMVARS_SIGNATURE
+	jne		SHORT .LoopStolenKBs	; Loop until sign found (always found eventually)
+	ret
+
+
+;--------------------------------------------------------------------
+; RamVars_GetHardDiskCountFromBDAtoAX
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AX:		Total hard disk count
+;	Corrupts registers:
+;		CX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+RamVars_GetHardDiskCountFromBDAtoAX:
+	call	RamVars_GetCountOfKnownDrivesToAX
+	push	ds
+	LOAD_BDA_SEGMENT_TO	ds, cx
+	mov		cl, [BDA.bHDCount]
+	MAX_U	al, cl
+	pop		ds
+	ret
+
+;--------------------------------------------------------------------
+; RamVars_GetCountOfKnownDrivesToAX
+;	Parameters:
+;		DS:		RAMVARS segment
+;	Returns:
+;		AX:		Total hard disk count
+;	Corrupts registers:
+;		None
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+RamVars_GetCountOfKnownDrivesToAX:
+	mov		ax, [RAMVARS.wDrvCntAndFirst]
+	add		al, ah
+	and		al, 7fh
+	cbw
+	ret
+
+;--------------------------------------------------------------------
+; RamVars_GetIdeControllerCountToCX
+;	Parameters:
+;		Nothing
+;	Returns:
+;		CX:		Number of IDE controllers to handle
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+RamVars_GetIdeControllerCountToCX:
+	eMOVZX	cx, [cs:ROMVARS.bIdeCnt]
+	ret
+
+%ifdef MODULE_SERIAL_FLOPPY
+;--------------------------------------------------------------------
+; RamVars_UnpackFlopCntAndFirstToAL
+;	Parameters:
+;		Nothing
+;	Returns:
+;		AL:		First floppy drive number supported
+;       CF:		Number of floppy drives supported (clear = 1, set = 2)
+;		SF:		Emulating drives (clear = yes, set = no)
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+RamVars_UnpackFlopCntAndFirstToAL:
+	mov		al, [RAMVARS.xlateVars+XLATEVARS.bFlopCntAndFirst]
+	sar		al, 1
+	ret
+%endif
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/gpl-2.0.txt
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/gpl-2.0.txt	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/gpl-2.0.txt	(revision 352)
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
Index: /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/makefile
===================================================================
--- /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/makefile	(revision 352)
+++ /tags/XTIDE_Universal_BIOS_v2.0.0_beta1/makefile	(revision 352)
@@ -0,0 +1,192 @@
+###############################################################################
+# Makefile to build XTIDE Universal BIOS.                                     #
+#                                                                             #
+# Valid makefile targets are:                                                 #
+# all		Removes existing files and builds binary files in \Build          #
+# small		Builds 8 kiB binaries only (without checksum)                     #
+# large		Builds 15 kiB binaries only (without checksum)                    #
+# clean		Removes all files from \Build                                     #
+# checksum*	Builds all and then generates checksum byte to all binary files   #
+# strings*	Compress src\strings.asm to src\StringsCompressed.asm             #
+#                                                                             #
+# * at the end of target name means that Perl is required for the job.        #
+# Build directory must be created manually if it does not exist.              #
+#                                                                             #
+###############################################################################
+
+###########################################
+# Source files and destination executable #
+###########################################
+
+# Assembly source code file (*.asm):
+SRC_ASM = Src/Main.asm
+
+# Program executable file name without extension:
+PROG = ide
+
+
+#######################################
+# Destination and include directories #
+#######################################
+
+# Directory where binary file will be compiled to
+BUILD_DIR = Build
+
+# Subdirectories where included files are:
+HEADERS = Inc/
+HEADERS += Src/
+HEADERS += Src/Boot/
+HEADERS += Src/Handlers/
+HEADERS += Src/Handlers/Int13h/
+HEADERS += Src/Handlers/Int13h/EBIOS/
+HEADERS += Src/Handlers/Int13h/Tools/
+HEADERS += Src/Device/
+HEADERS += Src/Device/IDE/
+HEADERS += Src/Device/MemoryMappedIDE/
+HEADERS += Src/Device/Serial/
+HEADERS += Src/Initialization/
+HEADERS += Src/Libraries/
+HEADERS += Src/VariablesAndDPTs/
+
+# Subdirectories where library files are:
+LIBS = ../Assembly_Library/Inc/
+LIBS += ../Assembly_Library/Src/
+LIBS += ../Assembly_Library/Src/Display/
+LIBS += ../Assembly_Library/Src/File/
+LIBS += ../Assembly_Library/Src/Keyboard/
+LIBS += ../Assembly_Library/Src/Menu/
+LIBS += ../Assembly_Library/Src/Menu/Dialog/
+LIBS += ../Assembly_Library/Src/String/
+LIBS += ../Assembly_Library/Src/Time/
+LIBS += ../Assembly_Library/Src/Util/
+LIBS += ../Assembly_Library/Src/Serial/
+LIBS += ../XTIDE_Universal_BIOS/Inc/
+HEADERS += $(LIBS)
+
+
+#################################################################
+# Assembler preprocessor defines.                               #
+#################################################################
+DEFINES = INCLUDE_MENU_LIBRARY EXCLUDE_FROM_XTIDE_UNIVERSAL_BIOS MODULE_EBIOS MODULE_STRINGS_COMPRESSED
+DEFINES_XT = ELIMINATE_CGA_SNOW MODULE_SERIAL MODULE_SERIAL_FLOPPY
+DEFINES_XTPLUS = ELIMINATE_CGA_SNOW USE_186 MODULE_SERIAL MODULE_SERIAL_FLOPPY
+DEFINES_AT = USE_286 USE_AT MODULE_SERIAL MODULE_SERIAL_FLOPPY
+DEFINES_XT_LARGE = $(DEFINES_XT) MODULE_JRIDE
+DEFINES_XTPLUS_LARGE = $(DEFINES_XTPLUS) MODULE_JRIDE
+DEFINES_AT_LARGE = $(DEFINES_AT) MODULE_JRIDE
+DEFINES_JRIDE_8K = ELIMINATE_CGA_SNOW MODULE_JRIDE
+
+
+###################
+# Other variables #
+###################
+
+# Target size of the ROM, used in main.asm for number of 512B blocks and by checksum Perl script below
+ROMSIZE = 8192
+ROMSIZE_LARGE = 15360
+
+# Add -D in front of every preprocessor define declaration
+DEFS = $(DEFINES:%=-D%)
+DEFS_XT = $(DEFINES_XT:%=-D%) -DROMSIZE=$(ROMSIZE)
+DEFS_XTPLUS = $(DEFINES_XTPLUS:%=-D%) -DROMSIZE=$(ROMSIZE)
+DEFS_AT = $(DEFINES_AT:%=-D%) -DROMSIZE=$(ROMSIZE)
+DEFS_XT_LARGE = $(DEFINES_XT_LARGE:%=-D%) -DROMSIZE=$(ROMSIZE_LARGE)
+DEFS_XTPLUS_LARGE = $(DEFINES_XTPLUS_LARGE:%=-D%) -DROMSIZE=$(ROMSIZE_LARGE)
+DEFS_AT_LARGE = $(DEFINES_AT_LARGE:%=-D%) -DROMSIZE=$(ROMSIZE_LARGE)
+DEFS_JRIDE_8K = $(DEFINES_JRIDE_8K:%=-D%) -DROMSIZE=$(ROMSIZE)
+
+# Add -I in front of all header directories
+IHEADERS = $(HEADERS:%=-I%)
+
+# Path + target file to be built
+TARGET = $(BUILD_DIR)/$(PROG)
+
+#########################
+# Compilers and linkers #
+#########################
+
+# Make
+MAKE = mingw32-make.exe
+
+# Assembler
+AS = nasm.exe
+
+# use this command to erase files.
+RM = -del /Q
+
+
+#############################
+# Compiler and linker flags #
+#############################
+
+# Assembly compiler flags
+ASFLAGS = -f bin				# Produce binary object files
+ASFLAGS += $(DEFS)				# Preprocessor defines
+ASFLAGS += $(IHEADERS)			# Set header file directory paths
+ASFLAGS += -Worphan-labels		# Warn about labels without colon
+ASFLAGS += -O9					# Optimize operands to their shortest forms
+
+
+############################################
+# Build process. Actual work is done here. #
+############################################
+
+all: clean small large
+	@echo All done!
+
+small: at xtplus xt jride_8k
+	@echo All 8 kiB binaries built!
+
+large: at_large xtplus_large xt_large
+	@echo All 15 kiB binaries built!
+
+at:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_AT) -l"$(TARGET)_at.lst" -o"$(TARGET)_at.bin"
+	@echo * 8k AT version "$(TARGET)_at.bin" built.
+
+at_large:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_AT_LARGE) -l"$(TARGET)_atl.lst" -o"$(TARGET)_atl.bin"
+	@echo *15k AT version "$(TARGET)_atl.bin" built.
+
+xtplus:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_XTPLUS) -l"$(TARGET)_xtp.lst" -o"$(TARGET)_xtp.bin"
+	@echo * 8k XT Plus version "$(TARGET)_xtp.bin" built.
+
+xtplus_large:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_XTPLUS_LARGE) -l"$(TARGET)_xtpl.lst" -o"$(TARGET)_xtpl.bin"
+	@echo *15k XT Plus version "$(TARGET)_xtpl.bin" built.
+
+xt:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_XT) -l"$(TARGET)_xt.lst" -o"$(TARGET)_xt.bin"
+	@echo * 8k XT version "$(TARGET)_xt.bin" built.
+
+xt_large:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_XT_LARGE) -l"$(TARGET)_xtl.lst" -o"$(TARGET)_xtl.bin"
+	@echo *15k XT version "$(TARGET)_xtl.bin" built.
+
+jride_8k:
+	@$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_JRIDE_8K) -l"$(TARGET)_jr8k.lst" -o"$(TARGET)_jr8k.bin"
+	@echo * 8k JR-IDE/ISA version "$(TARGET)_jr8k.bin" built.
+
+strings: src\Strings.asm
+	@$(AS) src\Strings.asm $(ASFLAGS) $(DEFS_XT) -DCHECK_FOR_UNUSED_ENTRYPOINTS -DMODULE_STRINGS_COMPRESSED_PRECOMPRESS -o build\Strings.bin -l build\StringsPrecompress.lst
+	@perl ..\tools\StringsCompress.pl < build\StringsPrecompress.lst > src\StringsCompressed.asm
+	@echo StringsCompressed.asm updated!
+
+clean:
+	@$(RM) $(BUILD_DIR)\*.*
+	@echo Deleted "(*.*)" from "$(BUILD_DIR)/"
+
+checksum: all
+	@perl ..\tools\checksum.pl $(TARGET)_atl.bin $(ROMSIZE_LARGE)
+	@perl ..\tools\checksum.pl $(TARGET)_xtpl.bin $(ROMSIZE_LARGE)
+	@perl ..\tools\checksum.pl $(TARGET)_xtl.bin $(ROMSIZE_LARGE)
+	@perl ..\tools\checksum.pl $(TARGET)_at.bin $(ROMSIZE)
+	@perl ..\tools\checksum.pl $(TARGET)_xtp.bin $(ROMSIZE)
+	@perl ..\tools\checksum.pl $(TARGET)_xt.bin $(ROMSIZE)
+	@perl ..\tools\checksum.pl $(TARGET)_jr8k.bin $(ROMSIZE)
+
+xt_unused: xt
+	$(AS) "$(SRC_ASM)" $(ASFLAGS) $(DEFS_XT) -o"$(TARGET)_xt_unused.asm" -E -DCHECK_FOR_UNUSED_ENTRYPOINTS
+	perl ..\tools\unused.pl $(TARGET)_xt.lst $(TARGET)_xt_unused.asm
+
