win32 port (initial patch by kazu)
[qemu] / hw / dma.c
1 /*
2  * QEMU DMA emulation
3  * 
4  * Copyright (c) 2003 Vassili Karpov (malc)
5  * 
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "vl.h"
25
26 #define log(...) fprintf (stderr, "dma: " __VA_ARGS__)
27 #ifdef DEBUG_DMA
28 #define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
29 #define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
30 #define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
31 #else
32 #define lwarn(...)
33 #define linfo(...)
34 #define ldebug(...)
35 #endif
36
37 #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
38
39 struct dma_regs {
40     int now[2];
41     uint16_t base[2];
42     uint8_t mode;
43     uint8_t page;
44     uint8_t dack;
45     uint8_t eop;
46     DMA_transfer_handler transfer_handler;
47     void *opaque;
48 };
49
50 #define ADDR 0
51 #define COUNT 1
52
53 static struct dma_cont {
54     uint8_t status;
55     uint8_t command;
56     uint8_t mask;
57     uint8_t flip_flop;
58     struct dma_regs regs[4];
59 } dma_controllers[2];
60
61 enum {
62   CMD_MEMORY_TO_MEMORY = 0x01,
63   CMD_FIXED_ADDRESS    = 0x02,
64   CMD_BLOCK_CONTROLLER = 0x04,
65   CMD_COMPRESSED_TIME  = 0x08,
66   CMD_CYCLIC_PRIORITY  = 0x10,
67   CMD_EXTENDED_WRITE   = 0x20,
68   CMD_LOW_DREQ         = 0x40,
69   CMD_LOW_DACK         = 0x80,
70   CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
71   | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
72   | CMD_LOW_DREQ | CMD_LOW_DACK
73
74 };
75
76 static void write_page (void *opaque, uint32_t nport, uint32_t data)
77 {
78     int ichan;
79     int ncont;
80     static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
81
82     ncont = nport > 0x87;
83     ichan = channels[nport - 0x80 - (ncont << 3)];
84
85     if (-1 == ichan) {
86         log ("invalid channel %#x %#x\n", nport, data);
87         return;
88     }
89
90     dma_controllers[ncont].regs[ichan].page = data;
91 }
92
93 static void init_chan (int ncont, int ichan)
94 {
95     struct dma_regs *r;
96
97     r = dma_controllers[ncont].regs + ichan;
98     r->now[ADDR] = r->base[0] << ncont;
99     r->now[COUNT] = 0;
100 }
101
102 static inline int getff (int ncont)
103 {
104     int ff;
105
106     ff = dma_controllers[ncont].flip_flop;
107     dma_controllers[ncont].flip_flop = !ff;
108     return ff;
109 }
110
111 static uint32_t read_chan (void *opaque, uint32_t nport)
112 {
113     int ff;
114     int ncont, ichan, nreg;
115     struct dma_regs *r;
116     int val;
117
118     ncont = nport > 7;
119     ichan = (nport >> (1 + ncont)) & 3;
120     nreg = (nport >> ncont) & 1;
121     r = dma_controllers[ncont].regs + ichan;
122
123     ff = getff (ncont);
124
125     if (nreg)
126         val = (r->base[COUNT] << ncont) - r->now[COUNT];
127     else
128         val = r->now[ADDR] + r->now[COUNT];
129
130     return (val >> (ncont + (ff << 3))) & 0xff;
131 }
132
133 static void write_chan (void *opaque, uint32_t nport, uint32_t data)
134 {
135     int ncont, ichan, nreg;
136     struct dma_regs *r;
137
138     ncont = nport > 7;
139     ichan = (nport >> (1 + ncont)) & 3;
140     nreg = (nport >> ncont) & 1;
141     r = dma_controllers[ncont].regs + ichan;
142
143     if (getff (ncont)) {
144         r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
145         init_chan (ncont, ichan);
146     } else {
147         r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
148     }
149 }
150
151 static void write_cont (void *opaque, uint32_t nport, uint32_t data)
152 {
153     int iport, ichan, ncont;
154     struct dma_cont *d;
155
156     ncont = nport > 0xf;
157     ichan = -1;
158
159     d = dma_controllers + ncont;
160     if (ncont) {
161         iport = ((nport - 0xd0) >> 1) + 8;
162     }
163     else {
164         iport = nport;
165     }
166
167     switch (iport) {
168     case 8:                     /* command */
169         if (data && (data | CMD_NOT_SUPPORTED)) {
170             log ("command %#x not supported\n", data);
171             goto error;
172         }
173         d->command = data;
174         break;
175
176     case 9:
177         ichan = data & 3;
178         if (data & 4) {
179             d->status |= 1 << (ichan + 4);
180         }
181         else {
182             d->status &= ~(1 << (ichan + 4));
183         }
184         d->status &= ~(1 << ichan);
185         break;
186
187     case 0xa:                   /* single mask */
188         if (data & 4)
189             d->mask |= 1 << (data & 3);
190         else
191             d->mask &= ~(1 << (data & 3));
192         break;
193
194     case 0xb:                   /* mode */
195         {
196             ichan = data & 3;
197 #ifdef DEBUG_DMA
198             int op;
199             int ai;
200             int dir;
201             int opmode;
202
203             op = (data >> 2) & 3;
204             ai = (data >> 4) & 1;
205             dir = (data >> 5) & 1;
206             opmode = (data >> 6) & 3;
207
208             linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
209                    ichan, op, ai, dir, opmode);
210 #endif
211
212             d->regs[ichan].mode = data;
213             break;
214         }
215
216     case 0xc:                   /* clear flip flop */
217         d->flip_flop = 0;
218         break;
219
220     case 0xd:                   /* reset */
221         d->flip_flop = 0;
222         d->mask = ~0;
223         d->status = 0;
224         d->command = 0;
225         break;
226
227     case 0xe:                   /* clear mask for all channels */
228         d->mask = 0;
229         break;
230
231     case 0xf:                   /* write mask for all channels */
232         d->mask = data;
233         break;
234
235     default:
236         log ("dma: unknown iport %#x\n", iport);
237         goto error;
238     }
239
240 #ifdef DEBUG_DMA
241     if (0xc != iport) {
242         linfo ("nport %#06x, ncont %d, ichan % 2d, val %#06x\n",
243                nport, d != dma_controllers, ichan, data);
244     }
245 #endif
246     return;
247
248  error:
249     abort ();
250 }
251
252 int DMA_get_channel_mode (int nchan)
253 {
254     return dma_controllers[nchan > 3].regs[nchan & 3].mode;
255 }
256
257 void DMA_hold_DREQ (int nchan)
258 {
259     int ncont, ichan;
260
261     ncont = nchan > 3;
262     ichan = nchan & 3;
263     linfo ("held cont=%d chan=%d\n", ncont, ichan);
264     dma_controllers[ncont].status |= 1 << (ichan + 4);
265 }
266
267 void DMA_release_DREQ (int nchan)
268 {
269     int ncont, ichan;
270
271     ncont = nchan > 3;
272     ichan = nchan & 3;
273     linfo ("released cont=%d chan=%d\n", ncont, ichan);
274     dma_controllers[ncont].status &= ~(1 << (ichan + 4));
275 }
276
277 static void channel_run (int ncont, int ichan)
278 {
279     struct dma_regs *r;
280     int n;
281     target_ulong addr;
282 /*     int ai, dir; */
283
284     r = dma_controllers[ncont].regs + ichan;
285 /*   ai = r->mode & 16; */
286 /*   dir = r->mode & 32 ? -1 : 1; */
287
288     addr = (r->page << 16) | r->now[ADDR];
289     n = r->transfer_handler (r->opaque, addr, 
290                              (r->base[COUNT] << ncont) + (1 << ncont));
291     r->now[COUNT] = n;
292
293     ldebug ("dma_pos %d size %d\n",
294             n, (r->base[1] << ncont) + (1 << ncont));
295 }
296
297 void DMA_run (void)
298 {
299     struct dma_cont *d;
300     int icont, ichan;
301
302     d = dma_controllers;
303
304     for (icont = 0; icont < 2; icont++, d++) {
305         for (ichan = 0; ichan < 4; ichan++) {
306             int mask;
307
308             mask = 1 << ichan;
309
310             if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
311                 channel_run (icont, ichan);
312         }
313     }
314 }
315
316 void DMA_register_channel (int nchan,
317                            DMA_transfer_handler transfer_handler, 
318                            void *opaque)
319 {
320     struct dma_regs *r;
321     int ichan, ncont;
322
323     ncont = nchan > 3;
324     ichan = nchan & 3;
325
326     r = dma_controllers[ncont].regs + ichan;
327     r->transfer_handler = transfer_handler;
328     r->opaque = opaque;
329 }
330
331 /* request the emulator to transfer a new DMA memory block ASAP */
332 void DMA_schedule(int nchan)
333 {
334     cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
335 }
336
337 void DMA_init (void)
338 {
339     int i;
340     int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
341
342     for (i = 0; i < 8; i++) {
343         register_ioport_write (i, 1, 1, write_chan, NULL);
344
345         register_ioport_write (0xc0 + (i << 1), 1, 1, write_chan, NULL);
346
347         register_ioport_read (i, 1, 1, read_chan, NULL);
348         register_ioport_read (0xc0 + (i << 1), 1, 1, read_chan, NULL);
349     }
350
351     for (i = 0; i < LENOFA (page_port_list); i++) {
352         register_ioport_write (page_port_list[i] + 0x80, 1, 1, write_page, NULL);
353         register_ioport_write (page_port_list[i] + 0x88, 1, 1, write_page, NULL);
354     }
355
356     for (i = 0; i < 8; i++) {
357         register_ioport_write (i + 8, 1, 1, write_cont, NULL);
358         register_ioport_write (0xd0 + (i << 1), 1, 1, write_cont, NULL);
359     }
360
361     write_cont (NULL, 0x0d, 0);
362     write_cont (NULL, 0xda, 0);
363 }