Statistics
| Branch: | Revision:

root / hw / dma.c @ 3504fe17

History | View | Annotate | Download (9.1 kB)

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 <stdio.h>
25
#include <stdlib.h>
26
#include <inttypes.h>
27

    
28
#include "cpu.h"
29
#include "vl.h"
30

    
31
#define log(...) fprintf (stderr, "dma: " __VA_ARGS__)
32
#ifdef DEBUG_DMA
33
#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
34
#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
35
#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
36
#else
37
#define lwarn(...)
38
#define linfo(...)
39
#define ldebug(...)
40
#endif
41

    
42
#define MEM_REAL(addr) ((addr)+(uint32_t)(phys_ram_base))
43
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
44

    
45
struct dma_regs {
46
    int now[2];
47
    uint16_t base[2];
48
    uint8_t mode;
49
    uint8_t page;
50
    uint8_t dack;
51
    uint8_t eop;
52
    DMA_read_handler read_handler;
53
    DMA_misc_handler misc_handler;
54
};
55

    
56
#define ADDR 0
57
#define COUNT 1
58

    
59
static struct dma_cont {
60
    uint8_t status;
61
    uint8_t command;
62
    uint8_t mask;
63
    uint8_t flip_flop;
64
    struct dma_regs regs[4];
65
} dma_controllers[2];
66

    
67
enum {
68
  CMD_MEMORY_TO_MEMORY = 0x01,
69
  CMD_FIXED_ADDRESS    = 0x02,
70
  CMD_BLOCK_CONTROLLER = 0x04,
71
  CMD_COMPRESSED_TIME  = 0x08,
72
  CMD_CYCLIC_PRIORITY  = 0x10,
73
  CMD_EXTENDED_WRITE   = 0x20,
74
  CMD_LOW_DREQ         = 0x40,
75
  CMD_LOW_DACK         = 0x80,
76
  CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
77
  | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
78
  | CMD_LOW_DREQ | CMD_LOW_DACK
79

    
80
};
81

    
82
static void write_page (CPUState *env, uint32_t nport, uint32_t data)
83
{
84
    int ichan;
85
    int ncont;
86
    static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
87

    
88
    ncont = nport > 0x87;
89
    ichan = channels[nport - 0x80 - (ncont << 3)];
90

    
91
    if (-1 == ichan) {
92
        log ("invalid channel %#x %#x\n", nport, data);
93
        return;
94
    }
95

    
96
    dma_controllers[ncont].regs[ichan].page = data;
97
}
98

    
99
static void init_chan (int ncont, int ichan)
100
{
101
    struct dma_regs *r;
102

    
103
    r = dma_controllers[ncont].regs + ichan;
104
    r->now[ADDR] = r->base[0] << ncont;
105
    r->now[COUNT] = 0;
106
}
107

    
108
static inline int getff (int ncont)
109
{
110
    int ff;
111

    
112
    ff = dma_controllers[ncont].flip_flop;
113
    dma_controllers[ncont].flip_flop = !ff;
114
    return ff;
115
}
116

    
117
static uint32_t read_chan (CPUState *env, uint32_t nport)
118
{
119
    int ff;
120
    int ncont, ichan, nreg;
121
    struct dma_regs *r;
122
    int val;
123

    
124
    ncont = nport > 7;
125
    ichan = (nport >> (1 + ncont)) & 3;
126
    nreg = (nport >> ncont) & 1;
127
    r = dma_controllers[ncont].regs + ichan;
128

    
129
    ff = getff (ncont);
130

    
131
    if (nreg)
132
        val = (r->base[COUNT] << ncont) - r->now[COUNT];
133
    else
134
        val = r->now[ADDR] + r->now[COUNT];
135

    
136
    return (val >> (ncont + (ff << 3))) & 0xff;
137
}
138

    
139
static void write_chan (CPUState *env, uint32_t nport, uint32_t data)
140
{
141
    int ncont, ichan, nreg;
142
    struct dma_regs *r;
143

    
144
    ncont = nport > 7;
145
    ichan = (nport >> (1 + ncont)) & 3;
146
    nreg = (nport >> ncont) & 1;
147
    r = dma_controllers[ncont].regs + ichan;
148

    
149
    if (getff (ncont)) {
150
        r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
151
        init_chan (ncont, ichan);
152
    } else {
153
        r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
154
    }
155
}
156

    
157
static void write_cont (CPUState *env, uint32_t nport, uint32_t data)
158
{
159
    int iport, ichan, ncont;
160
    struct dma_cont *d;
161

    
162
    ncont = nport > 0xf;
163
    ichan = -1;
164

    
165
    d = dma_controllers + ncont;
166
    if (ncont) {
167
        iport = ((nport - 0xd0) >> 1) + 8;
168
    }
169
    else {
170
        iport = nport;
171
    }
172

    
173
    switch (iport) {
174
    case 8:                     /* command */
175
        if (data && (data | CMD_NOT_SUPPORTED)) {
176
            log ("command %#x not supported\n", data);
177
            goto error;
178
        }
179
        d->command = data;
180
        break;
181

    
182
    case 9:
183
        ichan = data & 3;
184
        if (data & 4) {
185
            d->status |= 1 << (ichan + 4);
186
        }
187
        else {
188
            d->status &= ~(1 << (ichan + 4));
189
        }
190
        d->status &= ~(1 << ichan);
191
        break;
192

    
193
    case 0xa:                   /* single mask */
194
        if (data & 4)
195
            d->mask |= 1 << (data & 3);
196
        else
197
            d->mask &= ~(1 << (data & 3));
198
        break;
199

    
200
    case 0xb:                   /* mode */
201
        {
202
            ichan = data & 3;
203
#ifdef DEBUG_DMA
204
            int op;
205
            int ai;
206
            int dir;
207
            int opmode;
208

    
209
            op = (data >> 2) & 3;
210
            ai = (data >> 4) & 1;
211
            dir = (data >> 5) & 1;
212
            opmode = (data >> 6) & 3;
213

    
214
            linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
215
                   ichan, op, ai, dir, opmode);
216
#endif
217

    
218
            d->regs[ichan].mode = data;
219
            break;
220
        }
221

    
222
    case 0xc:                   /* clear flip flop */
223
        d->flip_flop = 0;
224
        break;
225

    
226
    case 0xd:                   /* reset */
227
        d->flip_flop = 0;
228
        d->mask = ~0;
229
        d->status = 0;
230
        d->command = 0;
231
        break;
232

    
233
    case 0xe:                   /* clear mask for all channels */
234
        d->mask = 0;
235
        break;
236

    
237
    case 0xf:                   /* write mask for all channels */
238
        d->mask = data;
239
        break;
240

    
241
    default:
242
        log ("dma: unknown iport %#x\n", iport);
243
        goto error;
244
    }
245

    
246
#ifdef DEBUG_DMA
247
    if (0xc != iport) {
248
        linfo ("nport %#06x, ncont %d, ichan % 2d, val %#06x\n",
249
               nport, d != dma_controllers, ichan, data);
250
    }
251
#endif
252
    return;
253

    
254
 error:
255
    abort ();
256
}
257

    
258
int DMA_get_channel_mode (int nchan)
259
{
260
    return dma_controllers[nchan > 3].regs[nchan & 3].mode;
261
}
262

    
263
void DMA_hold_DREQ (int nchan)
264
{
265
    int ncont, ichan;
266

    
267
    ncont = nchan > 3;
268
    ichan = nchan & 3;
269
    linfo ("held cont=%d chan=%d\n", ncont, ichan);
270
    dma_controllers[ncont].status |= 1 << (ichan + 4);
271
}
272

    
273
void DMA_release_DREQ (int nchan)
274
{
275
    int ncont, ichan;
276

    
277
    ncont = nchan > 3;
278
    ichan = nchan & 3;
279
    linfo ("released cont=%d chan=%d\n", ncont, ichan);
280
    dma_controllers[ncont].status &= ~(1 << (ichan + 4));
281
}
282

    
283
static void channel_run (int ncont, int ichan)
284
{
285
    struct dma_regs *r;
286
    int n;
287
    int irq;
288
    uint32_t addr;
289
/*     int ai, dir; */
290

    
291
    r = dma_controllers[ncont].regs + ichan;
292
/*   ai = r->mode & 16; */
293
/*   dir = r->mode & 32 ? -1 : 1; */
294

    
295
    addr = MEM_REAL ((r->page << 16) | r->now[ADDR]);
296

    
297
    irq = -1;
298
    n = r->read_handler (addr, (r->base[COUNT] << ncont) + (1 << ncont), &irq);
299
    r->now[COUNT] = n;
300

    
301
    ldebug ("dma_pos %d irq %d size %d\n",
302
            n, irq, (r->base[1] << ncont) + (1 << ncont));
303

    
304
    if (-1 != irq) {
305
        pic_set_irq (irq, 1);
306
    }
307
}
308

    
309
void DMA_run (void)
310
{
311
    static int in_dma;
312
    struct dma_cont *d;
313
    int icont, ichan;
314

    
315
    if (in_dma) {
316
        log ("attempt to re-enter dma\n");
317
        return;
318
    }
319

    
320
    in_dma = 1;
321
    d = dma_controllers;
322

    
323
    for (icont = 0; icont < 2; icont++, d++) {
324
        for (ichan = 0; ichan < 4; ichan++) {
325
            int mask;
326

    
327
            mask = 1 << ichan;
328

    
329
            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
330
                channel_run (icont, ichan);
331
        }
332
    }
333
    in_dma = 0;
334
}
335

    
336
void DMA_register_channel (int nchan,
337
                           DMA_read_handler read_handler,
338
                           DMA_misc_handler misc_handler)
339
{
340
    struct dma_regs *r;
341
    int ichan, ncont;
342

    
343
    ncont = nchan > 3;
344
    ichan = nchan & 3;
345

    
346
    r = dma_controllers[ncont].regs + ichan;
347
    r->read_handler = read_handler;
348
    r->misc_handler = misc_handler;
349
}
350

    
351
void DMA_init (void)
352
{
353
    int i;
354
    int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
355

    
356
    for (i = 0; i < 8; i++) {
357
        register_ioport_write (i, 1, write_chan, 1);
358

    
359
        register_ioport_write (0xc0 + (i << 1), 1, write_chan, 1);
360

    
361
        register_ioport_read (i, 1, read_chan, 1);
362
        register_ioport_read (0xc0 + (i << 1), 1, read_chan, 1);
363
    }
364

    
365
    for (i = 0; i < LENOFA (page_port_list); i++) {
366
        register_ioport_write (page_port_list[i] + 0x80, 1, write_page, 1);
367
        register_ioport_write (page_port_list[i] + 0x88, 1, write_page, 1);
368
    }
369

    
370
    for (i = 0; i < 8; i++) {
371
        register_ioport_write (i + 8, 1, write_cont, 1);
372
        register_ioport_write (0xd0 + (i << 1), 1, write_cont, 1);
373
    }
374

    
375
    write_cont (NULL, 0x0d, 0);
376
    write_cont (NULL, 0xda, 0);
377
}