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

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

Changes:

  • A speed optimization to the eSHL_IM macro for 386 and higher. This change breaks emulation in the sense that the macro will fail when given a memory operand as the first parameter.
  • Memory_SumCXbytesFromESSItoAL now returns with the zero flag set/cleared according to the result.
  • Unrolled all the 8 bit READ transfer loops to do 16 bytes per iteration. Added a new macro (UNROLL_SECTORS_IN_CX_TO_OWORDS) as part of it. Size wise this is expensive but I think it should be worth the ROM space. The WRITE transfer loops were left as is since writes are rare anyway (<10% of all disk I/O IIRC).
  • Minor optimizations and fixes here and there.
File size: 13.0 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-2012 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 normalized 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 ; Are we reading or writing?
53 test al, 16 ; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
54 mov ah, [bp+IDEPACK.bSectorCount]
55 jnz SHORT WriteToDrive
56 cmp al, COMMAND_WRITE_MULTIPLE
57 je SHORT WriteToDrive
58 ; Fall to ReadFromDrive
59
60;--------------------------------------------------------------------
61; ReadFromDrive
62; Parameters:
63; AH: Number of sectors to transfer (1...128)
64; ES:SI: Normalized ptr to buffer to receive data
65; DS:DI: Ptr to DPT (in RAMVARS segment)
66; SS:BP: Ptr to PIOVARS
67; Returns:
68; DS:DI: Ptr to DPT (in RAMVARS segment)
69; AH: BIOS Error code
70; CX: Number of successfully transferred sectors
71; CF: 0 if transfer successful
72; 1 if any error
73; Corrupts registers:
74; AL, BX, DX, SI, ES
75;--------------------------------------------------------------------
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
83 jc SHORT ReturnWithTransferErrorInAH
84 xchg si, di ; ES:DI now points buffer
85
86 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
87
88ALIGN JUMP_ALIGN
89.ReadNextBlockFromDrive:
90 mov dx, [bp+PIOVARS.wDataPort]
91 cmp [bp+PIOVARS.bSectorsLeft], cl
92 jbe SHORT .ReadLastBlockFromDrive
93 call [bp+PIOVARS.fnXfer]
94
95 ; Wait until ready for next block and check for errors
96 xchg di, si ; DS:DI now points DPT
97 call IdeWait_IRQorDRQ ; Wait until ready to transfer
98 jc SHORT ReturnWithTransferErrorInAH
99 xchg si, di ; ES:DI now points buffer
100
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
105 jmp SHORT .ReadNextBlockFromDrive
106
107ALIGN JUMP_ALIGN
108.ReadLastBlockFromDrive:
109 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
110 push cx
111 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
112
113 ; Check for errors in last block
114 mov di, si ; DS:DI now points DPT
115CheckErrorsAfterTransferringLastBlock:
116 mov bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_BSY)
117 call IdeWait_PollStatusFlagInBLwithTimeoutInBH
118 pop cx ; [bp+PIOVARS.bSectorsLeft]
119 jc SHORT ReturnWithTransferErrorInAH
120
121 ; All sectors successfully transferred
122 add cx, [bp+PIOVARS.bSectorsDone] ; Never sets CF
123 ret
124
125 ; Return number of successfully read sectors
126ReturnWithTransferErrorInAH:
127%ifdef USE_386
128 movzx cx, [bp+PIOVARS.bSectorsDone]
129%else
130 mov cl, [bp+PIOVARS.bSectorsDone]
131 mov ch, 0 ; Preserve CF
132%endif
133 ret
134
135
136;--------------------------------------------------------------------
137; WriteToDrive
138; Parameters:
139; AH: Number of sectors to transfer (1...128)
140; DS:DI: Ptr to DPT (in RAMVARS segment)
141; ES:SI: Normalized ptr to buffer containing data
142; SS:BP: Ptr to PIOVARS
143; Returns:
144; AH: BIOS Error code
145; CX: Number of successfully transferred sectors
146; CF: 0 if transfer successful
147; 1 if any error
148; Corrupts registers:
149; AL, BX, DX, SI, ES
150;--------------------------------------------------------------------
151ALIGN JUMP_ALIGN
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
160 jc SHORT ReturnWithTransferErrorInAH
161
162 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
163
164ALIGN JUMP_ALIGN
165.WriteNextBlockToDrive:
166 mov dx, [bp+PIOVARS.wDataPort]
167 cmp [bp+PIOVARS.bSectorsLeft], cl
168 jbe SHORT .WriteLastBlockToDrive
169 call [bp+PIOVARS.fnXfer]
170
171 ; Wait until ready for next block and check for errors
172 call IdeWait_IRQorDRQ ; Wait until ready to transfer
173 jc SHORT ReturnWithTransferErrorInAH
174
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
179 jmp SHORT .WriteNextBlockToDrive
180
181ALIGN JUMP_ALIGN
182.WriteLastBlockToDrive:
183 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
184 push cx
185%ifdef USE_186
186 push CheckErrorsAfterTransferringLastBlock
187 jmp [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
188%else
189 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
190 jmp SHORT CheckErrorsAfterTransferringLastBlock
191%endif
192
193
194;--------------------------------------------------------------------
195; InitializePiovarsInSSBPwithSectorCountInAH
196; Parameters:
197; AH: Number of sectors to transfer (1...128)
198; BX: Offset to transfer function lookup table
199; DS:DI: Ptr to DPT (in RAMVARS segment)
200; SS:BP: Ptr to PIOVARS
201; Returns:
202; Nothing
203; Corrupts registers:
204; AX, BX, DX
205;--------------------------------------------------------------------
206ALIGN JUMP_ALIGN
207InitializePiovarsInSSBPwithSectorCountInAH:
208 ; Store sizes
209 mov [bp+PIOVARS.bSectorsLeft], ah
210 eMOVZX ax, [di+DPT_ATA.bBlockSize]
211 mov [bp+PIOVARS.wSectorsInBlock], ax
212 mov [bp+PIOVARS.bSectorsDone], ah ; Zero
213
214 ; Get transfer function based on bus type
215 xchg ax, bx ; Lookup table offset to AX
216 mov bl, [di+DPT.bIdevarsOffset] ; CS:BX now points to IDEVARS
217 mov dx, [cs:bx+IDEVARS.wPort] ; Load IDE Data port address
218 mov bl, [di+DPT_ATA.bDevice]
219 add bx, ax
220
221 mov [bp+PIOVARS.wDataPort], dx
222 mov ax, [cs:bx] ; Load offset to transfer function
223 mov [bp+PIOVARS.fnXfer], ax
224 ret
225
226
227;--------------------------------------------------------------------
228; ReadBlockFromXtideRev1 XTIDE rev 1
229; ReadBlockFromXtideRev2 XTIDE rev 2 or rev 1 with swapped A0 and A3 (chuck-mod)
230; ReadBlockFrom8bitDataPort CF-XT when using 8-bit PIO
231; ReadBlockFrom16bitDataPort Normal 16-bit IDE
232; ReadBlockFrom32bitDataPort VLB/PCI 32-bit IDE
233; Parameters:
234; CX: Block size in 512 byte sectors
235; DX: IDE Data port address
236; ES:DI: Normalized ptr to buffer to receive data
237; Returns:
238; Nothing
239; Corrupts registers:
240; AX, BX, CX
241;--------------------------------------------------------------------
242%ifdef MODULE_8BIT_IDE
243
244 ALIGN JUMP_ALIGN
245 ReadBlockFromXtideRev1:
246 UNROLL_SECTORS_IN_CX_TO_OWORDS
247 mov bl, 8 ; Bit mask for toggling data low/high reg
248 ALIGN JUMP_ALIGN
249 .InswLoop:
250 %rep 8 ; WORDs
251 XTIDE_INSW
252 %endrep
253 loop .InswLoop
254 ret
255
256 ;--------------------------------------------------------------------
257 %ifndef USE_186 ; 8086/8088 compatible WORD read
258 ALIGN JUMP_ALIGN
259 ReadBlockFromXtideRev2:
260 UNROLL_SECTORS_IN_CX_TO_OWORDS
261 ALIGN JUMP_ALIGN
262 .ReadNextOword:
263 %rep 8 ; WORDs
264 in ax, dx ; Read WORD
265 stosw ; Store WORD to [ES:DI]
266 %endrep
267 loop .ReadNextOword
268 ret
269 %endif
270
271 ;--------------------------------------------------------------------
272 %ifdef USE_186
273 ALIGN JUMP_ALIGN
274 ReadBlockFrom8bitDataPort:
275 shl cx, 9 ; Sectors to BYTEs
276 rep insb
277 ret
278
279 %else ; If 8088/8086
280 ALIGN JUMP_ALIGN
281 ReadBlockFrom8bitDataPort:
282 UNROLL_SECTORS_IN_CX_TO_OWORDS
283 ALIGN JUMP_ALIGN
284 .ReadNextOword:
285 %rep 16 ; BYTEs
286 in al, dx ; Read BYTE
287 stosb ; Store BYTE to [ES:DI]
288 %endrep
289 loop .ReadNextOword
290 ret
291 %endif
292%endif ; MODULE_8BIT_IDE
293
294;--------------------------------------------------------------------
295%ifdef USE_186
296 ALIGN JUMP_ALIGN
297 ReadBlockFrom16bitDataPort:
298 xchg cl, ch ; Sectors to WORDs
299 rep insw
300 ret
301%endif
302
303;--------------------------------------------------------------------
304%ifdef USE_AT
305 ALIGN JUMP_ALIGN
306 ReadBlockFrom32bitDataPort:
307 shl cx, 7 ; Sectors to DWORDs
308 rep
309 db 66h ; Override operand size to 32-bit
310 db 6Dh ; INSW/INSD
311 ret
312%endif
313
314
315;--------------------------------------------------------------------
316; WriteBlockToXtideRev1 XTIDE rev 1
317; WriteBlockToXtideRev2 XTIDE rev 2 or rev 1 with swapped A0 and A3 (chuck-mod)
318; WriteBlockTo8bitDataPort XT-CF when using 8-bit PIO
319; WriteBlockTo16bitDataPort Normal 16-bit IDE
320; WriteBlockTo32bitDataPort VLB/PCI 32-bit IDE
321; Parameters:
322; CX: Block size in 512-byte sectors
323; DX: IDE Data port address
324; ES:SI: Normalized ptr to buffer containing data
325; Returns:
326; Nothing
327; Corrupts registers:
328; AX, BX, CX, DX
329;--------------------------------------------------------------------
330%ifdef MODULE_8BIT_IDE
331
332 ALIGN JUMP_ALIGN
333 WriteBlockToXtideRev1:
334 push ds
335 UNROLL_SECTORS_IN_CX_TO_QWORDS
336 mov bl, 8 ; Bit mask for toggling data low/high reg
337 push es ; Copy ES...
338 pop ds ; ...to DS
339 ALIGN JUMP_ALIGN
340 .OutswLoop:
341 %rep 4 ; WORDs
342 XTIDE_OUTSW
343 %endrep
344 loop .OutswLoop
345 pop ds
346 ret
347
348 ;--------------------------------------------------------------------
349 ALIGN JUMP_ALIGN
350 WriteBlockToXtideRev2:
351 UNROLL_SECTORS_IN_CX_TO_QWORDS
352 push ds
353 push es ; Copy ES...
354 pop ds ; ...to DS
355 ALIGN JUMP_ALIGN
356 .WriteNextQword:
357 %rep 4 ; WORDs
358 XTIDE_MOD_OUTSW
359 %endrep
360 loop .WriteNextQword
361 pop ds
362 ret
363
364 ;--------------------------------------------------------------------
365 %ifdef USE_186
366 ALIGN JUMP_ALIGN
367 WriteBlockTo8bitDataPort:
368 shl cx, 9 ; Sectors to BYTEs
369 es ; Source is ES segment
370 rep outsb
371 ret
372
373 %else ; If 8088/8086
374 ALIGN JUMP_ALIGN
375 WriteBlockTo8bitDataPort:
376 UNROLL_SECTORS_IN_CX_TO_DWORDS
377 push ds
378 push es
379 pop ds
380 ALIGN JUMP_ALIGN
381 .WriteNextDword:
382 %rep 4 ; BYTEs
383 lodsb ; Load BYTE from [DS:SI]
384 out dx, al ; Write BYTE
385 %endrep
386 loop .WriteNextDword
387 pop ds
388 ret
389 %endif
390%endif ; MODULE_8BIT_IDE
391
392;--------------------------------------------------------------------
393%ifdef USE_AT
394ALIGN JUMP_ALIGN
395WriteBlockTo16bitDataPort:
396 xchg cl, ch ; Sectors to WORDs
397 es ; Source is ES segment
398 rep outsw
399 ret
400
401;--------------------------------------------------------------------
402ALIGN JUMP_ALIGN
403WriteBlockTo32bitDataPort:
404 shl cx, 7 ; Sectors to DWORDs
405 es ; Source is ES segment
406 rep
407 db 66h ; Override operand size to 32-bit
408 db 6Fh ; OUTSW/OUTSD
409 ret
410%endif ; USE_AT
411
412
413
414; Lookup tables to get transfer function based on bus type
415ALIGN WORD_ALIGN
416g_rgfnPioRead:
417%ifdef MODULE_8BIT_IDE
418 dw 0 ; 0, DEVICE_8BIT_JRIDE_ISA
419 dw ReadBlockFrom8bitDataPort ; 1, DEVICE_8BIT_XTCF
420 %ifdef USE_186
421 dw ReadBlockFrom16bitDataPort ; 2, DEVICE_8BIT_XTIDE_REV2
422 %else
423 dw ReadBlockFromXtideRev2 ; 2, DEVICE_8BIT_XTIDE_REV2
424 %endif
425 dw ReadBlockFromXtideRev1 ; 3, DEVICE_XTIDE_REV1
426
427%else
428 times COUNT_OF_8BIT_IDE_DEVICES dw 0
429%endif
430%ifdef USE_AT
431 dw ReadBlockFrom16bitDataPort ; 4, DEVICE_16BIT_ATA
432 dw ReadBlockFrom32bitDataPort ; 5, DEVICE_32BIT_ATA
433%endif
434
435
436g_rgfnPioWrite:
437%ifdef MODULE_8BIT_IDE
438 dw 0 ; 0, DEVICE_8BIT_JRIDE_ISA
439 dw WriteBlockTo8bitDataPort ; 1, DEVICE_8BIT_XTCF
440 dw WriteBlockToXtideRev2 ; 2, DEVICE_XTIDE_REV2
441 dw WriteBlockToXtideRev1 ; 3, DEVICE_XTIDE_REV1
442
443%else
444 times COUNT_OF_8BIT_IDE_DEVICES dw 0
445%endif
446%ifdef USE_AT
447 dw WriteBlockTo16bitDataPort ; 4, DEVICE_16BIT_ATA
448 dw WriteBlockTo32bitDataPort ; 5, DEVICE_32BIT_ATA
449%endif
Note: See TracBrowser for help on using the repository browser.