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

Last change on this file since 630 was 630, checked in by Krister Nordvall, 8 days ago

Changes:

  • Changed the g_szPCFlashSuccessful string in XTIDECFG to reflect the reality - it turns out ANY key was limited to just ENTER or ESC.
  • Removed the NEC V-specific optimization I added in r602 because NEC's documentation completely fails to mention that the ROL4 instruction also changes the high nibble of AL. Huge thanks to vcfed-member dreNorteR for discovering this and also for suggesting an optimization to the physical address conversion code in IdeTransfer.asm.
  • Made some changes to the OUTPUT_AL_TO_IDE_REGISTER and OUTPUT_AL_TO_IDE_CONTROL_BLOCK_REGISTER macros as an optimization. This saves 15+12 bytes in builds without MODULE_8BIT_IDE (e.g. the PS/2 builds).
  • Other minor optimizations and cleanups.
File size: 12.7 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
[630]6; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2024 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:
[625]52%ifdef USE_PS2
53 ; Turn on the software controlled HDD LED on IBM PS/2 machines
54 xchg bx, ax ; Save AX
55 in al, 92h ; Read System Control Port A
56 or al, 80h ; Set bit 7 to turn on LED (bit 6 would also work)
57 out 92h, al ; Write it back
58 xchg bx, ax ; Restore AX
59%endif
[157]60 ; Are we reading or writing?
[171]61 test al, 16 ; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
[242]62 mov ah, [bp+IDEPACK.bSectorCount]
63 jnz SHORT WriteToDrive
[171]64 cmp al, COMMAND_WRITE_MULTIPLE
[242]65 je SHORT WriteToDrive
66 ; Fall to ReadFromDrive
[150]67
68;--------------------------------------------------------------------
[242]69; ReadFromDrive
[150]70; Parameters:
[242]71; AH: Number of sectors to transfer (1...128)
[480]72; ES:SI: Ptr to buffer to receive data
[150]73; DS:DI: Ptr to DPT (in RAMVARS segment)
74; SS:BP: Ptr to PIOVARS
75; Returns:
[242]76; DS:DI: Ptr to DPT (in RAMVARS segment)
[150]77; AH: BIOS Error code
[218]78; CX: Number of successfully transferred sectors
[294]79; CF: 0 if transfer successful
[150]80; 1 if any error
81; Corrupts registers:
[218]82; AL, BX, DX, SI, ES
[150]83;--------------------------------------------------------------------
[242]84ReadFromDrive:
85 ; Prepare to read data to ESSI
86 mov bx, g_rgfnPioRead
87 call InitializePiovarsInSSBPwithSectorCountInAH
[538]88%ifdef USE_AT
89 jc SHORT ReturnWithTransferErrorInAH
90%endif
[242]91
92 ; Wait until drive is ready to transfer
93 call IdeWait_IRQorDRQ ; Wait until ready to transfer
[218]94 jc SHORT ReturnWithTransferErrorInAH
[242]95 xchg si, di ; ES:DI now points buffer
[218]96
[363]97 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
[242]98
[150]99ALIGN JUMP_ALIGN
[242]100.ReadNextBlockFromDrive:
[150]101 mov dx, [bp+PIOVARS.wDataPort]
[363]102 cmp [bp+PIOVARS.bSectorsLeft], cl
[242]103 jbe SHORT .ReadLastBlockFromDrive
[218]104 call [bp+PIOVARS.fnXfer]
[169]105
[218]106 ; Wait until ready for next block and check for errors
[242]107 xchg di, si ; DS:DI now points DPT
[218]108 call IdeWait_IRQorDRQ ; Wait until ready to transfer
109 jc SHORT ReturnWithTransferErrorInAH
[242]110 xchg si, di ; ES:DI now points buffer
[169]111
[363]112 ; Increment number of successfully read sectors
113 mov cx, [bp+PIOVARS.wSectorsInBlock]
114 sub [bp+PIOVARS.bSectorsLeft], cl
115 add [bp+PIOVARS.bSectorsDone], cl
[242]116 jmp SHORT .ReadNextBlockFromDrive
[150]117
118ALIGN JUMP_ALIGN
[242]119.ReadLastBlockFromDrive:
[363]120 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
[419]121 push cx
[150]122 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
123
[242]124 ; Check for errors in last block
125 mov di, si ; DS:DI now points DPT
126CheckErrorsAfterTransferringLastBlock:
[417]127 mov bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_BSY)
[242]128 call IdeWait_PollStatusFlagInBLwithTimeoutInBH
[419]129 pop cx ; [bp+PIOVARS.bSectorsLeft]
130 jc SHORT ReturnWithTransferErrorInAH
[150]131
[445]132 ; All sectors successfully transferred
[419]133 add cx, [bp+PIOVARS.bSectorsDone] ; Never sets CF
[625]134%ifdef USE_PS2
135 ; Turn off the software controlled HDD LED on IBM PS/2 machines
136 in al, 92h ; Read System Control Port A
137 and al, 3Fh ; Clear bits 7 and 6 to turn off LED
138 out 92h, al ; Write it back
139%endif
[419]140 ret
141
[242]142 ; Return number of successfully read sectors
143ReturnWithTransferErrorInAH:
[370]144%ifdef USE_386
145 movzx cx, [bp+PIOVARS.bSectorsDone]
146%else
[363]147 mov cl, [bp+PIOVARS.bSectorsDone]
148 mov ch, 0 ; Preserve CF
[370]149%endif
[625]150%ifdef USE_PS2
151 ; Turn off the software controlled HDD LED on IBM PS/2 machines
152 in al, 92h ; Read System Control Port A
153 and al, 3Fh ; Clear bits 7 and 6 to turn off LED (Clears CF)
154 out 92h, al ; Write it back
155 stc ; Restore the CF
156%endif
[242]157 ret
158
159
[150]160;--------------------------------------------------------------------
[242]161; WriteToDrive
[150]162; Parameters:
[242]163; AH: Number of sectors to transfer (1...128)
164; DS:DI: Ptr to DPT (in RAMVARS segment)
[480]165; ES:SI: Ptr to buffer containing data
[150]166; SS:BP: Ptr to PIOVARS
167; Returns:
168; AH: BIOS Error code
[218]169; CX: Number of successfully transferred sectors
[294]170; CF: 0 if transfer successful
[150]171; 1 if any error
172; Corrupts registers:
[218]173; AL, BX, DX, SI, ES
[150]174;--------------------------------------------------------------------
175ALIGN JUMP_ALIGN
[242]176WriteToDrive:
177 ; Prepare to write data from ESSI
178 mov bx, g_rgfnPioWrite
179 call InitializePiovarsInSSBPwithSectorCountInAH
[538]180%ifdef USE_AT
181 jc SHORT ReturnWithTransferErrorInAH
182%endif
[242]183
184 ; Always poll when writing first block (IRQs are generated for following blocks)
185 mov bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
186 call IdeWait_PollStatusFlagInBLwithTimeoutInBH
[218]187 jc SHORT ReturnWithTransferErrorInAH
[150]188
[363]189 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
[242]190
[218]191ALIGN JUMP_ALIGN
[242]192.WriteNextBlockToDrive:
[150]193 mov dx, [bp+PIOVARS.wDataPort]
[363]194 cmp [bp+PIOVARS.bSectorsLeft], cl
[242]195 jbe SHORT .WriteLastBlockToDrive
[589]196 push ds
197 push es
198 pop ds
[218]199 call [bp+PIOVARS.fnXfer]
[589]200 pop ds
[218]201 ; Wait until ready for next block and check for errors
202 call IdeWait_IRQorDRQ ; Wait until ready to transfer
203 jc SHORT ReturnWithTransferErrorInAH
[150]204
[363]205 ; Increment number of successfully written sectors
206 mov cx, [bp+PIOVARS.wSectorsInBlock]
207 sub [bp+PIOVARS.bSectorsLeft], cl
208 add [bp+PIOVARS.bSectorsDone], cl
[242]209 jmp SHORT .WriteNextBlockToDrive
[169]210
[150]211ALIGN JUMP_ALIGN
[242]212.WriteLastBlockToDrive:
[363]213 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
[419]214 push cx
[589]215 push ds
216 push es
217 pop ds
[150]218 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
[589]219 pop ds
[242]220 jmp SHORT CheckErrorsAfterTransferringLastBlock
[218]221
[150]222
223;--------------------------------------------------------------------
[218]224; InitializePiovarsInSSBPwithSectorCountInAH
[150]225; Parameters:
[218]226; AH: Number of sectors to transfer (1...128)
[150]227; BX: Offset to transfer function lookup table
228; DS:DI: Ptr to DPT (in RAMVARS segment)
[480]229; ES:SI: Ptr to data buffer
[169]230; SS:BP: Ptr to PIOVARS
[167]231; Returns:
[538]232; ES:SI: Normalized pointer
233; AH: INT 13h Error Code (only when CF set)
[558]234; CF: Set if failed to normalize pointer (segment overflow)
[538]235; Cleared if success
[150]236; Corrupts registers:
[538]237; AL, BX, DX
[150]238;--------------------------------------------------------------------
239ALIGN JUMP_ALIGN
[218]240InitializePiovarsInSSBPwithSectorCountInAH:
[473]241 ; Store sizes and Data Port
[363]242 mov [bp+PIOVARS.bSectorsLeft], ah
[538]243%ifdef USE_AT
244 xchg dx, ax
245%endif
[473]246 mov ax, [di+DPT.wBasePort]
247 mov [bp+PIOVARS.wDataPort], ax
[370]248 eMOVZX ax, [di+DPT_ATA.bBlockSize]
[363]249 mov [bp+PIOVARS.wSectorsInBlock], ax
250 mov [bp+PIOVARS.bSectorsDone], ah ; Zero
[150]251
252 ; Get transfer function based on bus type
[567]253 mov al, [di+DPT_ATA.bDevice]
254 add bx, ax
[493]255%ifdef MODULE_8BIT_IDE_ADVANCED
[567]256 cmp al, DEVICE_8BIT_XTCF_DMA
[480]257%endif
[150]258 mov ax, [cs:bx] ; Load offset to transfer function
259 mov [bp+PIOVARS.fnXfer], ax
[480]260
261 ; Normalize pointer for PIO-transfers and convert to physical address for DMA transfers
[493]262%ifdef MODULE_8BIT_IDE_ADVANCED
[480]263 jb SHORT IdeTransfer_NormalizePointerInESSI
264
265 ; Convert ES:SI to physical address
[630]266%ifdef USE_386 ; 17 bytes
267 mov dx, es ; 2
268 xor ax, ax ; 2
269 shld ax, dx, 4 ; 3
270 shl dx, 4 ; 3
271 add si, dx ; 2
272 adc al, ah ; 2
273 mov es, ax ; 2
274 ;------
275 ; 16 cycles on 386
276%elifdef USE_186 ; 17 bytes
277 mov ax, es ; 2
278 rol ax, 4 ; 3
279 mov dx, ax ; 2
280 and al, 0F0h ; 2
281 xor dx, ax ; 2
282 add si, ax ; 2
283 adc dl, dh ; 2
284 mov es, dx ; 2
285 ;------
286 ; 17 cycles on 386
[491]287%else ; 808x
[589]288 mov al, 4
289 mov dx, es
290 xchg cx, ax
291 rol dx, cl
292 mov cx, dx
293 xchg cx, ax
[630]294 and al, 0F0h
[589]295 xor dx, ax
[630]296 add si, ax
297 adc dl, dh
298 mov es, dx
[589]299
[567]300%endif
301
302 ret ; With CF cleared (taken care of by the physical address conversion)
[493]303%endif ; MODULE_8BIT_IDE_ADVANCED
[558]304 ; Fall to IdeTransfer_NormalizePointerInESSI if no MODULE_8BIT_IDE_ADVANCED
[150]305
306
[480]307;--------------------------------------------------------------------
308; IdeTransfer_NormalizePointerInESSI
309; Parameters:
[538]310; DH: Number of sectors to transfer (when USE_AT defined)
[480]311; ES:SI: Ptr to be normalized
312; Returns:
313; ES:SI: Normalized pointer (SI = 0...15)
[558]314; AH: INT 13h Error Code (when USE_AT defined and normalization was attempted)
315; CF: Set if failed to normalize pointer (segment overflow)
[538]316; Cleared if success
[480]317; Corrupts registers:
318; AX, DX
319;--------------------------------------------------------------------
320IdeTransfer_NormalizePointerInESSI:
[538]321; Normalization can cause segment overflow if it is done when not needed
322; (I don't know if any software calls with such seg:off address).
323; This does not apply to XT systems since nothing will write to main BIOS ROM.
324; On AT systems things are quite different, even in protected mode the address
325; is passed in seg:offset form and HMA is accessible in real mode.
326%ifdef USE_AT
327 xor dl, dl
[558]328 eSHL_IM dx, 1
[538]329 dec dx ; Prevents normalization when bytes + offset will be zero
330 add dx, si
331 jc SHORT .NormalizationRequired
332 ret
333.NormalizationRequired:
334%endif ; USE_AT
335
[480]336 NORMALIZE_FAR_POINTER es, si, ax, dx
[538]337%ifdef USE_AT ; CF is always clear for XT builds
[558]338 ; AH = RET_HD_INVALID (01) if CF set, RET_HD_SUCCESS (00) if not. CF unchanged.
[589]339%ifdef USE_386
340 setc ah
341%else
[558]342 sbb ah, ah
343 neg ah
[538]344%endif
[589]345%endif ; USE_AT
[480]346 ret
[400]347
[480]348
[538]349
[150]350; Lookup tables to get transfer function based on bus type
351ALIGN WORD_ALIGN
352g_rgfnPioRead:
[601]353 dw IdePioBlock_ReadFrom16bitDataPort ; 0, DEVICE_16BIT_ATA
[589]354%ifdef MODULE_ADVANCED_ATA
[601]355 dw IdePioBlock_ReadFrom32bitDataPort ; 1, DEVICE_32BIT_ATA
[589]356%elifdef MODULE_8BIT_IDE
357 dw NULL
358%endif ; MODULE_ADVANCED_ATA
[400]359%ifdef MODULE_8BIT_IDE
[601]360 dw IdePioBlock_ReadFrom8bitDataPort ; 2, DEVICE_8BIT_ATA
361 dw IdePioBlock_ReadFromXtideRev1 ; 3, DEVICE_8BIT_XTIDE_REV1
362 dw IdePioBlock_ReadFrom16bitDataPort ; 4, DEVICE_8BIT_XTIDE_REV2
363 dw IdePioBlock_ReadFromXtideRev2_Olivetti ; 5, DEVICE_8BIT_XTIDE_REV2_OLIVETTI
[584]364%ifdef MODULE_8BIT_IDE_ADVANCED
[601]365 dw IdePioBlock_ReadFrom8bitDataPort ; 6, DEVICE_8BIT_XTCF_PIO8
366 dw IdePioBlock_ReadFrom16bitDataPort ; 7, DEVICE_8BIT_XTCF_PIO8_WITH_BIU_OFFLOAD
367 dw IdePioBlock_ReadFrom16bitDataPort ; 8, DEVICE_8BIT_XTCF_PIO16_WITH_BIU_OFFLOAD
368 dw IdeDmaBlock_ReadFromXTCF ; 9, DEVICE_8BIT_XTCF_DMA
[545]369%endif ; MODULE_8BIT_IDE_ADVANCED
370%endif ; MODULE_8BIT_IDE
[400]371
[480]372
[473]373g_rgfnPioWrite:
[601]374 dw IdePioBlock_WriteTo16bitDataPort ; 0, DEVICE_16BIT_ATA
[589]375%ifdef MODULE_ADVANCED_ATA
[601]376 dw IdePioBlock_WriteTo32bitDataPort ; 1, DEVICE_32BIT_ATA
[589]377%elifdef MODULE_8BIT_IDE
378 dw NULL
379%endif ; MODULE_ADVANCED_ATA
[400]380%ifdef MODULE_8BIT_IDE
[601]381 dw IdePioBlock_WriteTo8bitDataPort ; 2, DEVICE_8BIT_ATA
382 dw IdePioBlock_WriteToXtideRev1 ; 3, DEVICE_8BIT_XTIDE_REV1
383 dw IdePioBlock_WriteToXtideRev2 ; 4, DEVICE_8BIT_XTIDE_REV2
384 dw IdePioBlock_WriteToXtideRev2 ; 5, DEVICE_8BIT_XTIDE_REV2_OLIVETTI
[584]385%ifdef MODULE_8BIT_IDE_ADVANCED
[601]386 dw IdePioBlock_WriteTo8bitDataPort ; 6, DEVICE_8BIT_XTCF_PIO8
387 dw IdePioBlock_WriteTo16bitDataPort ; 7, DEVICE_8BIT_XTCF_PIO8_WITH_BIU_OFFLOAD
388 dw IdePioBlock_WriteTo16bitDataPort ; 8, DEVICE_8BIT_XTCF_PIO16_WITH_BIU_OFFLOAD
389 dw IdeDmaBlock_WriteToXTCF ; 9, DEVICE_8BIT_XTCF_DMA
[545]390%endif ; MODULE_8BIT_IDE_ADVANCED
391%endif ; MODULE_8BIT_IDE
Note: See TracBrowser for help on using the repository browser.