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

Last change on this file since 567 was 567, checked in by krille_n_@…, 10 years ago

Changes:

  • Renamed MODULE_FEATURE_SETS to MODULE_POWER_MANAGEMENT.
  • Renamed MODULE_VERY_LATE_INITIALIZATION to MODULE_VERY_LATE_INIT and removed it from the official builds.
  • Removed the code that skips detection of slave drives on XT-CF controllers since slave drives can be used with Lo-tech ISA CompactFlash boards.
  • Added autodetection of the SVC ADP50L controller to XTIDECFG.
  • The autodetection of XT-CF controllers now requires MODULE_8BIT_IDE_ADVANCED in the loaded BIOS.
  • Fixed a bug in XTIDECFG from r502 where the "Base (cmd block) address" menu option would be displayed when a serial device was selected as the IDE controller.
  • XTIDECFG would display the "Enable interrupt" menu option for the XTIDE r1 but not for the XTIDE r2. It's now displayed for both controller types.
  • Disabled the "Internal Write Cache" menu option in the Master/Slave Drive menus for serial device type drives.
  • Optimizations and other fixes.
File size: 12.1 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-2013 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    ; 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:  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%ifdef USE_AT
81    jc      SHORT ReturnWithTransferErrorInAH
82%endif
83
84    ; Wait until drive is ready to transfer
85    call    IdeWait_IRQorDRQ                    ; Wait until ready to transfer
86    jc      SHORT ReturnWithTransferErrorInAH
87    xchg    si, di                              ; ES:DI now points buffer
88
89    mov     cx, [bp+PIOVARS.wSectorsInBlock]    ; Max 128
90
91ALIGN JUMP_ALIGN
92.ReadNextBlockFromDrive:
93    mov     dx, [bp+PIOVARS.wDataPort]
94    cmp     [bp+PIOVARS.bSectorsLeft], cl
95    jbe     SHORT .ReadLastBlockFromDrive
96    call    [bp+PIOVARS.fnXfer]
97
98    ; Wait until ready for next block and check for errors
99    xchg    di, si                              ; DS:DI now points DPT
100    call    IdeWait_IRQorDRQ                    ; Wait until ready to transfer
101    jc      SHORT ReturnWithTransferErrorInAH
102    xchg    si, di                              ; ES:DI now points buffer
103
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
108    jmp     SHORT .ReadNextBlockFromDrive
109
110ALIGN JUMP_ALIGN
111.ReadLastBlockFromDrive:
112    mov     cl, [bp+PIOVARS.bSectorsLeft]       ; CH is already zero
113    push    cx
114    call    [bp+PIOVARS.fnXfer]                 ; Transfer possibly partial block
115
116    ; Check for errors in last block
117    mov     di, si                              ; DS:DI now points DPT
118CheckErrorsAfterTransferringLastBlock:
119    mov     bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_BSY)
120    call    IdeWait_PollStatusFlagInBLwithTimeoutInBH
121    pop     cx  ; [bp+PIOVARS.bSectorsLeft]
122    jc      SHORT ReturnWithTransferErrorInAH
123
124    ; All sectors successfully transferred
125    add     cx, [bp+PIOVARS.bSectorsDone]       ; Never sets CF
126    ret
127
128    ; Return number of successfully read sectors
129ReturnWithTransferErrorInAH:
130%ifdef USE_386
131    movzx   cx, [bp+PIOVARS.bSectorsDone]
132%else
133    mov     cl, [bp+PIOVARS.bSectorsDone]
134    mov     ch, 0                               ; Preserve CF
135%endif
136    ret
137
138
139;--------------------------------------------------------------------
140; WriteToDrive
141;   Parameters:
142;       AH:     Number of sectors to transfer (1...128)
143;       DS:DI:  Ptr to DPT (in RAMVARS segment)
144;       ES:SI:  Ptr to buffer containing data
145;       SS:BP:  Ptr to PIOVARS
146;   Returns:
147;       AH:     BIOS Error code
148;       CX:     Number of successfully transferred sectors
149;       CF:     0 if transfer successful
150;               1 if any error
151;   Corrupts registers:
152;       AL, BX, DX, SI, ES
153;--------------------------------------------------------------------
154ALIGN JUMP_ALIGN
155WriteToDrive:
156    ; Prepare to write data from ESSI
157    mov     bx, g_rgfnPioWrite
158    call    InitializePiovarsInSSBPwithSectorCountInAH
159%ifdef USE_AT
160    jc      SHORT ReturnWithTransferErrorInAH
161%endif
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
166    jc      SHORT ReturnWithTransferErrorInAH
167
168    mov     cx, [bp+PIOVARS.wSectorsInBlock]    ; Max 128
169
170ALIGN JUMP_ALIGN
171.WriteNextBlockToDrive:
172    mov     dx, [bp+PIOVARS.wDataPort]
173    cmp     [bp+PIOVARS.bSectorsLeft], cl
174    jbe     SHORT .WriteLastBlockToDrive
175    call    [bp+PIOVARS.fnXfer]
176
177    ; Wait until ready for next block and check for errors
178    call    IdeWait_IRQorDRQ                    ; Wait until ready to transfer
179    jc      SHORT ReturnWithTransferErrorInAH
180
181    ; Increment number of successfully written sectors
182    mov     cx, [bp+PIOVARS.wSectorsInBlock]
183    sub     [bp+PIOVARS.bSectorsLeft], cl
184    add     [bp+PIOVARS.bSectorsDone], cl
185    jmp     SHORT .WriteNextBlockToDrive
186
187ALIGN JUMP_ALIGN
188.WriteLastBlockToDrive:
189    mov     cl, [bp+PIOVARS.bSectorsLeft]       ; CH is already zero
190    push    cx
191%ifdef USE_186
192    push    CheckErrorsAfterTransferringLastBlock
193    jmp     [bp+PIOVARS.fnXfer]                 ; Transfer possibly partial block
194%else
195    call    [bp+PIOVARS.fnXfer]                 ; Transfer possibly partial block
196    jmp     SHORT CheckErrorsAfterTransferringLastBlock
197%endif
198
199
200;--------------------------------------------------------------------
201; InitializePiovarsInSSBPwithSectorCountInAH
202;   Parameters:
203;       AH:     Number of sectors to transfer (1...128)
204;       BX:     Offset to transfer function lookup table
205;       DS:DI:  Ptr to DPT (in RAMVARS segment)
206;       ES:SI:  Ptr to data buffer
207;       SS:BP:  Ptr to PIOVARS
208;   Returns:
209;       ES:SI:  Normalized pointer
210;       AH:     INT 13h Error Code (only when CF set)
211;       CF:     Set if failed to normalize pointer (segment overflow)
212;               Cleared if success
213;   Corrupts registers:
214;       AL, BX, DX
215;--------------------------------------------------------------------
216ALIGN JUMP_ALIGN
217InitializePiovarsInSSBPwithSectorCountInAH:
218    ; Store sizes and Data Port
219    mov     [bp+PIOVARS.bSectorsLeft], ah
220%ifdef USE_AT
221    xchg    dx, ax
222%endif
223    mov     ax, [di+DPT.wBasePort]
224    mov     [bp+PIOVARS.wDataPort], ax
225    eMOVZX  ax, [di+DPT_ATA.bBlockSize]
226    mov     [bp+PIOVARS.wSectorsInBlock], ax
227    mov     [bp+PIOVARS.bSectorsDone], ah       ; Zero
228
229    ; Get transfer function based on bus type
230    mov     al, [di+DPT_ATA.bDevice]
231    add     bx, ax
232%ifdef MODULE_8BIT_IDE_ADVANCED
233    cmp     al, DEVICE_8BIT_XTCF_DMA
234%endif
235    mov     ax, [cs:bx]                         ; Load offset to transfer function
236    mov     [bp+PIOVARS.fnXfer], ax
237
238    ; Normalize pointer for PIO-transfers and convert to physical address for DMA transfers
239%ifdef MODULE_8BIT_IDE_ADVANCED
240    jb      SHORT IdeTransfer_NormalizePointerInESSI
241
242    ; Convert ES:SI to physical address
243%ifdef USE_186
244                        ; Bytes EU Cycles(286)
245    mov     ax, es      ; 2     2
246    rol     ax, 4       ; 3     9
247    mov     dx, ax      ; 2     2
248    and     ax, BYTE 0Fh; 3     3
249    xor     dx, ax      ; 2     2
250    add     si, dx      ; 2     2
251    adc     al, ah      ; 2     2
252    mov     es, ax      ; 2     2
253    ;------------------------------------
254                        ; 18    24
255%else ; 808x
256                        ; Bytes EU Cycles(808x)
257    mov     al, 4       ; 2     4
258    mov     dx, es      ; 2     2
259    xchg    cx, ax      ; 1     3
260    rol     dx, cl      ; 2     24
261    mov     cx, dx      ; 2     2
262    xchg    cx, ax      ; 1     3
263    and     ax, BYTE 0Fh; 3     4
264    xor     dx, ax      ; 2     3
265    add     si, dx      ; 2     3
266    adc     al, ah      ; 2     3
267    mov     es, ax      ; 2     2
268    ;------------------------------------
269                        ; 21    53
270;
271; Judging by the Execution Unit cycle count the above block of code is
272; apparently slower. However, the shifts and rotates in the block below
273; execute faster than the Bus Interface Unit on an 8088 can fetch them,
274; thus causing the EU to starve. The difference in true execution speed
275; (if any) might not be worth the extra 5 bytes.
276; In other words, we could use a real world test here.
277;
278%if 0
279                        ; Bytes EU Cycles(808x/286)
280    xor     dx, dx      ; 2     3/2
281    mov     ax, es      ; 2     2/2
282%rep 4
283    shl     ax, 1       ; 8     8/8
284    rcl     dx, 1       ; 8     8/8
285%endrep
286    add     si, ax      ; 2     3/2
287    adc     dl, dh      ; 2     3/2
288    mov     es, dx      ; 2     2/2
289    ;------------------------------------
290                        ; 26    29/26
291%endif ; 0
292%endif
293
294    ret     ; With CF cleared (taken care of by the physical address conversion)
295%endif ; MODULE_8BIT_IDE_ADVANCED
296    ; Fall to IdeTransfer_NormalizePointerInESSI if no MODULE_8BIT_IDE_ADVANCED
297
298
299;--------------------------------------------------------------------
300; IdeTransfer_NormalizePointerInESSI
301;   Parameters:
302;       DH:     Number of sectors to transfer (when USE_AT defined)
303;       ES:SI:  Ptr to be normalized
304;   Returns:
305;       ES:SI:  Normalized pointer (SI = 0...15)
306;       AH:     INT 13h Error Code (when USE_AT defined and normalization was attempted)
307;       CF:     Set if failed to normalize pointer (segment overflow)
308;               Cleared if success
309;   Corrupts registers:
310;       AX, DX
311;--------------------------------------------------------------------
312IdeTransfer_NormalizePointerInESSI:
313; Normalization can cause segment overflow if it is done when not needed
314; (I don't know if any software calls with such seg:off address).
315; This does not apply to XT systems since nothing will write to main BIOS ROM.
316; On AT systems things are quite different, even in protected mode the address
317; is passed in seg:offset form and HMA is accessible in real mode.
318%ifdef USE_AT
319    xor     dl, dl
320    eSHL_IM dx, 1
321    dec     dx      ; Prevents normalization when bytes + offset will be zero
322    add     dx, si
323    jc      SHORT .NormalizationRequired
324    ret
325.NormalizationRequired:
326%endif ; USE_AT
327
328    NORMALIZE_FAR_POINTER   es, si, ax, dx
329%ifdef USE_AT       ; CF is always clear for XT builds
330    ; AH = RET_HD_INVALID (01) if CF set, RET_HD_SUCCESS (00) if not. CF unchanged.
331    sbb     ah, ah
332    neg     ah
333%endif
334    ret
335
336
337
338; Lookup tables to get transfer function based on bus type
339ALIGN WORD_ALIGN
340g_rgfnPioRead:
341        dw      IdePioBlock_ReadFrom16bitDataPort   ; 0, DEVICE_16BIT_ATA
342        dw      IdePioBlock_ReadFrom32bitDataPort   ; 1, DEVICE_32BIT_ATA
343%ifdef MODULE_8BIT_IDE
344        dw      IdePioBlock_ReadFrom8bitDataPort    ; 2, DEVICE_8BIT_ATA
345        dw      IdePioBlock_ReadFromXtideRev1       ; 3, DEVICE_8BIT_XTIDE_REV1
346        dw      IdePioBlock_ReadFrom16bitDataPort   ; 4, DEVICE_8BIT_XTIDE_REV2
347        dw      IdePioBlock_ReadFrom8bitDataPort    ; 5, DEVICE_8BIT_XTCF_PIO8
348        dw      IdePioBlock_ReadFrom16bitDataPort   ; 6, DEVICE_8BIT_XTCF_PIO8_WITH_BIU_OFFLOAD
349%ifdef MODULE_8BIT_IDE_ADVANCED
350        dw      IdeDmaBlock_ReadFromXTCF            ; 7, DEVICE_8BIT_XTCF_DMA
351%endif ; MODULE_8BIT_IDE_ADVANCED
352%endif ; MODULE_8BIT_IDE
353
354
355g_rgfnPioWrite:
356        dw      IdePioBlock_WriteTo16bitDataPort    ; 0, DEVICE_16BIT_ATA
357        dw      IdePioBlock_WriteTo32bitDataPort    ; 1, DEVICE_32BIT_ATA
358%ifdef MODULE_8BIT_IDE
359        dw      IdePioBlock_WriteTo8bitDataPort     ; 2, DEVICE_8BIT_ATA
360        dw      IdePioBlock_WriteToXtideRev1        ; 3, DEVICE_8BIT_XTIDE_REV1
361        dw      IdePioBlock_WriteToXtideRev2        ; 4, DEVICE_8BIT_XTIDE_REV2
362        dw      IdePioBlock_WriteTo8bitDataPort     ; 5, DEVICE_8BIT_XTCF_PIO8
363        dw      IdePioBlock_WriteTo16bitDataPort    ; 6, DEVICE_8BIT_XTCF_PIO8_WITH_BIU_OFFLOAD
364%ifdef MODULE_8BIT_IDE_ADVANCED
365        dw      IdeDmaBlock_WriteToXTCF             ; 7, DEVICE_8BIT_XTCF_DMA
366%endif ; MODULE_8BIT_IDE_ADVANCED
367%endif ; MODULE_8BIT_IDE
Note: See TracBrowser for help on using the repository browser.