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

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

Changes to all parts of the project:

  • Size optimizations.
  • Added a define (EXCLUDE_FROM_XTIDECFG) to exclude unused library code from XTIDECFG.
  • Tried to minimize time spent with interrupts disabled.
  • Some minor attempts to improve speed (reordering instructions etc).
  • Tried to improve readability, did some cleanup and fixed some errors in comments.
File size: 11.4 KB
Line 
1; Project name  :   XTIDE Universal BIOS
2; Description   :   IDE Device transfer functions.
3
4; Structure containing variables for PIO transfer functions.
5; This struct must not be larger than IDEPACK without INTPACK.
6struc PIOVARS
7    .wBlocksLeft            resb    2
8    .wBlockSize             resb    2   ; Block size in WORDs (256...32768)
9    .wDataPort              resb    2
10    .bSectorsInLastBlock:   resb    1
11                            resb    1   ; Offset 7 = IDEPACK.bDeviceControl
12    .fnXfer                 resb    2   ; Offset to transfer function
13endstruc
14
15
16; Section containing code
17SECTION .text
18
19;--------------------------------------------------------------------
20; IdeTransfer_StartWithCommandInAL
21;   Parameters:
22;       AL:     IDE command that was used to start the transfer
23;               (all PIO read and write commands including Identify Device)
24;       ES:SI:  Ptr to destination buffer or source data
25;       DS:DI:  Ptr to DPT (in RAMVARS segment)
26;       SS:BP:  Ptr to IDEPACK
27;   Returns:
28;       AH:     INT 13h Error Code
29;       CF:     Cleared if success, Set if error
30;   Corrupts registers:
31;       AL, BX, CX, DX, SI, ES
32;--------------------------------------------------------------------
33ALIGN JUMP_ALIGN
34IdeTransfer_StartWithCommandInAL:
35    mov     ah, [bp+IDEPACK.bSectorCountHighExt]
36
37    ; Are we reading or writing?
38    test    al, 16  ; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
39    jnz     SHORT .PrepareToWriteDataFromESSI
40    cmp     al, COMMAND_WRITE_MULTIPLE
41    je      SHORT .PrepareToWriteDataFromESSI
42
43    ; Prepare to read data to ESSI
44    mov     bx, g_rgfnPioRead
45    mov     al, [bp+IDEPACK.bSectorCount]
46    call    InitializePiovarsInSSBPwithSectorCountInAX
47    xchg    si, di
48    call    Registers_NormalizeESDI
49    jmp     SHORT ReadFromDrive
50
51ALIGN JUMP_ALIGN
52.PrepareToWriteDataFromESSI:
53    mov     bx, g_rgfnPioWrite
54    mov     al, [bp+IDEPACK.bSectorCount]
55    call    InitializePiovarsInSSBPwithSectorCountInAX
56    call    Registers_NormalizeESSI
57    ; Fall to WriteToDrive
58
59
60;--------------------------------------------------------------------
61; WriteToDrive
62;   Parameters:
63;       DS:DI:  Ptr to DPT (in RAMVARS segment)
64;       ES:SI:  Normalized ptr to buffer containing data
65;       SS:BP:  Ptr to PIOVARS
66;   Returns:
67;       AH:     BIOS Error code
68;       CF:     0 if transfer succesfull
69;               1 if any error
70;   Corrupts registers:
71;       AL, BX, CX, DX, SI, ES
72;--------------------------------------------------------------------
73WriteToDrive:
74    ; Always poll when writing first block (IRQs are generated for following blocks)
75    mov     bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
76    call    IdeWait_PollStatusFlagInBLwithTimeoutInBH
77    jc      SHORT .ReturnWithTransferErrorInAH
78ALIGN JUMP_ALIGN
79.WriteNextBlock:
80    mov     dx, [bp+PIOVARS.wDataPort]
81    dec     WORD [bp+PIOVARS.wBlocksLeft]       ; Transferring last (possibly partial) block?
82    jz      SHORT .XferLastBlock                ;  If so, jump to transfer
83    mov     cx, [bp+PIOVARS.wBlockSize]         ; Load block size in WORDs
84    call    [bp+PIOVARS.fnXfer]                 ; Transfer full block
85
86    ; Normalize pointer when necessary
87    mov     ax, si
88    shr     ax, 1                               ; WORD offset
89    add     ax, [bp+PIOVARS.wBlockSize]
90    jns     SHORT .WaitUntilReadyToTransferNextBlock
91    call    Registers_NormalizeESSI
92
93ALIGN JUMP_ALIGN
94.WaitUntilReadyToTransferNextBlock:
95%ifdef USE_186
96    push    .WriteNextBlock
97    jmp     IdeWait_IRQorDRQ
98%else
99    call    IdeWait_IRQorDRQ
100    jnc     SHORT .WriteNextBlock
101%endif
102.ReturnWithTransferErrorInAH:
103    ret
104
105ALIGN JUMP_ALIGN
106.XferLastBlock:
107    xor     cx, cx
108    mov     bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRDY)
109    mov     ch, [bp+PIOVARS.bSectorsInLastBlock]; CX = Partial block size in WORDs
110%ifdef USE_186
111    push    IdeWait_IRQorStatusFlagInBLwithTimeoutInBH
112    jmp     [bp+PIOVARS.fnXfer]
113%else
114    call    [bp+PIOVARS.fnXfer]                 ; Transfer possibly partial block
115    jmp     IdeWait_IRQorStatusFlagInBLwithTimeoutInBH  ; Check for errors
116%endif
117
118
119;--------------------------------------------------------------------
120; ReadFromDrive
121;   Parameters:
122;       ES:DI:  Normalized ptr to buffer to recieve data
123;       DS:SI:  Ptr to DPT (in RAMVARS segment)
124;       SS:BP:  Ptr to PIOVARS
125;   Returns:
126;       DS:DI:  Ptr to DPT (in RAMVARS segment)
127;       AH:     BIOS Error code
128;       CF:     0 if transfer succesfull
129;               1 if any error
130;   Corrupts registers:
131;       AL, BX, CX, DX, SI, ES
132;--------------------------------------------------------------------
133ALIGN JUMP_ALIGN
134ReadFromDrive:
135    ; Wait until drive is ready to transfer
136    xchg    di, si                              ; DS:DI now points DPT
137    call    IdeWait_IRQorDRQ                    ; Wait until ready to transfer
138    jc      SHORT WriteToDrive.ReturnWithTransferErrorInAH
139    xchg    si, di                              ; ES:DI now points buffer
140
141    ; Transfer full or last (possible partial) block
142    mov     dx, [bp+PIOVARS.wDataPort]
143    dec     WORD [bp+PIOVARS.wBlocksLeft]
144    jz      SHORT .XferLastBlock
145    mov     cx, [bp+PIOVARS.wBlockSize]         ; Load block size in WORDs
146    call    [bp+PIOVARS.fnXfer]                 ; Transfer full block
147
148    ; Normalize pointer when necessary
149    mov     ax, di
150    shr     ax, 1                               ; WORD offset
151    add     ax, [bp+PIOVARS.wBlockSize]
152    jns     SHORT ReadFromDrive
153%ifdef USE_186
154    push    ReadFromDrive
155    jmp     Registers_NormalizeESDI
156%else
157    call    Registers_NormalizeESDI
158    jmp     SHORT ReadFromDrive                 ; Loop while blocks left
159%endif
160
161
162ALIGN JUMP_ALIGN
163.XferLastBlock:
164    xor     cx, cx
165    mov     ch, [bp+PIOVARS.bSectorsInLastBlock]; CX = Partial block size in WORDs
166    call    [bp+PIOVARS.fnXfer]                 ; Transfer possibly partial block
167    mov     di, si                              ; DS:DI now points DPT
168    mov     bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRDY)
169    jmp     IdeWait_PollStatusFlagInBLwithTimeoutInBH
170
171
172;--------------------------------------------------------------------
173; InitializePiovarsInSSBPwithSectorCountInAX
174;   Parameters:
175;       AX:     Number of sectors to transfer (1...65535)
176;       BX:     Offset to transfer function lookup table
177;       DS:DI:  Ptr to DPT (in RAMVARS segment)
178;       SS:BP:  Ptr to PIOVARS
179;   Returns:
180;       Nothing
181;   Corrupts registers:
182;       AX, BX, CX, DX
183;--------------------------------------------------------------------
184ALIGN JUMP_ALIGN
185InitializePiovarsInSSBPwithSectorCountInAX:
186    ; Store number of blocks to transfer
187    eMOVZX  cx, BYTE [di+DPT_ATA.bSetBlock]     ; Block size in sectors
188    xor     dx, dx      ; DX:AX = Sectors to transfer (1...65535)
189    div     cx          ; AX = Full blocks to transfer
190    test    dx, dx
191    mov     dh, cl      ; DH = Full block size if no partial blocks to transfer
192    jz      SHORT .NoPartialBlocksToTransfer
193    inc     ax          ; Partial block
194    mov     dh, dl      ; DH = Size of partial block in sectors
195.NoPartialBlocksToTransfer:
196    mov     [bp+PIOVARS.wBlocksLeft], ax
197    mov     [bp+PIOVARS.bSectorsInLastBlock], dh
198
199    ; Store block size in WORDs
200    xchg    ch, cl      ; CX = Block size in WORDs
201    mov     [bp+PIOVARS.wBlockSize], cx
202
203    ; Get transfer function based on bus type
204    xchg    ax, bx                              ; Lookup table offset to AX
205    eMOVZX  bx, BYTE [di+DPT.bIdevarsOffset]    ; CS:BX now points to IDEVARS
206    mov     dx, [cs:bx+IDEVARS.wPort]           ; Load IDE Data port address
207    mov     bl, [cs:bx+IDEVARS.bDevice]         ; Load device type to BX
208    add     bx, ax
209    mov     ax, [cs:bx]                         ; Load offset to transfer function
210    mov     [bp+PIOVARS.wDataPort], dx
211    mov     [bp+PIOVARS.fnXfer], ax
212    ret
213
214
215;--------------------------------------------------------------------
216; DualByteReadForXtide      Dual port 8-bit XTIDE PIO read transfer
217; SingleByteRead            Single port 8-bit PIO read transfer
218; WordReadForXTIDEmod       8088/8086 compatible 16-bit IDE PIO read transfer
219; WordReadForXTplusAndAT    Normal 16-bit IDE PIO read transfer
220; DWordRead                 VLB/PCI 32-bit IDE PIO read transfer
221;   Parameters:
222;       CX:     Block size in WORDs
223;       DX:     IDE Data port address
224;       ES:DI:  Normalized ptr to buffer to recieve data
225;   Returns:
226;       Nothing
227;   Corrupts registers:
228;       AX, BX, CX
229;--------------------------------------------------------------------
230ALIGN JUMP_ALIGN
231DualByteReadForXtide:
232    eSHR_IM cx, 2       ; Loop unrolling
233    mov     bx, 8       ; Bit mask for toggling data low/high reg
234ALIGN JUMP_ALIGN
235.InswLoop:
236    XTIDE_INSW
237    XTIDE_INSW
238    XTIDE_INSW
239    XTIDE_INSW
240    loop    .InswLoop
241    ret
242
243;----
244ALIGN JUMP_ALIGN
245SingleByteRead:
246%ifdef USE_186  ; INS instruction available
247    shl     cx, 1       ; WORD count to BYTE count
248    rep insb
249%else           ; If 8088/8086
250    shr     cx, 1       ; WORD count to DWORD count
251ALIGN JUMP_ALIGN
252.InsdLoop:
253    in      al, dx
254    stosb               ; Store to [ES:DI]
255    in      al, dx
256    stosb
257    in      al, dx
258    stosb
259    in      al, dx
260    stosb
261    loop    .InsdLoop
262%endif
263    ret
264
265;----
266%ifndef USE_186
267ALIGN JUMP_ALIGN
268WordReadForXTIDEmod:
269    times 2 shr cx, 1   ; WORD count to QWORD count
270ALIGN JUMP_ALIGN
271.ReadNextQword:
272    in      ax, dx      ; Read 1st WORD
273    stosw               ; Store 1st WORD to [ES:DI]
274    in      ax, dx
275    stosw               ; 2nd
276    in      ax, dx
277    stosw               ; 3rd
278    in      ax, dx
279    stosw               ; 4th
280    loop    .ReadNextQword
281    ret
282%endif
283
284;----
285ALIGN JUMP_ALIGN
286WordReadForXTplusAndAT:
287    rep
288    db      6Dh         ; INSW (we want this in XT build)
289    ret
290
291;----
292ALIGN JUMP_ALIGN
293DWordRead:
294    shr     cx, 1       ; WORD count to DWORD count
295    rep
296    db      66h         ; Override operand size to 32-bit
297    db      6Dh         ; INSW/INSD
298    ret
299
300
301;--------------------------------------------------------------------
302; DualByteWriteForXtide     Dual port 8-bit XTIDE PIO write transfer
303; SingleByteWrite           Single port 8-bit PIO write transfer
304; WordWriteForXTIDEmod      8088/8086 compatible 16-bit IDE PIO read transfer
305; WordWrite                 Normal 16-bit IDE PIO write transfer
306; DWordWrite                VLB/PCI 32-bit IDE PIO write transfer
307;   Parameters:
308;       CX:     Block size in WORDs
309;       DX:     IDE Data port address
310;       ES:SI:  Normalized ptr to buffer containing data
311;   Returns:
312;       Nothing
313;   Corrupts registers:
314;       AX, CX
315;--------------------------------------------------------------------
316ALIGN JUMP_ALIGN
317DualByteWriteForXtide:
318    push    ds
319    push    bx
320    eSHR_IM cx, 2       ; Loop unrolling
321    mov     bx, 8       ; Bit mask for toggling data low/high reg
322    push    es          ; Copy ES...
323    pop     ds          ; ...to DS
324ALIGN JUMP_ALIGN
325.OutswLoop:
326    XTIDE_OUTSW
327    XTIDE_OUTSW
328    XTIDE_OUTSW
329    XTIDE_OUTSW
330    loop    .OutswLoop
331    pop     bx
332    pop     ds
333    ret
334
335;----
336ALIGN JUMP_ALIGN
337SingleByteWrite:
338%ifdef USE_186  ; OUTS instruction available
339    shl     cx, 1       ; WORD count to BYTE count
340    eSEG    es          ; Source is ES segment
341    rep outsb
342%else           ; If 8088/8086
343    shr     cx, 1       ; WORD count to DWORD count
344    push    ds          ; Store DS
345    push    es          ; Copy ES...
346    pop     ds          ; ...to DS
347ALIGN JUMP_ALIGN
348.OutsdLoop:
349    lodsb               ; Load from [DS:SI] to AL
350    out     dx, al
351    lodsb
352    out     dx, al
353    lodsb
354    out     dx, al
355    lodsb
356    out     dx, al
357    loop    .OutsdLoop
358    pop     ds          ; Restore DS
359%endif
360    ret
361
362;---
363ALIGN JUMP_ALIGN
364WordWriteForXTIDEmod:
365    push    ds
366    eSHR_IM cx, 2       ; Loop unrolling
367    push    es          ; Copy ES...
368    pop     ds          ; ...to DS
369ALIGN JUMP_ALIGN
370.WriteNextQword:
371    XTIDE_MOD_OUTSW
372    XTIDE_MOD_OUTSW
373    XTIDE_MOD_OUTSW
374    XTIDE_MOD_OUTSW
375    loop    .WriteNextQword
376    pop     ds
377    ret
378
379;----
380ALIGN JUMP_ALIGN
381WordWrite:
382    eSEG    es          ; Source is ES segment
383    rep
384    db      6Fh         ; OUTSW (we want this in XT build)
385    ret
386
387ALIGN JUMP_ALIGN
388DWordWrite:
389    shr     cx, 1       ; WORD count to DWORD count
390    eSEG    es          ; Source is ES segment
391    rep
392    db      66h         ; Override operand size to 32-bit
393    db      6Fh         ; OUTSW/OUTSD
394    ret
395
396
397
398; Lookup tables to get transfer function based on bus type
399ALIGN WORD_ALIGN
400g_rgfnPioRead:
401    dw      DualByteReadForXtide    ; DEVICE_8BIT_DUAL_PORT_XTIDE
402%ifdef USE_186
403    dw      WordReadForXTplusAndAT  ; DEVICE_XTIDE_WITH_REVERSED_A3_AND_A0
404%else
405    dw      WordReadForXTIDEmod
406%endif
407    dw      SingleByteRead          ; DEVICE_8BIT_SINGLE_PORT
408    dw      WordReadForXTplusAndAT  ; DEVICE_16BIT_ATA
409    dw      DWordRead               ; DEVICE_32BIT_ATA
410
411g_rgfnPioWrite:
412    dw      DualByteWriteForXtide   ; DEVICE_8BIT_DUAL_PORT_XTIDE
413    dw      WordWriteForXTIDEmod    ; DEVICE_XTIDE_WITH_REVERSED_A3_AND_A0
414    dw      SingleByteWrite         ; DEVICE_8BIT_SINGLE_PORT
415    dw      WordWrite               ; DEVICE_16BIT_ATA
416    dw      DWordWrite              ; DEVICE_32BIT_ATA
Note: See TracBrowser for help on using the repository browser.