[NTVDM]
[reactos.git] / reactos / subsystems / mvdm / ntvdm / hardware / dma.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: dma.c
5 * PURPOSE: Direct Memory Access Controller emulation -
6 * i8237A compatible with 74LS612 Memory Mapper extension
7 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #define NDEBUG
13
14 #include "ntvdm.h"
15 #include "emulator.h"
16 #include "dma.h"
17
18 #include "io.h"
19
20 /* PRIVATE VARIABLES **********************************************************/
21
22 /*
23 * DMA Controller 0 (Channels 0..3): Slave controller
24 * DMA Controller 1 (Channels 4..7): Master controller
25 */
26 static DMA_CONTROLLER DmaControllers[DMA_CONTROLLERS];
27
28 /* External page registers for each channel of the two DMA controllers */
29 static DMA_PAGE_REGISTER DmaPageRegisters[DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS];
30
31 /* PRIVATE FUNCTIONS **********************************************************/
32
33 #define READ_ADDR(CtrlIndex, ChanIndex, Data) \
34 do { \
35 (Data) = \
36 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrAddress + \
37 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
38 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
39 } while(0)
40
41 #define READ_CNT(CtrlIndex, ChanIndex, Data) \
42 do { \
43 (Data) = \
44 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrWordCnt + \
45 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)); \
46 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
47 } while(0)
48
49 static BYTE WINAPI DmaReadPort(USHORT Port)
50 {
51 BYTE ReadValue = 0xFF;
52
53 switch (Port)
54 {
55 /* Start Address Registers */
56 {
57 case 0x00:
58 READ_ADDR(0, 0, ReadValue);
59 return ReadValue;
60 case 0x02:
61 READ_ADDR(0, 1, ReadValue);
62 return ReadValue;
63 case 0x04:
64 READ_ADDR(0, 2, ReadValue);
65 return ReadValue;
66 case 0x06:
67 READ_ADDR(0, 3, ReadValue);
68 return ReadValue;
69 case 0xC0:
70 READ_ADDR(1, 0, ReadValue);
71 return ReadValue;
72 case 0xC4:
73 READ_ADDR(1, 1, ReadValue);
74 return ReadValue;
75 case 0xC8:
76 READ_ADDR(1, 2, ReadValue);
77 return ReadValue;
78 case 0xCC:
79 READ_ADDR(1, 3, ReadValue);
80 return ReadValue;
81 }
82
83 /* Count Address Registers */
84 {
85 case 0x01:
86 READ_CNT(0, 0, ReadValue);
87 return ReadValue;
88 case 0x03:
89 READ_CNT(0, 1, ReadValue);
90 return ReadValue;
91 case 0x05:
92 READ_CNT(0, 2, ReadValue);
93 return ReadValue;
94 case 0x07:
95 READ_CNT(0, 3, ReadValue);
96 return ReadValue;
97 case 0xC2:
98 READ_CNT(1, 0, ReadValue);
99 return ReadValue;
100 case 0xC6:
101 READ_CNT(1, 1, ReadValue);
102 return ReadValue;
103 case 0xCA:
104 READ_CNT(1, 2, ReadValue);
105 return ReadValue;
106 case 0xCE:
107 READ_CNT(1, 3, ReadValue);
108 return ReadValue;
109 }
110
111 /* Status Registers */
112 {
113 case 0x08:
114 return DmaControllers[0].Status;
115 case 0xD0:
116 return DmaControllers[1].Status;
117 }
118
119 /* DMA Intermediate (Temporary) Registers */
120 {
121 case 0x0D:
122 return DmaControllers[0].TempReg;
123 case 0xDA:
124 return DmaControllers[1].TempReg;
125 }
126 }
127
128 return 0x00;
129 }
130
131 #define WRITE_ADDR(CtrlIndex, ChanIndex, Data) \
132 do { \
133 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].BaseAddress + \
134 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
135 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrAddress + \
136 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
137 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
138 } while(0)
139
140 #define WRITE_CNT(CtrlIndex, ChanIndex, Data) \
141 do { \
142 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].BaseWordCnt + \
143 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
144 *((PBYTE)&DmaControllers[(CtrlIndex)].DmaChannel[(ChanIndex)].CurrWordCnt + \
145 (DmaControllers[(CtrlIndex)].FlipFlop & 0x01)) = (Data); \
146 DmaControllers[(CtrlIndex)].FlipFlop ^= 1; \
147 } while(0)
148
149 static VOID WINAPI DmaWritePort(USHORT Port, BYTE Data)
150 {
151 switch (Port)
152 {
153 /* Start Address Registers */
154 {
155 case 0x00:
156 WRITE_ADDR(0, 0, Data);
157 break;
158 case 0x02:
159 WRITE_ADDR(0, 1, Data);
160 break;
161 case 0x04:
162 WRITE_ADDR(0, 2, Data);
163 break;
164 case 0x06:
165 WRITE_ADDR(0, 3, Data);
166 break;
167 case 0xC0:
168 WRITE_ADDR(1, 0, Data);
169 break;
170 case 0xC4:
171 WRITE_ADDR(1, 1, Data);
172 break;
173 case 0xC8:
174 WRITE_ADDR(1, 2, Data);
175 break;
176 case 0xCC:
177 WRITE_ADDR(1, 3, Data);
178 break;
179 }
180
181 /* Count Address Registers */
182 {
183 case 0x01:
184 WRITE_CNT(0, 0, Data);
185 break;
186 case 0x03:
187 WRITE_CNT(0, 1, Data);
188 break;
189 case 0x05:
190 WRITE_CNT(0, 2, Data);
191 break;
192 case 0x07:
193 WRITE_CNT(0, 3, Data);
194 break;
195 case 0xC2:
196 WRITE_CNT(1, 0, Data);
197 break;
198 case 0xC6:
199 WRITE_CNT(1, 1, Data);
200 break;
201 case 0xCA:
202 WRITE_CNT(1, 2, Data);
203 break;
204 case 0xCE:
205 WRITE_CNT(1, 3, Data);
206 break;
207 }
208
209 /* Command Registers */
210 {
211 case 0x08:
212 DmaControllers[0].Command = Data;
213 break;
214 case 0xD0:
215 DmaControllers[1].Command = Data;
216 break;
217 }
218
219 /* Request Registers */
220 {
221 case 0x09:
222 DmaControllers[0].Request = Data;
223 break;
224 case 0xD2:
225 DmaControllers[1].Request = Data;
226 break;
227 }
228
229 /* Flip-Flop Reset */
230 {
231 case 0x0C:
232 DmaControllers[0].FlipFlop = 0;
233 break;
234 case 0xD8:
235 DmaControllers[1].FlipFlop = 0;
236 break;
237 }
238
239 /* DMA Master Reset */
240 {
241 case 0x0D:
242 DmaControllers[0].Command = 0x00;
243 DmaControllers[0].Status = 0x00;
244 DmaControllers[0].Request = 0x00;
245 DmaControllers[0].TempReg = 0x00;
246 DmaControllers[0].FlipFlop = 0;
247 DmaControllers[0].Mask = 0x0F;
248 break;
249 case 0xDA:
250 DmaControllers[1].Command = 0x00;
251 DmaControllers[1].Status = 0x00;
252 DmaControllers[1].Request = 0x00;
253 DmaControllers[1].TempReg = 0x00;
254 DmaControllers[1].FlipFlop = 0;
255 DmaControllers[1].Mask = 0x0F;
256 break;
257 }
258 }
259 }
260
261 /* Page Address Registers */
262
263 static BYTE WINAPI DmaPageReadPort(USHORT Port)
264 {
265 switch (Port)
266 {
267 case 0x87:
268 return DmaPageRegisters[0].Page;
269 case 0x83:
270 return DmaPageRegisters[1].Page;
271 case 0x81:
272 return DmaPageRegisters[2].Page;
273 case 0x82:
274 return DmaPageRegisters[3].Page;
275 case 0x8F:
276 return DmaPageRegisters[4].Page;
277 case 0x8B:
278 return DmaPageRegisters[5].Page;
279 case 0x89:
280 return DmaPageRegisters[6].Page;
281 case 0x8A:
282 return DmaPageRegisters[7].Page;
283 }
284
285 return 0x00;
286 }
287
288 static VOID WINAPI DmaPageWritePort(USHORT Port, BYTE Data)
289 {
290 switch (Port)
291 {
292 case 0x87:
293 DmaPageRegisters[0].Page = Data;
294 break;
295 case 0x83:
296 DmaPageRegisters[1].Page = Data;
297 break;
298 case 0x81:
299 DmaPageRegisters[2].Page = Data;
300 break;
301 case 0x82:
302 DmaPageRegisters[3].Page = Data;
303 break;
304 case 0x8F:
305 DmaPageRegisters[4].Page = Data;
306 break;
307 case 0x8B:
308 DmaPageRegisters[5].Page = Data;
309 break;
310 case 0x89:
311 DmaPageRegisters[6].Page = Data;
312 break;
313 case 0x8A:
314 DmaPageRegisters[7].Page = Data;
315 break;
316 }
317 }
318
319 /* PUBLIC FUNCTIONS ***********************************************************/
320
321 VOID DmaInitialize(VOID)
322 {
323 /* Register the I/O Ports */
324
325 /* Channels 0(Reserved)..3 */
326 RegisterIoPort(0x00, NULL, DmaWritePort); /* Start Address Register 0 (Reserved) */
327 RegisterIoPort(0x01, NULL, DmaWritePort); /* Count Address Register 0 (Reserved) */
328 RegisterIoPort(0x02, NULL, DmaWritePort); /* Start Address Register 1 */
329 RegisterIoPort(0x03, NULL, DmaWritePort); /* Count Address Register 1 */
330 RegisterIoPort(0x04, NULL, DmaWritePort); /* Start Address Register 2 */
331 RegisterIoPort(0x05, NULL, DmaWritePort); /* Count Address Register 2 */
332 RegisterIoPort(0x06, NULL, DmaWritePort); /* Start Address Register 3 */
333 RegisterIoPort(0x07, NULL, DmaWritePort); /* Count Address Register 3 */
334
335 RegisterIoPort(0x08, DmaReadPort, DmaWritePort); /* Status (Read) / Command (Write) Registers */
336 RegisterIoPort(0x09, NULL, DmaWritePort); /* Request Register */
337 RegisterIoPort(0x0A, NULL, DmaWritePort); /* Single Channel Mask Register */
338 RegisterIoPort(0x0B, NULL, DmaWritePort); /* Mode Register */
339 RegisterIoPort(0x0C, NULL, DmaWritePort); /* Flip-Flop Reset Register */
340 RegisterIoPort(0x0D, DmaReadPort, DmaWritePort); /* Intermediate (Read) / Master Reset (Write) Registers */
341 RegisterIoPort(0x0E, NULL, DmaWritePort); /* Mask Reset Register */
342 RegisterIoPort(0x0F, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Reset Register */
343
344
345 /* Channels 4(Reserved)..7 */
346 RegisterIoPort(0xC0, NULL, DmaWritePort); /* Start Address Register 4 (Reserved) */
347 RegisterIoPort(0xC2, NULL, DmaWritePort); /* Count Address Register 4 (Reserved) */
348 RegisterIoPort(0xC4, NULL, DmaWritePort); /* Start Address Register 5 */
349 RegisterIoPort(0xC6, NULL, DmaWritePort); /* Count Address Register 5 */
350 RegisterIoPort(0xC8, NULL, DmaWritePort); /* Start Address Register 6 */
351 RegisterIoPort(0xCA, NULL, DmaWritePort); /* Count Address Register 6 */
352 RegisterIoPort(0xCC, NULL, DmaWritePort); /* Start Address Register 7 */
353 RegisterIoPort(0xCE, NULL, DmaWritePort); /* Count Address Register 7 */
354
355 RegisterIoPort(0xD0, DmaReadPort, DmaWritePort); /* Status (Read) / Command (Write) Registers */
356 RegisterIoPort(0xD2, NULL, DmaWritePort); /* Request Register */
357 RegisterIoPort(0xD4, NULL, DmaWritePort); /* Single Channel Mask Register */
358 RegisterIoPort(0xD6, NULL, DmaWritePort); /* Mode Register */
359 RegisterIoPort(0xD8, NULL, DmaWritePort); /* Flip-Flop Reset Register */
360 RegisterIoPort(0xDA, DmaReadPort, DmaWritePort); /* Intermediate (Read) / Master Reset (Write) Registers */
361 RegisterIoPort(0xDC, NULL, DmaWritePort); /* Mask Reset Register */
362 RegisterIoPort(0xDE, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Reset Register */
363
364
365 /* Channels Page Address Registers */
366 RegisterIoPort(0x87, DmaPageReadPort, DmaPageWritePort); /* Channel 0 (Reserved) */
367 RegisterIoPort(0x83, DmaPageReadPort, DmaPageWritePort); /* Channel 1 */
368 RegisterIoPort(0x81, DmaPageReadPort, DmaPageWritePort); /* Channel 2 */
369 RegisterIoPort(0x82, DmaPageReadPort, DmaPageWritePort); /* Channel 3 */
370 RegisterIoPort(0x8F, DmaPageReadPort, DmaPageWritePort); /* Channel 4 (Reserved) */
371 RegisterIoPort(0x8B, DmaPageReadPort, DmaPageWritePort); /* Channel 5 */
372 RegisterIoPort(0x89, DmaPageReadPort, DmaPageWritePort); /* Channel 6 */
373 RegisterIoPort(0x8A, DmaPageReadPort, DmaPageWritePort); /* Channel 7 */
374 }
375
376
377
378 DWORD
379 WINAPI
380 VDDRequestDMA(IN HANDLE hVdd,
381 IN WORD iChannel,
382 IN OUT PVOID Buffer,
383 IN DWORD length)
384 {
385 UNREFERENCED_PARAMETER(hVdd);
386
387 if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
388 {
389 SetLastError(ERROR_INVALID_ADDRESS);
390 return FALSE;
391 }
392
393 UNIMPLEMENTED;
394 return 0;
395 }
396
397 BOOL
398 WINAPI
399 VDDQueryDMA(IN HANDLE hVdd,
400 IN WORD iChannel,
401 IN PVDD_DMA_INFO pDmaInfo)
402 {
403 PDMA_CONTROLLER pDcp;
404 WORD Channel;
405
406 UNREFERENCED_PARAMETER(hVdd);
407
408 if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
409 {
410 SetLastError(ERROR_INVALID_ADDRESS);
411 return FALSE;
412 }
413
414 pDcp = &DmaControllers[iChannel / DMA_CONTROLLER_CHANNELS];
415 Channel = iChannel % DMA_CONTROLLER_CHANNELS;
416
417 pDmaInfo->addr = pDcp->DmaChannel[Channel].CurrAddress;
418 pDmaInfo->count = pDcp->DmaChannel[Channel].CurrWordCnt;
419
420 // pDmaInfo->page = DmaPageRegisters[iChannel].Page;
421 pDmaInfo->status = pDcp->Status;
422 pDmaInfo->mode = pDcp->DmaChannel[Channel].Mode;
423 pDmaInfo->mask = pDcp->Mask;
424
425 return TRUE;
426 }
427
428 BOOL
429 WINAPI
430 VDDSetDMA(IN HANDLE hVdd,
431 IN WORD iChannel,
432 IN WORD fDMA,
433 IN PVDD_DMA_INFO pDmaInfo)
434 {
435 PDMA_CONTROLLER pDcp;
436 WORD Channel;
437
438 UNREFERENCED_PARAMETER(hVdd);
439
440 if (iChannel >= DMA_CONTROLLERS * DMA_CONTROLLER_CHANNELS)
441 {
442 SetLastError(ERROR_INVALID_ADDRESS);
443 return FALSE;
444 }
445
446 pDcp = &DmaControllers[iChannel / DMA_CONTROLLER_CHANNELS];
447 Channel = iChannel % DMA_CONTROLLER_CHANNELS;
448
449 if (fDMA & VDD_DMA_ADDR)
450 pDcp->DmaChannel[Channel].CurrAddress = pDmaInfo->addr;
451
452 if (fDMA & VDD_DMA_COUNT)
453 pDcp->DmaChannel[Channel].CurrWordCnt = pDmaInfo->count;
454
455 // if (fDMA & VDD_DMA_PAGE)
456 // DmaPageRegisters[iChannel].Page = pDmaInfo->page;
457
458 if (fDMA & VDD_DMA_STATUS)
459 pDcp->Status = pDmaInfo->status;
460
461 return TRUE;
462 }
463
464 /* EOF */