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

Last change on this file since 602 was 602, checked in by krille_n_, 5 years ago

Changes:

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