/[qemu]/qemu/hw/dma.c
ViewVC logotype

Diff of /qemu/hw/dma.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.11 by bellard, Mon Jun 21 16:47:42 2004 UTC revision 1.12 by bellard, Sun Nov 7 18:04:02 2004 UTC
# Line 1  Line 1 
1  /*  /*
2   * QEMU DMA emulation   * QEMU DMA emulation
3   *   *
4   * Copyright (c) 2003 Vassili Karpov (malc)   * Copyright (c) 2003-2004 Vassili Karpov (malc)
5   *   *
6   * Permission is hereby granted, free of charge, to any person obtaining a copy   * 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   * of this software and associated documentation files (the "Software"), to deal
8   * in the Software without restriction, including without limitation the rights   * in the Software without restriction, including without limitation the rights
# Line 23  Line 23 
23   */   */
24  #include "vl.h"  #include "vl.h"
25    
26  //#define DEBUG_DMA  /* #define DEBUG_DMA */
27    
28  #define log(...) fprintf (stderr, "dma: " __VA_ARGS__)  #define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
29  #ifdef DEBUG_DMA  #ifdef DEBUG_DMA
30  #define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)  #define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
31  #define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)  #define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
# Line 86  static void write_page (void *opaque, ui Line 86  static void write_page (void *opaque, ui
86    
87      ichan = channels[nport & 7];      ichan = channels[nport & 7];
88      if (-1 == ichan) {      if (-1 == ichan) {
89          log ("invalid channel %#x %#x\n", nport, data);          dolog ("invalid channel %#x %#x\n", nport, data);
90          return;          return;
91      }      }
92      d->regs[ichan].page = data;      d->regs[ichan].page = data;
# Line 99  static void write_pageh (void *opaque, u Line 99  static void write_pageh (void *opaque, u
99    
100      ichan = channels[nport & 7];      ichan = channels[nport & 7];
101      if (-1 == ichan) {      if (-1 == ichan) {
102          log ("invalid channel %#x %#x\n", nport, data);          dolog ("invalid channel %#x %#x\n", nport, data);
103          return;          return;
104      }      }
105      d->regs[ichan].pageh = data;      d->regs[ichan].pageh = data;
# Line 112  static uint32_t read_page (void *opaque, Line 112  static uint32_t read_page (void *opaque,
112    
113      ichan = channels[nport & 7];      ichan = channels[nport & 7];
114      if (-1 == ichan) {      if (-1 == ichan) {
115          log ("invalid channel read %#x\n", nport);          dolog ("invalid channel read %#x\n", nport);
116          return 0;          return 0;
117      }      }
118      return d->regs[ichan].page;      return d->regs[ichan].page;
# Line 125  static uint32_t read_pageh (void *opaque Line 125  static uint32_t read_pageh (void *opaque
125    
126      ichan = channels[nport & 7];      ichan = channels[nport & 7];
127      if (-1 == ichan) {      if (-1 == ichan) {
128          log ("invalid channel read %#x\n", nport);          dolog ("invalid channel read %#x\n", nport);
129          return 0;          return 0;
130      }      }
131      return d->regs[ichan].pageh;      return d->regs[ichan].pageh;
# Line 136  static inline void init_chan (struct dma Line 136  static inline void init_chan (struct dma
136      struct dma_regs *r;      struct dma_regs *r;
137    
138      r = d->regs + ichan;      r = d->regs + ichan;
139      r->now[ADDR] = r->base[0] << d->dshift;      r->now[ADDR] = r->base[ADDR] << d->dshift;
140      r->now[COUNT] = 0;      r->now[COUNT] = 0;
141  }  }
142    
# Line 152  static inline int getff (struct dma_cont Line 152  static inline int getff (struct dma_cont
152  static uint32_t read_chan (void *opaque, uint32_t nport)  static uint32_t read_chan (void *opaque, uint32_t nport)
153  {  {
154      struct dma_cont *d = opaque;      struct dma_cont *d = opaque;
155      int ichan, nreg, iport, ff, val;      int ichan, nreg, iport, ff, val, dir;
156      struct dma_regs *r;      struct dma_regs *r;
157    
158      iport = (nport >> d->dshift) & 0x0f;      iport = (nport >> d->dshift) & 0x0f;
# Line 160  static uint32_t read_chan (void *opaque, Line 160  static uint32_t read_chan (void *opaque,
160      nreg = iport & 1;      nreg = iport & 1;
161      r = d->regs + ichan;      r = d->regs + ichan;
162    
163        dir = ((r->mode >> 5) & 1) ? -1 : 1;
164      ff = getff (d);      ff = getff (d);
165      if (nreg)      if (nreg)
166          val = (r->base[COUNT] << d->dshift) - r->now[COUNT];          val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
167      else      else
168          val = r->now[ADDR] + r->now[COUNT];          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;      return (val >> (d->dshift + (ff << 3))) & 0xff;
172  }  }
173    
# Line 190  static void write_chan (void *opaque, ui Line 192  static void write_chan (void *opaque, ui
192  static void write_cont (void *opaque, uint32_t nport, uint32_t data)  static void write_cont (void *opaque, uint32_t nport, uint32_t data)
193  {  {
194      struct dma_cont *d = opaque;      struct dma_cont *d = opaque;
195      int iport, ichan;      int iport, ichan = 0;
196    
197      iport = (nport >> d->dshift) & 0x0f;      iport = (nport >> d->dshift) & 0x0f;
198      switch (iport) {      switch (iport) {
199      case 8:                     /* command */      case 0x08:                  /* command */
200          if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {          if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
201              log ("command %#x not supported\n", data);              dolog ("command %#x not supported\n", data);
202              return;              return;
203          }          }
204          d->command = data;          d->command = data;
205          break;          break;
206    
207      case 9:      case 0x09:
208          ichan = data & 3;          ichan = data & 3;
209          if (data & 4) {          if (data & 4) {
210              d->status |= 1 << (ichan + 4);              d->status |= 1 << (ichan + 4);
# Line 213  static void write_cont (void *opaque, ui Line 215  static void write_cont (void *opaque, ui
215          d->status &= ~(1 << ichan);          d->status &= ~(1 << ichan);
216          break;          break;
217    
218      case 0xa:                   /* single mask */      case 0x0a:                  /* single mask */
219          if (data & 4)          if (data & 4)
220              d->mask |= 1 << (data & 3);              d->mask |= 1 << (data & 3);
221          else          else
222              d->mask &= ~(1 << (data & 3));              d->mask &= ~(1 << (data & 3));
223          break;          break;
224    
225      case 0xb:                   /* mode */      case 0x0b:                  /* mode */
226          {          {
227              ichan = data & 3;              ichan = data & 3;
228  #ifdef DEBUG_DMA  #ifdef DEBUG_DMA
229              int op;              {
230              int ai;                  int op, ai, dir, opmode;
             int dir;  
             int opmode;  
   
231              op = (data >> 2) & 3;              op = (data >> 2) & 3;
232              ai = (data >> 4) & 1;              ai = (data >> 4) & 1;
233              dir = (data >> 5) & 1;              dir = (data >> 5) & 1;
# Line 236  static void write_cont (void *opaque, ui Line 235  static void write_cont (void *opaque, ui
235    
236              linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",              linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
237                     ichan, op, ai, dir, opmode);                     ichan, op, ai, dir, opmode);
238                }
239  #endif  #endif
   
240              d->regs[ichan].mode = data;              d->regs[ichan].mode = data;
241              break;              break;
242          }          }
243    
244      case 0xc:                   /* clear flip flop */      case 0x0c:                  /* clear flip flop */
245          d->flip_flop = 0;          d->flip_flop = 0;
246          break;          break;
247    
248      case 0xd:                   /* reset */      case 0x0d:                  /* reset */
249          d->flip_flop = 0;          d->flip_flop = 0;
250          d->mask = ~0;          d->mask = ~0;
251          d->status = 0;          d->status = 0;
252          d->command = 0;          d->command = 0;
253          break;          break;
254    
255      case 0xe:                   /* clear mask for all channels */      case 0x0e:                  /* clear mask for all channels */
256          d->mask = 0;          d->mask = 0;
257          break;          break;
258    
259      case 0xf:                   /* write mask for all channels */      case 0x0f:                  /* write mask for all channels */
260          d->mask = data;          d->mask = data;
261          break;          break;
262    
263      default:      default:
264          log ("dma: unknown iport %#x\n", iport);          dolog ("unknown iport %#x\n", iport);
265          break;          break;
266      }      }
267    
268  #ifdef DEBUG_DMA  #ifdef DEBUG_DMA
269      if (0xc != iport) {      if (0xc != iport) {
270          linfo ("nport %#06x, ichan % 2d, val %#06x\n",          linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
271                 nport, ichan, data);                 nport, ichan, data);
272      }      }
273  #endif  #endif
# Line 278  static uint32_t read_cont (void *opaque, Line 277  static uint32_t read_cont (void *opaque,
277  {  {
278      struct dma_cont *d = opaque;      struct dma_cont *d = opaque;
279      int iport, val;      int iport, val;
280        
281      iport = (nport >> d->dshift) & 0x0f;      iport = (nport >> d->dshift) & 0x0f;
282      switch (iport) {      switch (iport) {
283      case 0x08: /* status */      case 0x08:                  /* status */
284          val = d->status;          val = d->status;
285          d->status &= 0xf0;          d->status &= 0xf0;
286          break;          break;
287      case 0x0f: /* mask */      case 0x0f:                  /* mask */
288          val = d->mask;          val = d->mask;
289          break;          break;
290      default:      default:
291          val = 0;          val = 0;
292          break;          break;
293      }      }
294    
295        ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
296      return val;      return val;
297  }  }
298    
# Line 322  void DMA_release_DREQ (int nchan) Line 323  void DMA_release_DREQ (int nchan)
323    
324  static void channel_run (int ncont, int ichan)  static void channel_run (int ncont, int ichan)
325  {  {
     struct dma_regs *r;  
326      int n;      int n;
327      target_ulong addr;      struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
328  /*     int ai, dir; */  #ifdef DEBUG_DMA
329        int dir, opmode;
330    
331      r = dma_controllers[ncont].regs + ichan;      dir = (r->mode >> 5) & 1;
332  /*   ai = r->mode & 16; */      opmode = (r->mode >> 6) & 3;
 /*   dir = r->mode & 32 ? -1 : 1; */  
333    
334      /* NOTE: pageh is only used by PPC PREP */      if (dir) {
335      addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];          dolog ("DMA in address decrement mode\n");
336      n = r->transfer_handler (r->opaque, addr,      }
337                               (r->base[COUNT] << ncont) + (1 << ncont));      if (opmode != 1) {
338      r->now[COUNT] = n;          dolog ("DMA not in single mode select %#x\n", opmode);
339        }
340    #endif
341    
342      ldebug ("dma_pos %d size %d\n",      r = dma_controllers[ncont].regs + ichan;
343              n, (r->base[1] << ncont) + (1 << ncont));      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)  void DMA_run (void)
# Line 361  void DMA_run (void) Line 366  void DMA_run (void)
366  }  }
367    
368  void DMA_register_channel (int nchan,  void DMA_register_channel (int nchan,
369                             DMA_transfer_handler transfer_handler,                             DMA_transfer_handler transfer_handler,
370                             void *opaque)                             void *opaque)
371  {  {
372      struct dma_regs *r;      struct dma_regs *r;
# Line 375  void DMA_register_channel (int nchan, Line 380  void DMA_register_channel (int nchan,
380      r->opaque = opaque;      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 */  /* request the emulator to transfer a new DMA memory block ASAP */
428  void DMA_schedule(int nchan)  void DMA_schedule(int nchan)
429  {  {
# Line 388  static void dma_reset(void *opaque) Line 437  static void dma_reset(void *opaque)
437  }  }
438    
439  /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */  /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
440  static void dma_init2(struct dma_cont *d, int base, int dshift,  static void dma_init2(struct dma_cont *d, int base, int dshift,
441                        int page_base, int pageh_base)                        int page_base, int pageh_base)
442  {  {
443      const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };      const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
# Line 400  static void dma_init2(struct dma_cont *d Line 449  static void dma_init2(struct dma_cont *d
449          register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);          register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
450      }      }
451      for (i = 0; i < LENOFA (page_port_list); i++) {      for (i = 0; i < LENOFA (page_port_list); i++) {
452          register_ioport_write (page_base + page_port_list[i], 1, 1,          register_ioport_write (page_base + page_port_list[i], 1, 1,
453                                 write_page, d);                                 write_page, d);
454          register_ioport_read (page_base + page_port_list[i], 1, 1,          register_ioport_read (page_base + page_port_list[i], 1, 1,
455                                read_page, d);                                read_page, d);
456          if (pageh_base >= 0) {          if (pageh_base >= 0) {
457              register_ioport_write (pageh_base + page_port_list[i], 1, 1,              register_ioport_write (pageh_base + page_port_list[i], 1, 1,
458                                     write_pageh, d);                                     write_pageh, d);
459              register_ioport_read (pageh_base + page_port_list[i], 1, 1,              register_ioport_read (pageh_base + page_port_list[i], 1, 1,
460                                    read_pageh, d);                                    read_pageh, d);
461          }          }
462      }      }
463      for (i = 0; i < 8; i++) {      for (i = 0; i < 8; i++) {
464          register_ioport_write (base + ((i + 8) << dshift), 1, 1,          register_ioport_write (base + ((i + 8) << dshift), 1, 1,
465                                 write_cont, d);                                 write_cont, d);
466          register_ioport_read (base + ((i + 8) << dshift), 1, 1,          register_ioport_read (base + ((i + 8) << dshift), 1, 1,
467                                read_cont, d);                                read_cont, d);
468      }      }
469      qemu_register_reset(dma_reset, d);      qemu_register_reset(dma_reset, d);
470      dma_reset(d);      dma_reset(d);
471  }  }
472    
473    static void dma_save (QEMUFile *f, void *opaque)
474    {
475        struct dma_cont *d = opaque;
476        int i;
477    
478        /* qemu_put_8s (f, &d->status); */
479        qemu_put_8s (f, &d->command);
480        qemu_put_8s (f, &d->mask);
481        qemu_put_8s (f, &d->flip_flop);
482        qemu_put_be32s (f, &d->dshift);
483    
484        for (i = 0; i < 4; ++i) {
485            struct dma_regs *r = &d->regs[i];
486            qemu_put_be32s (f, &r->now[0]);
487            qemu_put_be32s (f, &r->now[1]);
488            qemu_put_be16s (f, &r->base[0]);
489            qemu_put_be16s (f, &r->base[1]);
490            qemu_put_8s (f, &r->mode);
491            qemu_put_8s (f, &r->page);
492            qemu_put_8s (f, &r->pageh);
493            qemu_put_8s (f, &r->dack);
494            qemu_put_8s (f, &r->eop);
495        }
496    }
497    
498    static int dma_load (QEMUFile *f, void *opaque, int version_id)
499    {
500        struct dma_cont *d = opaque;
501        int i;
502    
503        if (version_id != 1)
504            return -EINVAL;
505    
506        /* qemu_get_8s (f, &d->status); */
507        qemu_get_8s (f, &d->command);
508        qemu_get_8s (f, &d->mask);
509        qemu_get_8s (f, &d->flip_flop);
510        qemu_get_be32s (f, &d->dshift);
511    
512        for (i = 0; i < 4; ++i) {
513            struct dma_regs *r = &d->regs[i];
514            qemu_get_be32s (f, &r->now[0]);
515            qemu_get_be32s (f, &r->now[1]);
516            qemu_get_be16s (f, &r->base[0]);
517            qemu_get_be16s (f, &r->base[1]);
518            qemu_get_8s (f, &r->mode);
519            qemu_get_8s (f, &r->page);
520            qemu_get_8s (f, &r->pageh);
521            qemu_get_8s (f, &r->dack);
522            qemu_get_8s (f, &r->eop);
523        }
524        return 0;
525    }
526    
527  void DMA_init (int high_page_enable)  void DMA_init (int high_page_enable)
528  {  {
529      dma_init2(&dma_controllers[0], 0x00, 0, 0x80,      dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
530                high_page_enable ? 0x480 : -1);                high_page_enable ? 0x480 : -1);
531      dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,      dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
532                high_page_enable ? 0x488 : -1);                high_page_enable ? 0x488 : -1);
533        register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
534        register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
535  }  }

Legend:
Removed from v.1.11  
changed lines
  Added in v.1.12

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26