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

Last change on this file since 607 was 602, checked in by Krister Nordvall, 5 years ago

Changes:

  • SerDrive: Fixed a bug that prevented use of 3.5" 720 KB floppy disk images.
  • Also added support for Microsoft DMF (Distribution Media Format) floppy disk images.
  • XTIDECFG / Library: Minor size optimizations. Added a new macro (SKIP1B) as part of that.
  • BIOS: A small size optimization (2 bytes) to MODULE_8BIT_IDE_ADVANCED that is enabled only when USE_NEC_V is defined.
File size: 11.9 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
[538]80%ifdef USE_AT
81 jc SHORT ReturnWithTransferErrorInAH
82%endif
[242]83
84 ; Wait until drive is ready to transfer
85 call IdeWait_IRQorDRQ ; Wait until ready to transfer
[218]86 jc SHORT ReturnWithTransferErrorInAH
[242]87 xchg si, di ; ES:DI now points buffer
[218]88
[363]89 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
[242]90
[150]91ALIGN JUMP_ALIGN
[242]92.ReadNextBlockFromDrive:
[150]93 mov dx, [bp+PIOVARS.wDataPort]
[363]94 cmp [bp+PIOVARS.bSectorsLeft], cl
[242]95 jbe SHORT .ReadLastBlockFromDrive
[218]96 call [bp+PIOVARS.fnXfer]
[169]97
[218]98 ; Wait until ready for next block and check for errors
[242]99 xchg di, si ; DS:DI now points DPT
[218]100 call IdeWait_IRQorDRQ ; Wait until ready to transfer
101 jc SHORT ReturnWithTransferErrorInAH
[242]102 xchg si, di ; ES:DI now points buffer
[169]103
[363]104 ; Increment number of successfully read sectors
105 mov cx, [bp+PIOVARS.wSectorsInBlock]
106 sub [bp+PIOVARS.bSectorsLeft], cl
107 add [bp+PIOVARS.bSectorsDone], cl
[242]108 jmp SHORT .ReadNextBlockFromDrive
[150]109
110ALIGN JUMP_ALIGN
[242]111.ReadLastBlockFromDrive:
[363]112 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
[419]113 push cx
[150]114 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
115
[242]116 ; Check for errors in last block
117 mov di, si ; DS:DI now points DPT
118CheckErrorsAfterTransferringLastBlock:
[417]119 mov bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_BSY)
[242]120 call IdeWait_PollStatusFlagInBLwithTimeoutInBH
[419]121 pop cx ; [bp+PIOVARS.bSectorsLeft]
122 jc SHORT ReturnWithTransferErrorInAH
[150]123
[445]124 ; All sectors successfully transferred
[419]125 add cx, [bp+PIOVARS.bSectorsDone] ; Never sets CF
126 ret
127
[242]128 ; Return number of successfully read sectors
129ReturnWithTransferErrorInAH:
[370]130%ifdef USE_386
131 movzx cx, [bp+PIOVARS.bSectorsDone]
132%else
[363]133 mov cl, [bp+PIOVARS.bSectorsDone]
134 mov ch, 0 ; Preserve CF
[370]135%endif
[242]136 ret
137
138
[150]139;--------------------------------------------------------------------
[242]140; WriteToDrive
[150]141; Parameters:
[242]142; AH: Number of sectors to transfer (1...128)
143; DS:DI: Ptr to DPT (in RAMVARS segment)
[480]144; ES:SI: Ptr to buffer containing data
[150]145; SS:BP: Ptr to PIOVARS
146; Returns:
147; AH: BIOS Error code
[218]148; CX: Number of successfully transferred sectors
[294]149; CF: 0 if transfer successful
[150]150; 1 if any error
151; Corrupts registers:
[218]152; AL, BX, DX, SI, ES
[150]153;--------------------------------------------------------------------
154ALIGN JUMP_ALIGN
[242]155WriteToDrive:
156 ; Prepare to write data from ESSI
157 mov bx, g_rgfnPioWrite
158 call InitializePiovarsInSSBPwithSectorCountInAH
[538]159%ifdef USE_AT
160 jc SHORT ReturnWithTransferErrorInAH
161%endif
[242]162
163 ; Always poll when writing first block (IRQs are generated for following blocks)
164 mov bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
165 call IdeWait_PollStatusFlagInBLwithTimeoutInBH
[218]166 jc SHORT ReturnWithTransferErrorInAH
[150]167
[363]168 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
[242]169
[218]170ALIGN JUMP_ALIGN
[242]171.WriteNextBlockToDrive:
[150]172 mov dx, [bp+PIOVARS.wDataPort]
[363]173 cmp [bp+PIOVARS.bSectorsLeft], cl
[242]174 jbe SHORT .WriteLastBlockToDrive
[589]175 push ds
176 push es
177 pop ds
[218]178 call [bp+PIOVARS.fnXfer]
[589]179 pop ds
[218]180 ; Wait until ready for next block and check for errors
181 call IdeWait_IRQorDRQ ; Wait until ready to transfer
182 jc SHORT ReturnWithTransferErrorInAH
[150]183
[363]184 ; Increment number of successfully written sectors
185 mov cx, [bp+PIOVARS.wSectorsInBlock]
186 sub [bp+PIOVARS.bSectorsLeft], cl
187 add [bp+PIOVARS.bSectorsDone], cl
[242]188 jmp SHORT .WriteNextBlockToDrive
[169]189
[150]190ALIGN JUMP_ALIGN
[242]191.WriteLastBlockToDrive:
[363]192 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
[419]193 push cx
[589]194 push ds
195 push es
196 pop ds
[150]197 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
[589]198 pop ds
[242]199 jmp SHORT CheckErrorsAfterTransferringLastBlock
[218]200
[150]201
202;--------------------------------------------------------------------
[218]203; InitializePiovarsInSSBPwithSectorCountInAH
[150]204; Parameters:
[218]205; AH: Number of sectors to transfer (1...128)
[150]206; BX: Offset to transfer function lookup table
207; DS:DI: Ptr to DPT (in RAMVARS segment)
[480]208; ES:SI: Ptr to data buffer
[169]209; SS:BP: Ptr to PIOVARS
[167]210; Returns:
[538]211; ES:SI: Normalized pointer
212; AH: INT 13h Error Code (only when CF set)
[558]213; CF: Set if failed to normalize pointer (segment overflow)
[538]214; Cleared if success
[150]215; Corrupts registers:
[538]216; AL, BX, DX
[150]217;--------------------------------------------------------------------
218ALIGN JUMP_ALIGN
[218]219InitializePiovarsInSSBPwithSectorCountInAH:
[473]220 ; Store sizes and Data Port
[363]221 mov [bp+PIOVARS.bSectorsLeft], ah
[538]222%ifdef USE_AT
223 xchg dx, ax
224%endif
[473]225 mov ax, [di+DPT.wBasePort]
226 mov [bp+PIOVARS.wDataPort], ax
[370]227 eMOVZX ax, [di+DPT_ATA.bBlockSize]
[363]228 mov [bp+PIOVARS.wSectorsInBlock], ax
229 mov [bp+PIOVARS.bSectorsDone], ah ; Zero
[150]230
231 ; Get transfer function based on bus type
[567]232 mov al, [di+DPT_ATA.bDevice]
233 add bx, ax
[493]234%ifdef MODULE_8BIT_IDE_ADVANCED
[567]235 cmp al, DEVICE_8BIT_XTCF_DMA
[480]236%endif
[150]237 mov ax, [cs:bx] ; Load offset to transfer function
238 mov [bp+PIOVARS.fnXfer], ax
[480]239
240 ; Normalize pointer for PIO-transfers and convert to physical address for DMA transfers
[493]241%ifdef MODULE_8BIT_IDE_ADVANCED
[480]242 jb SHORT IdeTransfer_NormalizePointerInESSI
243
244 ; Convert ES:SI to physical address
[568]245%ifdef USE_386
246 mov dx, es
247 xor ax, ax
248 shld ax, dx, 4
249 shl dx, 4
250 add si, dx
251 adc al, ah
252 mov es, ax
253
254%elifdef USE_186
[602]255%ifdef USE_NEC_V
256 mov dx, es
257 xor ax, ax
258 eROL4 dl
259 eROL4 dh
260 add si, dx
261 adc al, ah
262 mov es, ax
263
264%else
[589]265 mov ax, es
266 rol ax, 4
267 mov dx, ax
268 and ax, 0Fh
269 xor dx, ax
270 add si, dx
271 adc al, ah
272 mov es, ax
273
[602]274%endif
[491]275%else ; 808x
[589]276 mov al, 4
277 mov dx, es
278 xchg cx, ax
279 rol dx, cl
280 mov cx, dx
281 xchg cx, ax
282 and ax, 0Fh
283 xor dx, ax
284 add si, dx
285 adc al, ah
286 mov es, ax
287
[567]288%endif
289
290 ret ; With CF cleared (taken care of by the physical address conversion)
[493]291%endif ; MODULE_8BIT_IDE_ADVANCED
[558]292 ; Fall to IdeTransfer_NormalizePointerInESSI if no MODULE_8BIT_IDE_ADVANCED
[150]293
294
[480]295;--------------------------------------------------------------------
296; IdeTransfer_NormalizePointerInESSI
297; Parameters:
[538]298; DH: Number of sectors to transfer (when USE_AT defined)
[480]299; ES:SI: Ptr to be normalized
300; Returns:
301; ES:SI: Normalized pointer (SI = 0...15)
[558]302; AH: INT 13h Error Code (when USE_AT defined and normalization was attempted)
303; CF: Set if failed to normalize pointer (segment overflow)
[538]304; Cleared if success
[480]305; Corrupts registers:
306; AX, DX
307;--------------------------------------------------------------------
308IdeTransfer_NormalizePointerInESSI:
[538]309; Normalization can cause segment overflow if it is done when not needed
310; (I don't know if any software calls with such seg:off address).
311; This does not apply to XT systems since nothing will write to main BIOS ROM.
312; On AT systems things are quite different, even in protected mode the address
313; is passed in seg:offset form and HMA is accessible in real mode.
314%ifdef USE_AT
315 xor dl, dl
[558]316 eSHL_IM dx, 1
[538]317 dec dx ; Prevents normalization when bytes + offset will be zero
318 add dx, si
319 jc SHORT .NormalizationRequired
320 ret
321.NormalizationRequired:
322%endif ; USE_AT
323
[480]324 NORMALIZE_FAR_POINTER es, si, ax, dx
[538]325%ifdef USE_AT ; CF is always clear for XT builds
[558]326 ; AH = RET_HD_INVALID (01) if CF set, RET_HD_SUCCESS (00) if not. CF unchanged.
[589]327%ifdef USE_386
328 setc ah
329%else
[558]330 sbb ah, ah
331 neg ah
[538]332%endif
[589]333%endif ; USE_AT
[480]334 ret
[400]335
[480]336
[538]337
[150]338; Lookup tables to get transfer function based on bus type
339ALIGN WORD_ALIGN
340g_rgfnPioRead:
[601]341 dw IdePioBlock_ReadFrom16bitDataPort ; 0, DEVICE_16BIT_ATA
[589]342%ifdef MODULE_ADVANCED_ATA
[601]343 dw IdePioBlock_ReadFrom32bitDataPort ; 1, DEVICE_32BIT_ATA
[589]344%elifdef MODULE_8BIT_IDE
345 dw NULL
346%endif ; MODULE_ADVANCED_ATA
[400]347%ifdef MODULE_8BIT_IDE
[601]348 dw IdePioBlock_ReadFrom8bitDataPort ; 2, DEVICE_8BIT_ATA
349 dw IdePioBlock_ReadFromXtideRev1 ; 3, DEVICE_8BIT_XTIDE_REV1
350 dw IdePioBlock_ReadFrom16bitDataPort ; 4, DEVICE_8BIT_XTIDE_REV2
351 dw IdePioBlock_ReadFromXtideRev2_Olivetti ; 5, DEVICE_8BIT_XTIDE_REV2_OLIVETTI
[584]352%ifdef MODULE_8BIT_IDE_ADVANCED
[601]353 dw IdePioBlock_ReadFrom8bitDataPort ; 6, DEVICE_8BIT_XTCF_PIO8
354 dw IdePioBlock_ReadFrom16bitDataPort ; 7, DEVICE_8BIT_XTCF_PIO8_WITH_BIU_OFFLOAD
355 dw IdePioBlock_ReadFrom16bitDataPort ; 8, DEVICE_8BIT_XTCF_PIO16_WITH_BIU_OFFLOAD
356 dw IdeDmaBlock_ReadFromXTCF ; 9, DEVICE_8BIT_XTCF_DMA
[545]357%endif ; MODULE_8BIT_IDE_ADVANCED
358%endif ; MODULE_8BIT_IDE
[400]359
[480]360
[473]361g_rgfnPioWrite:
[601]362 dw IdePioBlock_WriteTo16bitDataPort ; 0, DEVICE_16BIT_ATA
[589]363%ifdef MODULE_ADVANCED_ATA
[601]364 dw IdePioBlock_WriteTo32bitDataPort ; 1, DEVICE_32BIT_ATA
[589]365%elifdef MODULE_8BIT_IDE
366 dw NULL
367%endif ; MODULE_ADVANCED_ATA
[400]368%ifdef MODULE_8BIT_IDE
[601]369 dw IdePioBlock_WriteTo8bitDataPort ; 2, DEVICE_8BIT_ATA
370 dw IdePioBlock_WriteToXtideRev1 ; 3, DEVICE_8BIT_XTIDE_REV1
371 dw IdePioBlock_WriteToXtideRev2 ; 4, DEVICE_8BIT_XTIDE_REV2
372 dw IdePioBlock_WriteToXtideRev2 ; 5, DEVICE_8BIT_XTIDE_REV2_OLIVETTI
[584]373%ifdef MODULE_8BIT_IDE_ADVANCED
[601]374 dw IdePioBlock_WriteTo8bitDataPort ; 6, DEVICE_8BIT_XTCF_PIO8
375 dw IdePioBlock_WriteTo16bitDataPort ; 7, DEVICE_8BIT_XTCF_PIO8_WITH_BIU_OFFLOAD
376 dw IdePioBlock_WriteTo16bitDataPort ; 8, DEVICE_8BIT_XTCF_PIO16_WITH_BIU_OFFLOAD
377 dw IdeDmaBlock_WriteToXTCF ; 9, DEVICE_8BIT_XTCF_DMA
[545]378%endif ; MODULE_8BIT_IDE_ADVANCED
379%endif ; MODULE_8BIT_IDE
Note: See TracBrowser for help on using the repository browser.