source: xtideuniversalbios/trunk/XTIDE_Universal_BIOS/Src/Device/IDE/IdeTransfer.asm@ 534

Last change on this file since 534 was 526, checked in by krille_n_@…, 12 years ago

Changes:

  • Update of the copyright notices to include the year 2013.
File size: 10.6 KB
RevLine 
[150]1; Project name : XTIDE Universal BIOS
2; Description : IDE Device transfer functions.
3
[376]4;
[445]5; XTIDE Universal BIOS and Associated Tools
[526]6; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
[376]7;
8; This program is free software; you can redistribute it and/or modify
9; it under the terms of the GNU General Public License as published by
10; the Free Software Foundation; either version 2 of the License, or
11; (at your option) any later version.
[445]12;
[376]13; This program is distributed in the hope that it will be useful,
14; but WITHOUT ANY WARRANTY; without even the implied warranty of
15; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
[445]16; GNU General Public License for more details.
[376]17; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
[445]18;
[376]19
[150]20; Structure containing variables for PIO transfer functions.
21; This struct must not be larger than IDEPACK without INTPACK.
[414]22struc PIOVARS ; Must not be larger than 9 bytes! See IDEPACK in RamVars.inc.
23 .wDataPort resb 2 ; 0-1, IDE Data Port
24 .fnXfer resb 2 ; 2-3, Offset to transfer function
25 .wSectorsInBlock resb 2 ; 4-5, Block size in sectors
[363]26 .bSectorsLeft resb 1 ; 6, Sectors left to transfer
[218]27 resb 1 ; 7, IDEPACK.bDeviceControl
[363]28 .bSectorsDone resb 1 ; 8, Number of sectors xferred
[150]29endstruc
30
31
32; Section containing code
33SECTION .text
34
35;--------------------------------------------------------------------
36; IdeTransfer_StartWithCommandInAL
37; Parameters:
38; AL: IDE command that was used to start the transfer
[171]39; (all PIO read and write commands including Identify Device)
[480]40; ES:SI: Ptr to data buffer
[150]41; DS:DI: Ptr to DPT (in RAMVARS segment)
42; SS:BP: Ptr to IDEPACK
43; Returns:
44; AH: INT 13h Error Code
[218]45; CX: Number of successfully transferred sectors
[150]46; CF: Cleared if success, Set if error
47; Corrupts registers:
[218]48; AL, BX, DX, SI, ES
[150]49;--------------------------------------------------------------------
50ALIGN JUMP_ALIGN
51IdeTransfer_StartWithCommandInAL:
[157]52 ; Are we reading or writing?
[171]53 test al, 16 ; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
[242]54 mov ah, [bp+IDEPACK.bSectorCount]
55 jnz SHORT WriteToDrive
[171]56 cmp al, COMMAND_WRITE_MULTIPLE
[242]57 je SHORT WriteToDrive
58 ; Fall to ReadFromDrive
[150]59
60;--------------------------------------------------------------------
[242]61; ReadFromDrive
[150]62; Parameters:
[242]63; AH: Number of sectors to transfer (1...128)
[480]64; ES:SI: Ptr to buffer to receive data
[150]65; DS:DI: Ptr to DPT (in RAMVARS segment)
66; SS:BP: Ptr to PIOVARS
67; Returns:
[242]68; DS:DI: Ptr to DPT (in RAMVARS segment)
[150]69; AH: BIOS Error code
[218]70; CX: Number of successfully transferred sectors
[294]71; CF: 0 if transfer successful
[150]72; 1 if any error
73; Corrupts registers:
[218]74; AL, BX, DX, SI, ES
[150]75;--------------------------------------------------------------------
[242]76ReadFromDrive:
77 ; Prepare to read data to ESSI
78 mov bx, g_rgfnPioRead
79 call InitializePiovarsInSSBPwithSectorCountInAH
80
81 ; Wait until drive is ready to transfer
82 call IdeWait_IRQorDRQ ; Wait until ready to transfer
[218]83 jc SHORT ReturnWithTransferErrorInAH
[242]84 xchg si, di ; ES:DI now points buffer
[218]85
[363]86 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
[242]87
[150]88ALIGN JUMP_ALIGN
[242]89.ReadNextBlockFromDrive:
[150]90 mov dx, [bp+PIOVARS.wDataPort]
[363]91 cmp [bp+PIOVARS.bSectorsLeft], cl
[242]92 jbe SHORT .ReadLastBlockFromDrive
[218]93 call [bp+PIOVARS.fnXfer]
[169]94
[218]95 ; Wait until ready for next block and check for errors
[242]96 xchg di, si ; DS:DI now points DPT
[218]97 call IdeWait_IRQorDRQ ; Wait until ready to transfer
98 jc SHORT ReturnWithTransferErrorInAH
[242]99 xchg si, di ; ES:DI now points buffer
[169]100
[363]101 ; Increment number of successfully read sectors
102 mov cx, [bp+PIOVARS.wSectorsInBlock]
103 sub [bp+PIOVARS.bSectorsLeft], cl
104 add [bp+PIOVARS.bSectorsDone], cl
[242]105 jmp SHORT .ReadNextBlockFromDrive
[150]106
107ALIGN JUMP_ALIGN
[242]108.ReadLastBlockFromDrive:
[363]109 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
[419]110 push cx
[150]111 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
112
[242]113 ; Check for errors in last block
114 mov di, si ; DS:DI now points DPT
115CheckErrorsAfterTransferringLastBlock:
[417]116 mov bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_BSY)
[242]117 call IdeWait_PollStatusFlagInBLwithTimeoutInBH
[419]118 pop cx ; [bp+PIOVARS.bSectorsLeft]
119 jc SHORT ReturnWithTransferErrorInAH
[150]120
[445]121 ; All sectors successfully transferred
[419]122 add cx, [bp+PIOVARS.bSectorsDone] ; Never sets CF
123 ret
124
[242]125 ; Return number of successfully read sectors
126ReturnWithTransferErrorInAH:
[370]127%ifdef USE_386
128 movzx cx, [bp+PIOVARS.bSectorsDone]
129%else
[363]130 mov cl, [bp+PIOVARS.bSectorsDone]
131 mov ch, 0 ; Preserve CF
[370]132%endif
[242]133 ret
134
135
[150]136;--------------------------------------------------------------------
[242]137; WriteToDrive
[150]138; Parameters:
[242]139; AH: Number of sectors to transfer (1...128)
140; DS:DI: Ptr to DPT (in RAMVARS segment)
[480]141; ES:SI: Ptr to buffer containing data
[150]142; SS:BP: Ptr to PIOVARS
143; Returns:
144; AH: BIOS Error code
[218]145; CX: Number of successfully transferred sectors
[294]146; CF: 0 if transfer successful
[150]147; 1 if any error
148; Corrupts registers:
[218]149; AL, BX, DX, SI, ES
[150]150;--------------------------------------------------------------------
151ALIGN JUMP_ALIGN
[242]152WriteToDrive:
153 ; Prepare to write data from ESSI
154 mov bx, g_rgfnPioWrite
155 call InitializePiovarsInSSBPwithSectorCountInAH
156
157 ; Always poll when writing first block (IRQs are generated for following blocks)
158 mov bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
159 call IdeWait_PollStatusFlagInBLwithTimeoutInBH
[218]160 jc SHORT ReturnWithTransferErrorInAH
[150]161
[363]162 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
[242]163
[218]164ALIGN JUMP_ALIGN
[242]165.WriteNextBlockToDrive:
[150]166 mov dx, [bp+PIOVARS.wDataPort]
[363]167 cmp [bp+PIOVARS.bSectorsLeft], cl
[242]168 jbe SHORT .WriteLastBlockToDrive
[218]169 call [bp+PIOVARS.fnXfer]
[169]170
[218]171 ; Wait until ready for next block and check for errors
172 call IdeWait_IRQorDRQ ; Wait until ready to transfer
173 jc SHORT ReturnWithTransferErrorInAH
[150]174
[363]175 ; Increment number of successfully written sectors
176 mov cx, [bp+PIOVARS.wSectorsInBlock]
177 sub [bp+PIOVARS.bSectorsLeft], cl
178 add [bp+PIOVARS.bSectorsDone], cl
[242]179 jmp SHORT .WriteNextBlockToDrive
[169]180
[150]181ALIGN JUMP_ALIGN
[242]182.WriteLastBlockToDrive:
[363]183 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
[419]184 push cx
[242]185%ifdef USE_186
186 push CheckErrorsAfterTransferringLastBlock
187 jmp [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
188%else
[150]189 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
[242]190 jmp SHORT CheckErrorsAfterTransferringLastBlock
191%endif
[218]192
[150]193
194;--------------------------------------------------------------------
[218]195; InitializePiovarsInSSBPwithSectorCountInAH
[150]196; Parameters:
[218]197; AH: Number of sectors to transfer (1...128)
[150]198; BX: Offset to transfer function lookup table
199; DS:DI: Ptr to DPT (in RAMVARS segment)
[480]200; ES:SI: Ptr to data buffer
[169]201; SS:BP: Ptr to PIOVARS
[167]202; Returns:
[169]203; Nothing
[150]204; Corrupts registers:
[242]205; AX, BX, DX
[150]206;--------------------------------------------------------------------
207ALIGN JUMP_ALIGN
[218]208InitializePiovarsInSSBPwithSectorCountInAH:
[473]209 ; Store sizes and Data Port
[363]210 mov [bp+PIOVARS.bSectorsLeft], ah
[473]211 mov ax, [di+DPT.wBasePort]
212 mov [bp+PIOVARS.wDataPort], ax
[370]213 eMOVZX ax, [di+DPT_ATA.bBlockSize]
[363]214 mov [bp+PIOVARS.wSectorsInBlock], ax
215 mov [bp+PIOVARS.bSectorsDone], ah ; Zero
[150]216
217 ; Get transfer function based on bus type
[158]218 xchg ax, bx ; Lookup table offset to AX
[400]219 mov bl, [di+DPT_ATA.bDevice]
[493]220%ifdef MODULE_8BIT_IDE_ADVANCED
[480]221 mov dl, bl
222%endif
[150]223 add bx, ax
224 mov ax, [cs:bx] ; Load offset to transfer function
225 mov [bp+PIOVARS.fnXfer], ax
[480]226
227 ; Normalize pointer for PIO-transfers and convert to physical address for DMA transfers
[493]228%ifdef MODULE_8BIT_IDE_ADVANCED
[480]229 cmp dl, DEVICE_8BIT_XTCF_DMA
230 jb SHORT IdeTransfer_NormalizePointerInESSI
231
232 ; Convert ES:SI to physical address
[491]233%ifdef USE_186 ; Bytes EU Cycles(286)
234 mov ax, es ; 2 2
235 rol ax, 4 ; 3 9
236 mov dx, ax ; 2 2
237 and ax, BYTE 0Fh; 3 3
238 xor dx, ax ; 2 2
239 add si, dx ; 2 2
240 adc al, ah ; 2 2
241 mov es, ax ; 2 2
242 ;------------------------------------
243 ; 18 24
244%else ; 808x
245
246%if 0
247 ; Bytes EU Cycles(808x)
248 mov al, 4 ; 2 4
249 mov dx, es ; 2 2
250 xchg cx, ax ; 1 3
251 rol dx, cl ; 2 24
252 mov cx, dx ; 2 2
253 xchg cx, ax ; 1 3
254 and ax, BYTE 0Fh; 3 4
255 xor dx, ax ; 2 3
256 add si, dx ; 2 3
257 adc al, ah ; 2 3
258 mov es, ax ; 2 2
259 ;------------------------------------
260 ; 21 53
261;
262; Judging by the Execution Unit cycle count the above block of code is
263; apparently slower. However, the shifts and rotates in the block below
264; execute faster than the Bus Interface Unit on an 8088 can fetch them,
265; thus causing the EU to starve. The difference in true execution speed
266; (if any) might not be worth the extra 5 bytes.
267; In other words, we could use a real world test here.
268;
269%endif ; 0
270 ; Bytes EU Cycles(808x/286)
271 xor dx, dx ; 2 3/2
272 mov ax, es ; 2 2/2
[480]273%rep 4
[491]274 shl ax, 1 ; 8 8/8
275 rcl dx, 1 ; 8 8/8
[480]276%endrep
[491]277 add si, ax ; 2 3/2
278 adc dl, dh ; 2 3/2
279 mov es, dx ; 2 2/2
280 ;------------------------------------
281%endif ; 26 29/26
[150]282 ret
[493]283%endif ; MODULE_8BIT_IDE_ADVANCED
[480]284 ; Fall to IdeTransfer_NormalizePointerInESSI if no MODULE_8BIT_IDE
[150]285
286
[480]287;--------------------------------------------------------------------
288; IdeTransfer_NormalizePointerInESSI
289; Parameters:
290; ES:SI: Ptr to be normalized
291; Returns:
292; ES:SI: Normalized pointer (SI = 0...15)
293; Corrupts registers:
294; AX, DX
295;--------------------------------------------------------------------
296IdeTransfer_NormalizePointerInESSI:
297 NORMALIZE_FAR_POINTER es, si, ax, dx
298 ret
[400]299
[480]300
[150]301; Lookup tables to get transfer function based on bus type
302ALIGN WORD_ALIGN
303g_rgfnPioRead:
[473]304 dw IdePioBlock_ReadFrom16bitDataPort ; 0, DEVICE_16BIT_ATA
305 dw IdePioBlock_ReadFrom32bitDataPort ; 1, DEVICE_32BIT_ATA
[400]306%ifdef MODULE_8BIT_IDE
[480]307 dw IdePioBlock_ReadFrom8bitDataPort ; 2, DEVICE_8BIT_ATA
[491]308 dw IdePioBlock_ReadFromXtideRev1 ; 3, DEVICE_8BIT_XTIDE_REV1
[480]309 dw IdePioBlock_ReadFromXtideRev2 ; 4, DEVICE_8BIT_XTIDE_REV2
[493]310%ifdef MODULE_8BIT_IDE_ADVANCED
[480]311 dw IdePioBlock_ReadFrom8bitDataPort ; 5, DEVICE_8BIT_XTCF_PIO8
312 dw IdeDmaBlock_ReadFromXTCF ; 6, DEVICE_8BIT_XTCF_DMA
[473]313%endif
[493]314%endif
[400]315
[480]316
[473]317g_rgfnPioWrite:
318 dw IdePioBlock_WriteTo16bitDataPort ; 0, DEVICE_16BIT_ATA
319 dw IdePioBlock_WriteTo32bitDataPort ; 1, DEVICE_32BIT_ATA
[400]320%ifdef MODULE_8BIT_IDE
[480]321 dw IdePioBlock_WriteTo8bitDataPort ; 2, DEVICE_8BIT_ATA
322 dw IdePioBlock_WriteToXtideRev1 ; 3, DEVICE_8BIT_XTIDE_REV1
323 dw IdePioBlock_WriteToXtideRev2 ; 4, DEVICE_8BIT_XTIDE_REV2
[526]324%ifdef MODULE_8BIT_IDE_ADVANCED
[480]325 dw IdePioBlock_WriteTo8bitDataPort ; 5, DEVICE_8BIT_XTCF_PIO8
326 dw IdeDmaBlock_WriteToXTCF ; 6, DEVICE_8BIT_XTCF_DMA
[361]327%endif
[493]328%endif
Note: See TracBrowser for help on using the repository browser.