Index: trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h.asm	(revision 152)
+++ trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h.asm	(revision 155)
@@ -23,5 +23,5 @@
 	sti									; Enable interrupts
 	cld									; String instructions to increment pointers
-	SAVE_AND_GET_INTPACK_WITH_EXTRA_WORDS_TO_SSBP EXTRA_WORDS_TO_RESERVE_FOR_INTPACK
+	CREATE_FRAME_INTPACK_TO_SSBP	EXTRA_BYTES_FOR_INTPACK
 
 	call	RamVars_GetSegmentToDS
@@ -33,5 +33,4 @@
 
 	; Jump to correct BIOS function
-JumpToBiosFunctionInAH:
 	cmp		ah, 25h						; Valid BIOS function?
 	ja		SHORT Int13h_UnsupportedFunction
@@ -109,5 +108,5 @@
 	or		WORD [bp+IDEPACK.intpack+INTPACK.flags], FLG_FLAGS_IF	; Return with interrupts enabled
 	mov		sp, bp									; Now we can exit anytime
-	RESTORE_INTPACK_WITH_EXTRA_WORDS_FROM_SSBP EXTRA_WORDS_TO_RESERVE_FOR_INTPACK
+	RESTORE_FRAME_INTPACK_FROM_SSBP		EXTRA_BYTES_FOR_INTPACK
 
 
Index: trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH15h_HSize.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH15h_HSize.asm	(revision 152)
+++ trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH15h_HSize.asm	(revision 155)
@@ -59,5 +59,5 @@
 
 ConvertAH08hReturnValuesToSectorCount:
-	call	HAddress_ExtractLCHSparametersFromOldInt13hAddress
+	call	Address_ExtractLCHSparametersFromOldInt13hAddress
 	xor		ax, ax			; Zero AX
 	inc		cx				; Max cylinder number to cylinder count
Index: trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH2h_HRead.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH2h_HRead.asm	(revision 152)
+++ trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH2h_HRead.asm	(revision 155)
@@ -15,5 +15,5 @@
 ;		SS:BP:	Ptr to IDEPACK
 ;	Parameters on INTPACK:
-;		AL:		Number of sectors to read (1...255, 0=256)
+;		AL:		Number of sectors to read (1...255)
 ;		CH:		Cylinder number, bits 7...0
 ;		CL:		Bits 7...6: Cylinder number bits 9 and 8
@@ -28,4 +28,5 @@
 ALIGN JUMP_ALIGN
 AH2h_HandlerForReadDiskSectors:
+	call	AH2h_ExitInt13hIfSectorCountInIntpackIsZero
 	mov		ah, COMMAND_READ_SECTORS	; Load sector mode command
 	test	WORD [di+DPT.wFlags], FLG_DPT_BLOCK_MODE_SUPPORTED
@@ -40,2 +41,23 @@
 	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
 %endif
+
+
+;--------------------------------------------------------------------
+; AH2h_ExitInt13hIfSectorCountInIntpackIsZero
+;	Parameters:
+;		SS:BP:	Ptr to IDEPACK
+;	Parameters on INTPACK:
+;		AL:		Number of sectors to transfer (1...255)
+;	Returns:
+;		Nothing (does not return if error)
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+AH2h_ExitInt13hIfSectorCountInIntpackIsZero:
+	cmp		BYTE [bp+IDEPACK.intpack+INTPACK.al], 0
+	je		SHORT .InvalidSectorCount
+	ret
+.InvalidSectorCount:
+	mov		ah, RET_HD_INVALID
+	jmp		Int13h_ReturnFromHandlerAfterStoringErrorCodeFromAH
Index: trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH3h_HWrite.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH3h_HWrite.asm	(revision 152)
+++ trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH3h_HWrite.asm	(revision 155)
@@ -27,5 +27,5 @@
 ALIGN JUMP_ALIGN
 AH3h_HandlerForWriteDiskSectors:
-	; Prepare parameters
+	call	AH2h_ExitInt13hIfSectorCountInIntpackIsZero
 	mov		ah, COMMAND_WRITE_SECTORS	; Load sector mode command
 	test	WORD [di+DPT.wFlags], FLG_DPT_BLOCK_MODE_SUPPORTED
Index: trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH4h_HVerify.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH4h_HVerify.asm	(revision 152)
+++ trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH4h_HVerify.asm	(revision 155)
@@ -26,5 +26,6 @@
 ALIGN JUMP_ALIGN
 AH4h_HandlerForVerifyDiskSectors:
-	mov		ah, COMMAND_WRITE_SECTORS
+	call	AH2h_ExitInt13hIfSectorCountInIntpackIsZero
+	mov		ah, COMMAND_VERIFY_SECTORS
 	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRDY)
 %ifdef USE_186
Index: trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/Address.asm
===================================================================
--- trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/Address.asm	(revision 155)
+++ trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/Address.asm	(revision 155)
@@ -0,0 +1,154 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Functions for address translations.
+
+; Section containing code
+SECTION .text
+
+; Jump table for conversion functions
+ALIGN WORD_ALIGN
+g_rgfnAddressTranslation:
+	dw		DoNotConvertLCHS					; 0, ADDR_DPT_LCHS
+	dw		ConvertLCHStoPCHS					; 1, ADDR_DPT_PCHS
+	dw		ConvertLCHStoLBARegisterValues		; 2, ADDR_DPT_LBA28
+	dw		ConvertLCHStoLBARegisterValues		; 3, ADDR_DPT_LBA48
+
+
+;--------------------------------------------------------------------
+; 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	AccessDPT_GetAddressingModeForWordLookToBX
+	push	WORD [cs:bx+g_rgfnAddressTranslation]		; Push return address
+	; Fall to Address_ExtractLCHSparametersFromOldInt13hAddress
+
+;---------------------------------------------------------------------
+; 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
+;--------------------------------------------------------------------
+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.wFlags]		; Load shift count
+	and		cl, MASK_DPT_CHS_SHIFT_COUNT
+	shl		dx, cl					; DX = LCylinder << n
+	add		ax, dx					; AX = P-CHS Cylinder number
+	mov		cx, ax					; Copy P-CHS Cylinder number to CX
+DoNotConvertLCHS:
+	ret
+
+
+;---------------------------------------------------------------------
+; 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, cx					; Copy Cylinder number to AX
+	eMOVZX	dx, BYTE [di+DPT.bLchsHeads]
+	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)
+	eMOVZX	cx, BYTE [di+DPT.bPchsSectors]	; Load Sectors per Track
+	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
