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
Line 
1; Project name : XTIDE Universal BIOS
2; Description : IDE Device transfer functions.
3
4;
5; XTIDE Universal BIOS and Associated Tools
6; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2024 by XTIDE Universal BIOS Team.
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.
12;
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
16; GNU General Public License for more details.
17; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
18;
19
20; Structure containing variables for PIO transfer functions.
21; This struct must not be larger than IDEPACK without INTPACK.
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
26 .bSectorsLeft resb 1 ; 6, Sectors left to transfer
27 resb 1 ; 7, IDEPACK.bDeviceControl
28 .bSectorsDone resb 1 ; 8, Number of sectors xferred
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
39; (all PIO read and write commands including Identify Device)
40; ES:SI: Ptr to data buffer
41; DS:DI: Ptr to DPT (in RAMVARS segment)
42; SS:BP: Ptr to IDEPACK
43; Returns:
44; AH: INT 13h Error Code
45; CX: Number of successfully transferred sectors
46; CF: Cleared if success, Set if error
47; Corrupts registers:
48; AL, BX, DX, SI, ES
49;--------------------------------------------------------------------
50ALIGN JUMP_ALIGN
51IdeTransfer_StartWithCommandInAL:
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
60 ; Are we reading or writing?
61 test al, 16 ; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
62 mov ah, [bp+IDEPACK.bSectorCount]
63 jnz SHORT WriteToDrive
64 cmp al, COMMAND_WRITE_MULTIPLE
65 je SHORT WriteToDrive
66 ; Fall to ReadFromDrive
67
68;--------------------------------------------------------------------
69; ReadFromDrive
70; Parameters:
71; AH: Number of sectors to transfer (1...128)
72; ES:SI: Ptr to buffer to receive data
73; DS:DI: Ptr to DPT (in RAMVARS segment)
74; SS:BP: Ptr to PIOVARS
75; Returns:
76; DS:DI: Ptr to DPT (in RAMVARS segment)
77; AH: BIOS Error code
78; CX: Number of successfully transferred sectors
79; CF: 0 if transfer successful
80; 1 if any error
81; Corrupts registers:
82; AL, BX, DX, SI, ES
83;--------------------------------------------------------------------
84ReadFromDrive:
85 ; Prepare to read data to ESSI
86 mov bx, g_rgfnPioRead
87 call InitializePiovarsInSSBPwithSectorCountInAH
88%ifdef USE_AT
89 jc SHORT ReturnWithTransferErrorInAH
90%endif
91
92 ; Wait until drive is ready to transfer
93 call IdeWait_IRQorDRQ ; Wait until ready to transfer
94 jc SHORT ReturnWithTransferErrorInAH
95 xchg si, di ; ES:DI now points buffer
96
97 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
98
99ALIGN JUMP_ALIGN
100.ReadNextBlockFromDrive:
101 mov dx, [bp+PIOVARS.wDataPort]
102 cmp [bp+PIOVARS.bSectorsLeft], cl
103 jbe SHORT .ReadLastBlockFromDrive
104 call [bp+PIOVARS.fnXfer]
105
106 ; Wait until ready for next block and check for errors
107 xchg di, si ; DS:DI now points DPT
108 call IdeWait_IRQorDRQ ; Wait until ready to transfer
109 jc SHORT ReturnWithTransferErrorInAH
110 xchg si, di ; ES:DI now points buffer
111
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
116 jmp SHORT .ReadNextBlockFromDrive
117
118ALIGN JUMP_ALIGN
119.ReadLastBlockFromDrive:
120 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
121 push cx
122 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
123
124 ; Check for errors in last block
125 mov di, si ; DS:DI now points DPT
126CheckErrorsAfterTransferringLastBlock:
127 mov bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_BSY)
128 call IdeWait_PollStatusFlagInBLwithTimeoutInBH
129 pop cx ; [bp+PIOVARS.bSectorsLeft]
130 jc SHORT ReturnWithTransferErrorInAH
131
132 ; All sectors successfully transferred
133 add cx, [bp+PIOVARS.bSectorsDone] ; Never sets CF
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
140 ret
141
142 ; Return number of successfully read sectors
143ReturnWithTransferErrorInAH:
144%ifdef USE_386
145 movzx cx, [bp+PIOVARS.bSectorsDone]
146%else
147 mov cl, [bp+PIOVARS.bSectorsDone]
148 mov ch, 0 ; Preserve CF
149%endif
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
157 ret
158
159
160;--------------------------------------------------------------------
161; WriteToDrive
162; Parameters:
163; AH: Number of sectors to transfer (1...128)
164; DS:DI: Ptr to DPT (in RAMVARS segment)
165; ES:SI: Ptr to buffer containing data
166; SS:BP: Ptr to PIOVARS
167; Returns:
168; AH: BIOS Error code
169; CX: Number of successfully transferred sectors
170; CF: 0 if transfer successful
171; 1 if any error
172; Corrupts registers:
173; AL, BX, DX, SI, ES
174;--------------------------------------------------------------------
175ALIGN JUMP_ALIGN
176WriteToDrive:
177 ; Prepare to write data from ESSI
178 mov bx, g_rgfnPioWrite
179 call InitializePiovarsInSSBPwithSectorCountInAH
180%ifdef USE_AT
181 jc SHORT ReturnWithTransferErrorInAH
182%endif
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
187 jc SHORT ReturnWithTransferErrorInAH
188
189 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
190
191ALIGN JUMP_ALIGN
192.WriteNextBlockToDrive:
193 mov dx, [bp+PIOVARS.wDataPort]
194 cmp [bp+PIOVARS.bSectorsLeft], cl
195 jbe SHORT .WriteLastBlockToDrive
196 push ds
197 push es
198 pop ds
199 call [bp+PIOVARS.fnXfer]
200 pop ds
201 ; Wait until ready for next block and check for errors
202 call IdeWait_IRQorDRQ ; Wait until ready to transfer
203 jc SHORT ReturnWithTransferErrorInAH
204
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
209 jmp SHORT .WriteNextBlockToDrive
210
211ALIGN JUMP_ALIGN
212.WriteLastBlockToDrive:
213 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
214 push cx
215 push ds
216 push es
217 pop ds
218 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
219 pop ds
220 jmp SHORT CheckErrorsAfterTransferringLastBlock
221
222
223;--------------------------------------------------------------------
224; InitializePiovarsInSSBPwithSectorCountInAH
225; Parameters:
226; AH: Number of sectors to transfer (1...128)
227; BX: Offset to transfer function lookup table
228; DS:DI: Ptr to DPT (in RAMVARS segment)
229; ES:SI: Ptr to data buffer
230; SS:BP: Ptr to PIOVARS
231; Returns:
232; ES:SI: Normalized pointer
233; AH: INT 13h Error Code (only when CF set)
234; CF: Set if failed to normalize pointer (segment overflow)
235; Cleared if success
236; Corrupts registers:
237; AL, BX, DX
238;--------------------------------------------------------------------
239ALIGN JUMP_ALIGN
240InitializePiovarsInSSBPwithSectorCountInAH:
241 ; Store sizes and Data Port
242 mov [bp+PIOVARS.bSectorsLeft], ah
243%ifdef USE_AT
244 xchg dx, ax
245%endif
246 mov ax, [di+DPT.wBasePort]
247 mov [bp+PIOVARS.wDataPort], ax
248 eMOVZX ax, [di+DPT_ATA.bBlockSize]
249 mov [bp+PIOVARS.wSectorsInBlock], ax
250 mov [bp+PIOVARS.bSectorsDone], ah ; Zero
251
252 ; Get transfer function based on bus type
253 mov al, [di+DPT_ATA.bDevice]
254 add bx, ax
255%ifdef MODULE_8BIT_IDE_ADVANCED
256 cmp al, DEVICE_8BIT_XTCF_DMA
257%endif
258 mov ax, [cs:bx] ; Load offset to transfer function
259 mov [bp+PIOVARS.fnXfer], ax
260
261 ; Normalize pointer for PIO-transfers and convert to physical address for DMA transfers
262%ifdef MODULE_8BIT_IDE_ADVANCED
263 jb SHORT IdeTransfer_NormalizePointerInESSI
264
265 ; Convert ES:SI to physical address
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
287%else ; 808x
288 mov al, 4
289 mov dx, es
290 xchg cx, ax
291 rol dx, cl
292 mov cx, dx
293 xchg cx, ax
294 and al, 0F0h
295 xor dx, ax
296 add si, ax
297 adc dl, dh
298 mov es, dx
299
300%endif
301
302 ret ; With CF cleared (taken care of by the physical address conversion)
303%endif ; MODULE_8BIT_IDE_ADVANCED
304 ; Fall to IdeTransfer_NormalizePointerInESSI if no MODULE_8BIT_IDE_ADVANCED
305
306
307;--------------------------------------------------------------------
308; IdeTransfer_NormalizePointerInESSI
309; Parameters:
310; DH: Number of sectors to transfer (when USE_AT defined)
311; ES:SI: Ptr to be normalized
312; Returns:
313; ES:SI: Normalized pointer (SI = 0...15)
314; AH: INT 13h Error Code (when USE_AT defined and normalization was attempted)
315; CF: Set if failed to normalize pointer (segment overflow)
316; Cleared if success
317; Corrupts registers:
318; AX, DX
319;--------------------------------------------------------------------
320IdeTransfer_NormalizePointerInESSI:
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
328 eSHL_IM dx, 1
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
336 NORMALIZE_FAR_POINTER es, si, ax, dx
337%ifdef USE_AT ; CF is always clear for XT builds
338 ; AH = RET_HD_INVALID (01) if CF set, RET_HD_SUCCESS (00) if not. CF unchanged.
339%ifdef USE_386
340 setc ah
341%else
342 sbb ah, ah
343 neg ah
344%endif
345%endif ; USE_AT
346 ret
347
348
349
350; Lookup tables to get transfer function based on bus type
351ALIGN WORD_ALIGN
352g_rgfnPioRead:
353 dw IdePioBlock_ReadFrom16bitDataPort ; 0, DEVICE_16BIT_ATA
354%ifdef MODULE_ADVANCED_ATA
355 dw IdePioBlock_ReadFrom32bitDataPort ; 1, DEVICE_32BIT_ATA
356%elifdef MODULE_8BIT_IDE
357 dw NULL
358%endif ; MODULE_ADVANCED_ATA
359%ifdef MODULE_8BIT_IDE
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
364%ifdef MODULE_8BIT_IDE_ADVANCED
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
369%endif ; MODULE_8BIT_IDE_ADVANCED
370%endif ; MODULE_8BIT_IDE
371
372
373g_rgfnPioWrite:
374 dw IdePioBlock_WriteTo16bitDataPort ; 0, DEVICE_16BIT_ATA
375%ifdef MODULE_ADVANCED_ATA
376 dw IdePioBlock_WriteTo32bitDataPort ; 1, DEVICE_32BIT_ATA
377%elifdef MODULE_8BIT_IDE
378 dw NULL
379%endif ; MODULE_ADVANCED_ATA
380%ifdef MODULE_8BIT_IDE
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
385%ifdef MODULE_8BIT_IDE_ADVANCED
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
390%endif ; MODULE_8BIT_IDE_ADVANCED
391%endif ; MODULE_8BIT_IDE
Note: See TracBrowser for help on using the repository browser.