PCem

view src/dma.c @ 152:f6069ee5e9d7

Fixed terminal count on auto-init DMA. Fixed sound on All New World of Lemmings when using GUS.
author TomW
date Sun Aug 24 14:08:17 2014 +0100
parents 4bde4cf3074b
children
line source
1 #include "ibm.h"
3 #include "dma.h"
4 #include "fdc.h"
5 #include "io.h"
6 #include "mem.h"
7 #include "video.h"
9 static uint8_t dmaregs[16];
10 static int dmaon[4];
11 static uint8_t dma16regs[16];
12 static int dma16on[4];
13 static uint8_t dmapages[16];
15 void dma_reset()
16 {
17 int c;
18 dma.wp = 0;
19 for (c = 0; c < 16; c++)
20 dmaregs[c] = 0;
21 for (c = 0; c < 4; c++)
22 {
23 dma.mode[c] = 0;
24 dma.ac[c] = 0;
25 dma.cc[c] = 0;
26 dma.ab[c] = 0;
27 dma.cb[c] = 0;
28 }
29 dma.m = 0;
31 dma16.wp = 0;
32 for (c = 0; c < 16; c++)
33 dma16regs[c] = 0;
34 for (c = 0; c < 4; c++)
35 {
36 dma16.mode[c] = 0;
37 dma16.ac[c] = 0;
38 dma16.cc[c] = 0;
39 dma16.ab[c] = 0;
40 dma16.cb[c] = 0;
41 }
42 dma16.m = 0;
43 }
45 uint8_t dma_read(uint16_t addr, void *priv)
46 {
47 uint8_t temp;
48 // printf("Read DMA %04X %04X:%04X %i %02X\n",addr,CS,pc, pic_intpending, pic.pend);
49 switch (addr & 0xf)
50 {
51 case 0: case 2: case 4: case 6: /*Address registers*/
52 dma.wp ^= 1;
53 if (dma.wp)
54 return dma.ac[(addr >> 1) & 3] & 0xff;
55 return dma.ac[(addr >> 1) & 3] >> 8;
57 case 1: case 3: case 5: case 7: /*Count registers*/
58 dma.wp ^= 1;
59 if (dma.wp) temp = dma.cc[(addr >> 1) & 3] & 0xff;
60 else temp = dma.cc[(addr >> 1) & 3] >> 8;
61 return temp;
63 case 8: /*Status register*/
64 temp = dma.stat;
65 dma.stat = 0;
66 return temp;
68 case 0xd:
69 return 0;
70 }
71 // printf("Bad DMA read %04X %04X:%04X\n",addr,CS,pc);
72 return dmaregs[addr & 0xf];
73 }
75 void dma_write(uint16_t addr, uint8_t val, void *priv)
76 {
77 // printf("Write DMA %04X %02X %04X:%04X\n",addr,val,CS,pc);
78 dmaregs[addr & 0xf] = val;
79 switch (addr & 0xf)
80 {
81 case 0: case 2: case 4: case 6: /*Address registers*/
82 dma.wp ^= 1;
83 if (dma.wp) dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xff00) | val;
84 else dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8);
85 dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3];
86 dmaon[(addr >> 1) & 3] = 1;
87 return;
89 case 1: case 3: case 5: case 7: /*Count registers*/
90 dma.wp ^= 1;
91 if (dma.wp) dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0xff00) | val;
92 else dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8);
93 dma.cc[(addr >> 1) & 3] = dma.cb[(addr >> 1) & 3];
94 dmaon[(addr >> 1) & 3] = 1;
95 return;
97 case 8: /*Control register*/
98 dma.command = val;
99 return;
101 case 0xa: /*Mask*/
102 if (val & 4) dma.m |= (1 << (val & 3));
103 else dma.m &= ~(1 << (val & 3));
104 return;
106 case 0xb: /*Mode*/
107 dma.mode[val & 3] = val;
108 return;
110 case 0xc: /*Clear FF*/
111 dma.wp = 0;
112 return;
114 case 0xd: /*Master clear*/
115 dma.wp = 0;
116 dma.m = 0xf;
117 return;
119 case 0xf: /*Mask write*/
120 dma.m = val & 0xf;
121 return;
122 }
123 }
125 uint8_t dma16_read(uint16_t addr, void *priv)
126 {
127 uint8_t temp;
128 // printf("Read DMA %04X %04X:%04X\n",addr,cs>>4,pc);
129 addr >>= 1;
130 switch (addr & 0xf)
131 {
132 case 0: case 2: case 4: case 6: /*Address registers*/
133 dma16.wp ^= 1;
134 if (dma16.wp)
135 return dma16.ac[(addr >> 1) & 3] & 0xff;
136 return dma16.ac[(addr >> 1) & 3] >> 8;
138 case 1: case 3: case 5: case 7: /*Count registers*/
139 dma16.wp ^= 1;
140 if (dma16.wp) temp = dma16.cc[(addr >> 1) & 3] & 0xff;
141 else temp = dma16.cc[(addr >> 1) & 3] >> 8;
142 return temp;
144 case 8: /*Status register*/
145 temp = dma16.stat;
146 dma16.stat = 0;
147 return temp;
148 }
149 return dma16regs[addr & 0xf];
150 }
152 void dma16_write(uint16_t addr, uint8_t val, void *priv)
153 {
154 // printf("Write dma16 %04X %02X %04X:%04X\n",addr,val,CS,pc);
155 addr >>= 1;
156 dma16regs[addr & 0xf] = val;
157 switch (addr & 0xf)
158 {
159 case 0: case 2: case 4: case 6: /*Address registers*/
160 dma16.wp ^= 1;
161 if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xff00) | val;
162 else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8);
163 dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3];
164 dma16on[(addr >> 1) & 3] = 1;
165 return;
167 case 1: case 3: case 5: case 7: /*Count registers*/
168 dma16.wp ^= 1;
169 if (dma16.wp) dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0xff00) | val;
170 else dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8);
171 dma16.cc[(addr >> 1) & 3] = dma16.cb[(addr >> 1) & 3];
172 dma16on[(addr >> 1) & 3] = 1;
173 return;
175 case 8: /*Control register*/
176 return;
178 case 0xa: /*Mask*/
179 if (val & 4) dma16.m |= (1 << (val & 3));
180 else dma16.m &= ~(1 << (val & 3));
181 return;
183 case 0xb: /*Mode*/
184 dma16.mode[val & 3] = val;
185 return;
187 case 0xc: /*Clear FF*/
188 dma16.wp = 0;
189 return;
191 case 0xd: /*Master clear*/
192 dma16.wp = 0;
193 dma16.m = 0xf;
194 return;
196 case 0xf: /*Mask write*/
197 dma16.m = val&0xf;
198 return;
199 }
200 }
203 void dma_page_write(uint16_t addr, uint8_t val, void *priv)
204 {
205 dmapages[addr & 0xf] = val;
206 switch (addr & 0xf)
207 {
208 case 1:
209 dma.page[2] = (AT) ? val : val & 0xf;
210 break;
211 case 2:
212 dma.page[3] = (AT) ? val : val & 0xf;
213 break;
214 case 3:
215 dma.page[1] = (AT) ? val : val & 0xf;
216 break;
217 case 0xb:
218 dma16.page[1] = val;
219 break;
220 }
221 }
223 uint8_t dma_page_read(uint16_t addr, void *priv)
224 {
225 return dmapages[addr & 0xf];
226 }
228 void dma_init()
229 {
230 io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL, NULL);
231 io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
232 }
234 void dma16_init()
235 {
236 io_sethandler(0x00C0, 0x0020, dma16_read, NULL, NULL, dma16_write, NULL, NULL, NULL);
237 io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL);
238 }
241 uint8_t _dma_read(uint32_t addr)
242 {
243 return mem_readb_phys(addr);
244 }
246 void _dma_write(uint32_t addr, uint8_t val)
247 {
248 mem_writeb_phys(addr, val);
249 }
251 int dma_channel_read(int channel)
252 {
253 uint16_t temp;
254 int tc = 0;
256 if (dma.command & 0x04)
257 return DMA_NODATA;
259 if (!AT)
260 refreshread();
262 if (channel < 4)
263 {
264 if (dma.m & (1 << channel))
265 return DMA_NODATA;
266 if ((dma.mode[channel] & 0xC) != 8)
267 return DMA_NODATA;
269 temp = _dma_read(dma.ac[channel] + (dma.page[channel] << 16)); //ram[(dma.ac[2]+(dma.page[2]<<16))&rammask];
271 if (dma.mode[channel] & 0x20) dma.ac[channel]--;
272 else dma.ac[channel]++;
273 dma.cc[channel]--;
274 if (dma.cc[channel] < 0)
275 {
276 tc = 1;
277 if (dma.mode[channel] & 0x10) /*Auto-init*/
278 {
279 dma.cc[channel] = dma.cb[channel];
280 dma.ac[channel] = dma.ab[channel];
281 }
282 else
283 dma.m |= (1 << channel);
284 dma.stat |= (1 << channel);
285 }
287 if (tc)
288 return temp | DMA_OVER;
289 return temp;
290 }
291 else
292 {
293 channel &= 3;
294 if (dma16.m & (1 << channel))
295 return DMA_NODATA;
296 if ((dma16.mode[channel] & 0xC) != 8)
297 return DMA_NODATA;
299 temp = _dma_read((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16)) |
300 (_dma_read((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16) + 1) << 8);
302 if (dma16.mode[channel] & 0x20) dma16.ac[channel]--;
303 else dma16.ac[channel]++;
304 dma16.cc[channel]--;
305 if (dma16.cc[channel] < 0)
306 {
307 tc = 1;
308 if (dma16.mode[channel] & 0x10) /*Auto-init*/
309 {
310 dma16.cc[channel] = dma16.cb[channel];
311 dma16.ac[channel] = dma16.ab[channel];
312 }
313 else
314 dma16.m |= (1 << channel);
315 dma16.stat |= (1 << channel);
316 }
318 if (tc)
319 return temp | DMA_OVER;
320 return temp;
321 }
322 }
324 int dma_channel_write(int channel, uint16_t val)
325 {
326 if (dma.command & 0x04)
327 return DMA_NODATA;
329 if (!AT)
330 refreshread();
332 if (channel < 4)
333 {
334 if (dma.m & (1 << channel))
335 return DMA_NODATA;
336 if ((dma.mode[channel] & 0xC) != 4)
337 return DMA_NODATA;
339 _dma_write(dma.ac[channel] + (dma.page[channel] << 16), val);
341 if (dma.mode[channel]&0x20) dma.ac[channel]--;
342 else dma.ac[channel]++;
343 dma.cc[channel]--;
344 if (dma.cc[channel] < 0)
345 {
346 if (dma.mode[channel] & 0x10) /*Auto-init*/
347 {
348 dma.cc[channel] = dma.cb[channel];
349 dma.ac[channel] = dma.ab[channel];
350 }
351 else
352 dma.m |= (1 << channel);
353 dma.stat |= (1 << channel);
354 }
356 if (dma.m & (1 << channel))
357 return DMA_OVER;
358 }
359 else
360 {
361 channel &= 3;
362 if (dma16.m & (1 << channel))
363 return DMA_NODATA;
364 if ((dma16.mode[channel] & 0xC) != 4)
365 return DMA_NODATA;
367 _dma_write((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16), val);
368 _dma_write((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16) + 1, val >> 8);
370 if (dma16.mode[channel]&0x20) dma16.ac[channel]--;
371 else dma16.ac[channel]++;
372 dma16.cc[channel]--;
373 if (dma16.cc[channel] < 0)
374 {
375 if (dma16.mode[channel] & 0x10) /*Auto-init*/
376 {
377 dma16.cc[channel] = dma16.cb[channel] + 1;
378 dma16.ac[channel] = dma16.ab[channel];
379 }
380 dma16.m |= (1 << channel);
381 dma16.stat |= (1 << channel);
382 }
384 if (dma.m & (1 << channel))
385 return DMA_OVER;
386 }
387 return 0;
388 }