source: xtideuniversalbios/trunk/XTIDE_Universal_BIOS/Src/Device/IDE/IdeDmaBlock.asm @ 551

Last change on this file since 551 was 551, checked in by aitotat@…, 11 years ago

Changes to XTIDE Universal BIOS:

  • DMA fixes by James Pearce.
  • Interrupt handlers are now installed before starting to detect drives (HotkeyBar require INT 40h handler for correct drive letters).
File size: 8.0 KB
Line 
1; Project name  :   XTIDE Universal BIOS
2; Description   :   IDE Read/Write functions for transferring
3;           block using DMA.
4;           These functions should only be called from IdeTransfer.asm.
5; Modified JJP 05-Jun-13
6;
7; XTIDE Universal BIOS and Associated Tools
8; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
9;
10; This program is free software; you can redistribute it and/or modify
11; it under the terms of the GNU General Public License as published by
12; the Free Software Foundation; either version 2 of the License, or
13; (at your option) any later version.
14;
15; This program is distributed in the hope that it will be useful,
16; but WITHOUT ANY WARRANTY; without even the implied warranty of
17; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18; GNU General Public License for more details.
19; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20;
21
22; Section containing code
23SECTION .text
24
25;--------------------------------------------------------------------
26; IdeDmaBlock_WriteToXTCF
27;   Parameters:
28;       CX:     Block size in 512 byte sectors
29;       DX:     XTCF Base Port Address
30;       ES:SI:  Physical address to buffer to receive data
31;   Returns:
32;       Nothing
33;   Corrupts registers:
34;       AX, BX, CX, DX
35;--------------------------------------------------------------------
36ALIGN JUMP_ALIGN
37IdeDmaBlock_WriteToXTCF:
38    xchg    si, di
39    mov     bl, CHANNEL_3 | READ | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
40    call    TransferBlockToOrFromXTCF
41    xchg    di, si
42    ret
43
44
45;--------------------------------------------------------------------
46; IdeDmaBlock_ReadFromXTCF
47;   Parameters:
48;       CX:     Block size in 512 byte sectors
49;       DX:     XTCF Base Port Address
50;       ES:DI:  Physical address to buffer to receive data
51;   Returns:
52;       Nothing
53;   Corrupts registers:
54;       AX, BX, CX, DX
55;--------------------------------------------------------------------
56ALIGN JUMP_ALIGN
57IdeDmaBlock_ReadFromXTCF:
58    mov     bl, CHANNEL_3 | WRITE | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
59    ; Fall to TransferBlockToOrFromXTCF
60
61
62;--------------------------------------------------------------------
63; TransferBlockToOrFromXTCF
64;   Parameters:
65;       BL:     Mode byte for DMA Mode Register
66;       CX:     Block size in 512 byte sectors
67;       DX:     XTCF Base Port Address
68;       ES:DI:  Physical address to buffer to receive data
69;   Returns:
70;       Nothing
71;   Corrupts registers:
72;       AX, BX, CX, DX
73;--------------------------------------------------------------------
74TransferBlockToOrFromXTCF:
75    ; 8-bit DMA transfers must be done within 64k physical page.
76    ; XT-CF support maximum of 64 sector (32768 bytes) blocks in DMA mode
77    ; so we never need to separate transfer to more than 2 separate DMA operations.
78
79    ; Load XT-CFv3 Control Register port to DX
80    add     dl, XTCF_CONTROL_REGISTER
81
82    ; convert sectors in CX to BYTES
83%ifdef USE_186
84    shl     cx, 9                                   ; CX = Block size in BYTEs
85%else
86    xchg        cl, ch
87    shl     cx, 1
88%endif
89
90    ; Calculate bytes for first page
91    mov     ax, di
92    neg     ax          ; 2s compliment
93
94    ; if DI was zero carry flag will be cleared (and set otherwise)
95    ; When DI is zero only one transfer is required since we've limited the
96    ; XT-CFv3 block size to 32k
97    jnc .TransferLastDmaPageWithSizeInCX
98
99    ; CF was set, so DI != 0 and we might need one or two transfers
100    cmp     cx, ax                                  ; if we won't cross a physical page boundary...
101    jbe SHORT .TransferLastDmaPageWithSizeInCX  ; ...perform the transfer in one operation
102
103    ; Calculate how much we can transfer on first and second rounds
104    xchg        cx, ax          ; CX = BYTEs for first page
105    sub     ax, cx          ; AX = BYTEs for second page
106    push        ax          ; Save bytes for second transfer on stack
107
108    ; Transfer first DMA page
109    call    StartDMAtransferForXTCFwithDmaModeInBL
110    pop     cx                                      ; Pop size for second DMA page
111
112.TransferLastDmaPageWithSizeInCX:
113    ; Fall to StartDMAtransferForXTCFwithDmaModeInBL
114
115
116;--------------------------------------------------------------------
117; StartDMAtransferForXTCFwithDmaModeInBL
118; Updated for XT-CFv3, 11-Apr-13
119;   Parameters:
120;       BL:     Byte for DMA Mode Register
121;       CX:     Number of BYTEs to transfer (1...32768 since max block size is limited to 64)
122;       DX:     XT-CFv3 Control Register
123;       ES:     Bits 3..0 have physical address bits 19..16
124;       DI:     Physical address bits 15..0
125;   Returns:
126;       ES:DI updated (CX is added)
127;   Corrupts registers:
128;       AX
129;--------------------------------------------------------------------
130ALIGN JUMP_ALIGN
131StartDMAtransferForXTCFwithDmaModeInBL:
132    ; Program 8-bit DMA Controller
133    ; Disable Interrupts and DMA Channel 3 during DMA setup
134    mov     al, SET_CH3_MASK_BIT
135    cli                                 ; Disable interrupts - programming must be atomic
136    out     MASK_REGISTER_DMA8_out, al  ; Disable DMA Channel 3
137
138    ; Set DMA Mode (read or write using channel 3)
139    mov     al, bl
140    out     MODE_REGISTER_DMA8_out, al
141
142    ; Send start address to DMA controller
143    mov     ax, es
144    out     PAGE_DMA8_CH_3, al
145    mov     ax, di
146    out     CLEAR_FLIPFLOP_DMA8_out, al                         ; Reset flip-flop to low byte
147    out     BASE_AND_CURRENT_ADDRESS_REGISTER_DMA8_CH3_out, al  ; Low byte
148    mov     al, ah
149    out     BASE_AND_CURRENT_ADDRESS_REGISTER_DMA8_CH3_out, al  ; High byte
150
151    ; Set number of bytes to transfer (DMA controller must be programmed number of bytes - 1)
152    mov     ax, cx
153    dec     ax                                                  ; DMA controller is programmed for one byte less
154    out     BASE_AND_CURRENT_COUNT_REGISTER_DMA8_CH3_out, al    ; Low byte
155    mov     al, ah
156    out     BASE_AND_CURRENT_COUNT_REGISTER_DMA8_CH3_out, al    ; High byte
157
158    ; Enable DMA Channel 3
159    mov     al, CLEAR_CH3_MASK_BIT
160    out     MASK_REGISTER_DMA8_out, al                          ; Enable DMA Channel 3
161    sti                                                         ; Enable interrupts
162
163    ; XT-CF transfers 16 bytes at a time. We need to manually start transfer for every block by writing (anything)
164    ; to the XT-CFv3 Control Register, which raises DRQ thereby passing system control to the 8237 DMA controller.
165    ; The XT-CFv3 logic releases DRQ after 16 transfers, thereby handing control back to the CPU and allowing any other IRQs or
166    ; DRQs to be serviced (which, on the PC and PC/XT will include DRAM refresh via DMA channel 0).  The 16-byte transfers can
167    ; also be interrupted by the DMA controller raising TC (i.e. when done).  Each transfer cannot be otherwise interrupted
168    ; and is therefore atomic (and hence fast).
169
170%if 0   ; Slow DMA code - works by checking 8237 status register after each 16-byte transfer, until it reports TC has been raised.
171;ALIGN JUMP_ALIGN
172;.TransferNextBlock:
173;   cli                                 ; We want no ISR to read DMA Status Register before we do
174;   out     dx, al                      ; Transfer up to 16 bytes to/from XT-CF card
175;   in      al, STATUS_REGISTER_DMA8_in
176;   sti
177;   test    al, FLG_CH3_HAS_REACHED_TERMINAL_COUNT
178;   jz      SHORT .TransferNextBlock    ; All bytes transferred?
179%endif ; Slow DMA code
180
181%if 1   ; Fast DMA code - perform computed number of transfers, then check DMA status register to be sure
182    push    cx                          ; need byte count to update pointer at the end
183    add     cx, BYTE 15                 ; We'll divide transfers in 16-byte atomic transfers,
184    eSHR_IM cx, 4                       ; so include any partial block, which will be terminated
185ALIGN JUMP_ALIGN                        ; by the DMA controller raising T/C
186.TransferNextDmaBlock:
187    out     dx, al                      ; Transfer up to 16 bytes to/from XT-CF card
188    loop    .TransferNextDmaBlock       ; dec CX and loop if CX > 0, also adds required wait-state
189    inc     cx                          ; set up CX, in case we need to do an extra iteration
190    in      al, STATUS_REGISTER_DMA8_in ; check 8237 DMA controller status flags...
191    test    al, FLG_CH3_HAS_REACHED_TERMINAL_COUNT  ; ... for channel 3 terminal count
192    jz      SHORT .TransferNextDmaBlock ; If not set, get more bytes
193    pop     cx                          ; get back requested bytes
194%endif ; Fast DMA code
195
196    ; Update physical address in ES:DI - since IO might need several calls through this function either from here
197    ; if crossing a physical page boundary, and from IdeTransfer.asm if requested sectors was > PIOVARS.wSectorsInBlock
198    mov     ax, es                      ; copy physical page address to ax
199    add     di, cx                      ; add requested bytes to di
200    adc     al, 0                       ; and increment physical page address, if required
201    mov     es, ax                      ; and save it back in es
202
203    ret
Note: See TracBrowser for help on using the repository browser.