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

Last change on this file since 556 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
RevLine 
[480]1; Project name : XTIDE Universal BIOS
2; Description : IDE Read/Write functions for transferring
[551]3; block using DMA.
4; These functions should only be called from IdeTransfer.asm.
5; Modified JJP 05-Jun-13
[480]6;
7; XTIDE Universal BIOS and Associated Tools
[526]8; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
[480]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:
[491]75 ; 8-bit DMA transfers must be done within 64k physical page.
[486]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.
[480]78
[545]79 ; Load XT-CFv3 Control Register port to DX
[480]80 add dl, XTCF_CONTROL_REGISTER
81
[551]82 ; convert sectors in CX to BYTES
[480]83%ifdef USE_186
84 shl cx, 9 ; CX = Block size in BYTEs
85%else
[551]86 xchg cl, ch
[480]87 shl cx, 1
88%endif
[551]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
[545]100 cmp cx, ax ; if we won't cross a physical page boundary...
[551]101 jbe SHORT .TransferLastDmaPageWithSizeInCX ; ...perform the transfer in one operation
[480]102
[545]103 ; Calculate how much we can transfer on first and second rounds
[551]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
[480]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
[545]118; Updated for XT-CFv3, 11-Apr-13
[480]119; Parameters:
[482]120; BL: Byte for DMA Mode Register
[551]121; CX: Number of BYTEs to transfer (1...32768 since max block size is limited to 64)
[545]122; DX: XT-CFv3 Control Register
123; ES: Bits 3..0 have physical address bits 19..16
124; DI: Physical address bits 15..0
[480]125; Returns:
[545]126; ES:DI updated (CX is added)
[480]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
[545]135 cli ; Disable interrupts - programming must be atomic
136 out MASK_REGISTER_DMA8_out, al ; Disable DMA Channel 3
[480]137
138 ; Set DMA Mode (read or write using channel 3)
139 mov al, bl
140 out MODE_REGISTER_DMA8_out, al
141
[545]142 ; Send start address to DMA controller
[480]143 mov ax, es
144 out PAGE_DMA8_CH_3, al
145 mov ax, di
[545]146 out CLEAR_FLIPFLOP_DMA8_out, al ; Reset flip-flop to low byte
[480]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
[545]153 dec ax ; DMA controller is programmed for one byte less
[480]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
[545]160 out MASK_REGISTER_DMA8_out, al ; Enable DMA Channel 3
161 sti ; Enable interrupts
[480]162
[545]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).
[480]169
[545]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?
[486]179%endif ; Slow DMA code
[480]180
[545]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
[486]186.TransferNextDmaBlock:
[545]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
[486]189 inc cx ; set up CX, in case we need to do an extra iteration
[545]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
[486]194%endif ; Fast DMA code
195
[545]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
[486]202
[480]203 ret
Note: See TracBrowser for help on using the repository browser.