|
|
1.1 root 1: /*
2: * QEMU DMA emulation
3: *
4: * Copyright (c) 2003-2004 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 DEBUG_DMA */
27:
28: #define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
29: #ifdef DEBUG_DMA
30: #define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
31: #define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
32: #define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
33: #else
34: #define lwarn(...)
35: #define linfo(...)
36: #define ldebug(...)
37: #endif
38:
39: #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
40:
41: struct dma_regs {
42: int now[2];
43: uint16_t base[2];
44: uint8_t mode;
45: uint8_t page;
46: uint8_t pageh;
47: uint8_t dack;
48: uint8_t eop;
49: DMA_transfer_handler transfer_handler;
50: void *opaque;
51: };
52:
53: #define ADDR 0
54: #define COUNT 1
55:
56: static struct dma_cont {
57: uint8_t status;
58: uint8_t command;
59: uint8_t mask;
60: uint8_t flip_flop;
61: int dshift;
62: struct dma_regs regs[4];
63: } dma_controllers[2];
64:
65: enum {
66: CMD_MEMORY_TO_MEMORY = 0x01,
67: CMD_FIXED_ADDRESS = 0x02,
68: CMD_BLOCK_CONTROLLER = 0x04,
69: CMD_COMPRESSED_TIME = 0x08,
70: CMD_CYCLIC_PRIORITY = 0x10,
71: CMD_EXTENDED_WRITE = 0x20,
72: CMD_LOW_DREQ = 0x40,
73: CMD_LOW_DACK = 0x80,
74: CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
75: | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
76: | CMD_LOW_DREQ | CMD_LOW_DACK
77:
78: };
79:
80: static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
81:
82: static void write_page (void *opaque, uint32_t nport, uint32_t data)
83: {
84: struct dma_cont *d = opaque;
85: int ichan;
86:
87: ichan = channels[nport & 7];
88: if (-1 == ichan) {
89: dolog ("invalid channel %#x %#x\n", nport, data);
90: return;
91: }
92: d->regs[ichan].page = data;
93: }
94:
95: static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
96: {
97: struct dma_cont *d = opaque;
98: int ichan;
99:
100: ichan = channels[nport & 7];
101: if (-1 == ichan) {
102: dolog ("invalid channel %#x %#x\n", nport, data);
103: return;
104: }
105: d->regs[ichan].pageh = data;
106: }
107:
108: static uint32_t read_page (void *opaque, uint32_t nport)
109: {
110: struct dma_cont *d = opaque;
111: int ichan;
112:
113: ichan = channels[nport & 7];
114: if (-1 == ichan) {
115: dolog ("invalid channel read %#x\n", nport);
116: return 0;
117: }
118: return d->regs[ichan].page;
119: }
120:
121: static uint32_t read_pageh (void *opaque, uint32_t nport)
122: {
123: struct dma_cont *d = opaque;
124: int ichan;
125:
126: ichan = channels[nport & 7];
127: if (-1 == ichan) {
128: dolog ("invalid channel read %#x\n", nport);
129: return 0;
130: }
131: return d->regs[ichan].pageh;
132: }
133:
134: static inline void init_chan (struct dma_cont *d, int ichan)
135: {
136: struct dma_regs *r;
137:
138: r = d->regs + ichan;
139: r->now[ADDR] = r->base[ADDR] << d->dshift;
140: r->now[COUNT] = 0;
141: }
142:
143: static inline int getff (struct dma_cont *d)
144: {
145: int ff;
146:
147: ff = d->flip_flop;
148: d->flip_flop = !ff;
149: return ff;
150: }
151:
152: static uint32_t read_chan (void *opaque, uint32_t nport)
153: {
154: struct dma_cont *d = opaque;
155: int ichan, nreg, iport, ff, val, dir;
156: struct dma_regs *r;
157:
158: iport = (nport >> d->dshift) & 0x0f;
159: ichan = iport >> 1;
160: nreg = iport & 1;
161: r = d->regs + ichan;
162:
163: dir = ((r->mode >> 5) & 1) ? -1 : 1;
164: ff = getff (d);
165: if (nreg)
166: val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
167: else
168: val = r->now[ADDR] + r->now[COUNT] * dir;
169:
170: ldebug ("read_chan %#x -> %d\n", iport, val);
171: return (val >> (d->dshift + (ff << 3))) & 0xff;
172: }
173:
174: static void write_chan (void *opaque, uint32_t nport, uint32_t data)
175: {
176: struct dma_cont *d = opaque;
177: int iport, ichan, nreg;
178: struct dma_regs *r;
179:
180: iport = (nport >> d->dshift) & 0x0f;
181: ichan = iport >> 1;
182: nreg = iport & 1;
183: r = d->regs + ichan;
184: if (getff (d)) {
185: r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
186: init_chan (d, ichan);
187: } else {
188: r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
189: }
190: }
191:
192: static void write_cont (void *opaque, uint32_t nport, uint32_t data)
193: {
194: struct dma_cont *d = opaque;
195: int iport, ichan = 0;
196:
197: iport = (nport >> d->dshift) & 0x0f;
198: switch (iport) {
199: case 0x08: /* command */
200: if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
201: dolog ("command %#x not supported\n", data);
202: return;
203: }
204: d->command = data;
205: break;
206:
207: case 0x09:
208: ichan = data & 3;
209: if (data & 4) {
210: d->status |= 1 << (ichan + 4);
211: }
212: else {
213: d->status &= ~(1 << (ichan + 4));
214: }
215: d->status &= ~(1 << ichan);
216: break;
217:
218: case 0x0a: /* single mask */
219: if (data & 4)
220: d->mask |= 1 << (data & 3);
221: else
222: d->mask &= ~(1 << (data & 3));
223: break;
224:
225: case 0x0b: /* mode */
226: {
227: ichan = data & 3;
228: #ifdef DEBUG_DMA
229: {
230: int op, ai, dir, opmode;
231: op = (data >> 2) & 3;
232: ai = (data >> 4) & 1;
233: dir = (data >> 5) & 1;
234: opmode = (data >> 6) & 3;
235:
236: linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
237: ichan, op, ai, dir, opmode);
238: }
239: #endif
240: d->regs[ichan].mode = data;
241: break;
242: }
243:
244: case 0x0c: /* clear flip flop */
245: d->flip_flop = 0;
246: break;
247:
248: case 0x0d: /* reset */
249: d->flip_flop = 0;
250: d->mask = ~0;
251: d->status = 0;
252: d->command = 0;
253: break;
254:
255: case 0x0e: /* clear mask for all channels */
256: d->mask = 0;
257: break;
258:
259: case 0x0f: /* write mask for all channels */
260: d->mask = data;
261: break;
262:
263: default:
264: dolog ("unknown iport %#x\n", iport);
265: break;
266: }
267:
268: #ifdef DEBUG_DMA
269: if (0xc != iport) {
270: linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
271: nport, ichan, data);
272: }
273: #endif
274: }
275:
276: static uint32_t read_cont (void *opaque, uint32_t nport)
277: {
278: struct dma_cont *d = opaque;
279: int iport, val;
280:
281: iport = (nport >> d->dshift) & 0x0f;
282: switch (iport) {
283: case 0x08: /* status */
284: val = d->status;
285: d->status &= 0xf0;
286: break;
287: case 0x0f: /* mask */
288: val = d->mask;
289: break;
290: default:
291: val = 0;
292: break;
293: }
294:
295: ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
296: return val;
297: }
298:
299: int DMA_get_channel_mode (int nchan)
300: {
301: return dma_controllers[nchan > 3].regs[nchan & 3].mode;
302: }
303:
304: void DMA_hold_DREQ (int nchan)
305: {
306: int ncont, ichan;
307:
308: ncont = nchan > 3;
309: ichan = nchan & 3;
310: linfo ("held cont=%d chan=%d\n", ncont, ichan);
311: dma_controllers[ncont].status |= 1 << (ichan + 4);
312: }
313:
314: void DMA_release_DREQ (int nchan)
315: {
316: int ncont, ichan;
317:
318: ncont = nchan > 3;
319: ichan = nchan & 3;
320: linfo ("released cont=%d chan=%d\n", ncont, ichan);
321: dma_controllers[ncont].status &= ~(1 << (ichan + 4));
322: }
323:
324: static void channel_run (int ncont, int ichan)
325: {
326: int n;
327: struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
328: #ifdef DEBUG_DMA
329: int dir, opmode;
330:
331: dir = (r->mode >> 5) & 1;
332: opmode = (r->mode >> 6) & 3;
333:
334: if (dir) {
335: dolog ("DMA in address decrement mode\n");
336: }
337: if (opmode != 1) {
338: dolog ("DMA not in single mode select %#x\n", opmode);
339: }
340: #endif
341:
342: r = dma_controllers[ncont].regs + ichan;
343: n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
344: r->now[COUNT], (r->base[COUNT] + 1) << ncont);
345: r->now[COUNT] = n;
346: ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
347: }
348:
349: void DMA_run (void)
350: {
351: struct dma_cont *d;
352: int icont, ichan;
353:
354: d = dma_controllers;
355:
356: for (icont = 0; icont < 2; icont++, d++) {
357: for (ichan = 0; ichan < 4; ichan++) {
358: int mask;
359:
360: mask = 1 << ichan;
361:
362: if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
363: channel_run (icont, ichan);
364: }
365: }
366: }
367:
368: void DMA_register_channel (int nchan,
369: DMA_transfer_handler transfer_handler,
370: void *opaque)
371: {
372: struct dma_regs *r;
373: int ichan, ncont;
374:
375: ncont = nchan > 3;
376: ichan = nchan & 3;
377:
378: r = dma_controllers[ncont].regs + ichan;
379: r->transfer_handler = transfer_handler;
380: r->opaque = opaque;
381: }
382:
383: int DMA_read_memory (int nchan, void *buf, int pos, int len)
384: {
385: struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
386: target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
387:
388: if (r->mode & 0x20) {
389: int i;
390: uint8_t *p = buf;
391:
392: cpu_physical_memory_read (addr - pos - len, buf, len);
393: /* What about 16bit transfers? */
394: for (i = 0; i < len >> 1; i++) {
395: uint8_t b = p[len - i - 1];
396: p[i] = b;
397: }
398: }
399: else
400: cpu_physical_memory_read (addr + pos, buf, len);
401:
402: return len;
403: }
404:
405: int DMA_write_memory (int nchan, void *buf, int pos, int len)
406: {
407: struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
408: target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
409:
410: if (r->mode & 0x20) {
411: int i;
412: uint8_t *p = buf;
413:
414: cpu_physical_memory_write (addr - pos - len, buf, len);
415: /* What about 16bit transfers? */
416: for (i = 0; i < len; i++) {
417: uint8_t b = p[len - i - 1];
418: p[i] = b;
419: }
420: }
421: else
422: cpu_physical_memory_write (addr + pos, buf, len);
423:
424: return len;
425: }
426:
427: /* request the emulator to transfer a new DMA memory block ASAP */
428: void DMA_schedule(int nchan)
429: {
1.1.1.2 ! root 430: CPUState *env = cpu_single_env;
! 431: if (env)
! 432: cpu_interrupt(env, CPU_INTERRUPT_EXIT);
1.1 root 433: }
434:
435: static void dma_reset(void *opaque)
436: {
437: struct dma_cont *d = opaque;
438: write_cont (d, (0x0d << d->dshift), 0);
439: }
440:
441: /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
442: static void dma_init2(struct dma_cont *d, int base, int dshift,
443: int page_base, int pageh_base)
444: {
445: const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
446: int i;
447:
448: d->dshift = dshift;
449: for (i = 0; i < 8; i++) {
450: register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
451: register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
452: }
453: for (i = 0; i < LENOFA (page_port_list); i++) {
454: register_ioport_write (page_base + page_port_list[i], 1, 1,
455: write_page, d);
456: register_ioport_read (page_base + page_port_list[i], 1, 1,
457: read_page, d);
458: if (pageh_base >= 0) {
459: register_ioport_write (pageh_base + page_port_list[i], 1, 1,
460: write_pageh, d);
461: register_ioport_read (pageh_base + page_port_list[i], 1, 1,
462: read_pageh, d);
463: }
464: }
465: for (i = 0; i < 8; i++) {
466: register_ioport_write (base + ((i + 8) << dshift), 1, 1,
467: write_cont, d);
468: register_ioport_read (base + ((i + 8) << dshift), 1, 1,
469: read_cont, d);
470: }
471: qemu_register_reset(dma_reset, d);
472: dma_reset(d);
473: }
474:
475: static void dma_save (QEMUFile *f, void *opaque)
476: {
477: struct dma_cont *d = opaque;
478: int i;
479:
480: /* qemu_put_8s (f, &d->status); */
481: qemu_put_8s (f, &d->command);
482: qemu_put_8s (f, &d->mask);
483: qemu_put_8s (f, &d->flip_flop);
484: qemu_put_be32s (f, &d->dshift);
485:
486: for (i = 0; i < 4; ++i) {
487: struct dma_regs *r = &d->regs[i];
488: qemu_put_be32s (f, &r->now[0]);
489: qemu_put_be32s (f, &r->now[1]);
490: qemu_put_be16s (f, &r->base[0]);
491: qemu_put_be16s (f, &r->base[1]);
492: qemu_put_8s (f, &r->mode);
493: qemu_put_8s (f, &r->page);
494: qemu_put_8s (f, &r->pageh);
495: qemu_put_8s (f, &r->dack);
496: qemu_put_8s (f, &r->eop);
497: }
498: }
499:
500: static int dma_load (QEMUFile *f, void *opaque, int version_id)
501: {
502: struct dma_cont *d = opaque;
503: int i;
504:
505: if (version_id != 1)
506: return -EINVAL;
507:
508: /* qemu_get_8s (f, &d->status); */
509: qemu_get_8s (f, &d->command);
510: qemu_get_8s (f, &d->mask);
511: qemu_get_8s (f, &d->flip_flop);
512: qemu_get_be32s (f, &d->dshift);
513:
514: for (i = 0; i < 4; ++i) {
515: struct dma_regs *r = &d->regs[i];
516: qemu_get_be32s (f, &r->now[0]);
517: qemu_get_be32s (f, &r->now[1]);
518: qemu_get_be16s (f, &r->base[0]);
519: qemu_get_be16s (f, &r->base[1]);
520: qemu_get_8s (f, &r->mode);
521: qemu_get_8s (f, &r->page);
522: qemu_get_8s (f, &r->pageh);
523: qemu_get_8s (f, &r->dack);
524: qemu_get_8s (f, &r->eop);
525: }
526: return 0;
527: }
528:
529: void DMA_init (int high_page_enable)
530: {
531: dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
532: high_page_enable ? 0x480 : -1);
533: dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
534: high_page_enable ? 0x488 : -1);
535: register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
536: register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
537: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.