"Fossies" - the Fresh Open Source Software Archive

Member "dosemu-1.4.0/src/base/dev/dma/dmanew.c" (29 Nov 2006, 14552 Bytes) of package /linux/misc/old/dosemu-1.4.0.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dmanew.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  *  Copyright (C) 2006 Stas Sergeev <stsp@users.sourceforge.net>
    3  *
    4  * The below copyright strings have to be distributed unchanged together
    5  * with this file. This prefix can not be modified or separated.
    6  */
    7 
    8 /*
    9  *  This program is free software; you can redistribute it and/or modify
   10  *  it under the terms of the GNU General Public License as published by
   11  *  the Free Software Foundation; either version 2 of the License, or
   12  *  (at your option) any later version.
   13  *
   14  *  This program is distributed in the hope that it will be useful,
   15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17  *  GNU General Public License for more details.
   18  *
   19  *  You should have received a copy of the GNU General Public License
   20  *  along with this program; if not, write to the Free Software
   21  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   22  */
   23 
   24 /*
   25  * DMA controller emulation.
   26  *
   27  * Author: Stas Sergeev <stsp@users.sourceforge.net>
   28  */
   29 
   30 #include "emu.h"
   31 #include "init.h"
   32 #include "utilities.h"
   33 #include "port.h"
   34 #include "timers.h"
   35 #include "dma.h"
   36 #include <string.h>
   37 
   38 typedef union {
   39     Bit8u byte[2];
   40     Bit16u value;
   41 } dma_reg16;
   42 
   43 struct dma_channel {
   44     dma_reg16 base_addr;
   45     dma_reg16 base_count;
   46     dma_reg16 cur_addr;
   47     dma_reg16 cur_count;
   48     Bit8u page;
   49     Bit8u mode;
   50 };
   51 
   52 struct dma_controller {
   53     struct dma_channel chans[4];
   54 #if 0
   55     /* looks like we don't need those */
   56     Bit16u tmp_addr;
   57     Bit16u tmp_count;
   58 #endif
   59     Bit8u tmp_reg;
   60     Bit8u status;
   61     Bit8u command;
   62     Bit8u mask;
   63     Bit8u request;
   64     Bit8u ff;
   65 } dma[2];
   66 
   67 static Bit8u dma_data_bus[2];
   68 
   69 #define DMA1  0
   70 #define DMA2  1
   71 
   72 /* need this as soon as dosemu is threaded */
   73 #define DMA_LOCK()
   74 #define DMA_UNLOCK()
   75 
   76 #define DI(c) (((c) & 4) >> 2)
   77 #define CI(c) ((c) & 3)
   78 
   79 #define HAVE_DRQ(contr, chan) (dma[contr].status & (1 << ((chan) + 4)))
   80 #define REACHED_TC(contr, chan) (dma[contr].status & (1 << (chan)))
   81 #define MASKED(contr, chan) (dma[contr].mask & (1 << (chan)))
   82 #define HAVE_SRQ(contr, chan) (dma[contr].request & (1 << (chan)))
   83 #define SW_ACTIVE(contr, chan) \
   84   (HAVE_SRQ(contr, chan) && \
   85   (dma[contr].chans[chan].mode & 0x30) == 0x20)
   86 
   87 
   88 static void dma_soft_reset(int dma_idx)
   89 {
   90     dma[dma_idx].command = 0;
   91     dma[dma_idx].status = 0;
   92     dma[dma_idx].request = 0;
   93     dma[dma_idx].tmp_reg = 0;
   94     dma[dma_idx].ff = 0;
   95     dma[dma_idx].mask = 0x0f;
   96     q_printf("DMA: Soft Reset on controller %i\n", dma_idx);
   97 }
   98 
   99 static void dma_poll_DRQ(int dma_idx, int chan_idx)
  100 {
  101     /* Since our model is simplified (API has only pulse_DRQ() instead
  102      * of assert_DRQ()/release_DRQ()), poll never sees the DRQ asserted. */
  103     dma[dma_idx].status &= ~(1 << (chan_idx + 4));
  104 }
  105 
  106 static void dma_update_DRQ(int dma_idx, int chan_idx)
  107 {
  108     switch (dma[dma_idx].chans[chan_idx].mode & 0x30) {
  109     case 0x00:          // demand
  110     dma_poll_DRQ(dma_idx, chan_idx);
  111     break;
  112     case 0x10:          // single
  113     dma[dma_idx].status &= ~(1 << (chan_idx + 4));
  114     break;
  115     case 0x20:          // block
  116     if (REACHED_TC(dma_idx, chan_idx))
  117         dma_poll_DRQ(dma_idx, chan_idx);
  118     break;
  119     case 0x30:          // cascade
  120     dma_poll_DRQ(dma_idx, chan_idx);
  121     break;
  122     }
  123 }
  124 
  125 static void dma_process_channel(int dma_idx, int chan_idx)
  126 {
  127     struct dma_channel *chan = &dma[dma_idx].chans[chan_idx];
  128     Bit32u addr = (chan->page << 16) | (chan->cur_addr.value << dma_idx);
  129     Bit8u mode = chan->mode;
  130 
  131     /* first, do the transfer */
  132     switch (mode & 3) {
  133     case 0:         /* verify */
  134     q_printf("DMA: verify mode does nothing\n");
  135     break;
  136     case 1:         /* write */
  137     MEMCPY_2DOS(addr, dma_data_bus, 1 << dma_idx);
  138     break;
  139     case 2:         /* read */
  140     MEMCPY_2UNIX(dma_data_bus, addr, 1 << dma_idx);
  141     break;
  142     case 3:         /* invalid */
  143     q_printf("DMA: invalid mode does nothing\n");
  144     break;
  145     }
  146 
  147     /* now advance the address */
  148     if (!(dma[dma_idx].command & 2))
  149     chan->cur_addr.value += (mode & 8) ? -1 : 1;
  150 
  151     /* and the counter */
  152     chan->cur_count.value--;
  153     if (chan->cur_count.value == 0xffff) {  /* overflow */
  154     if (mode & 4) {     /* auto-init */
  155         q_printf("DMA: controller %i, channel %i reinitialized\n",
  156              dma_idx, chan_idx);
  157         chan->cur_addr.value = chan->base_addr.value;
  158         chan->cur_count.value = chan->base_count.value;
  159     } else {        /* eop */
  160         q_printf("DMA: controller %i, channel %i EOP\n", dma_idx,
  161              chan_idx);
  162         dma[dma_idx].status |= 1 << chan_idx;
  163         dma[dma_idx].request &= ~(1 << chan_idx);
  164         /* the datasheet says it gets automatically masked too */
  165         dma[dma_idx].mask |= 1 << chan_idx;
  166     }
  167     }
  168 }
  169 
  170 static void dma_run_channel(int dma_idx, int chan_idx)
  171 {
  172     int done = 0;
  173     long ticks = 0;
  174     while (!done &&
  175        (HAVE_DRQ(dma_idx, chan_idx) || SW_ACTIVE(dma_idx, chan_idx))) {
  176     if (!MASKED(dma_idx, chan_idx) &&
  177         !REACHED_TC(dma_idx, chan_idx) &&
  178         !(dma[dma_idx].command & 4) &&
  179         ((dma[dma_idx].chans[chan_idx].mode & 0x30) != 0x30)) {
  180         dma_process_channel(dma_idx, chan_idx);
  181         ticks++;
  182     } else {
  183         done = 1;
  184     }
  185     dma_update_DRQ(dma_idx, chan_idx);
  186     }
  187     if (ticks > 1)
  188     q_printf("DMA: processed %lu (left %u) cycles on controller %i channel %i\n",
  189          ticks, dma[dma_idx].chans[chan_idx].cur_count.value, dma_idx,
  190          chan_idx);
  191 }
  192 
  193 static void dma_process(void)
  194 {
  195     int contr_num, chan_num;
  196 
  197     DMA_LOCK();
  198     for (contr_num = 0; contr_num < 2; contr_num++) {
  199     for (chan_num = 0; chan_num < 4; chan_num++)
  200         dma_run_channel(contr_num, chan_num);
  201     }
  202     DMA_UNLOCK();
  203 }
  204 
  205 int dma_pulse_DRQ(int ch, Bit8u * buf)
  206 {
  207     int ret = DMA_DACK;
  208     if (MASKED(DI(ch), CI(ch))) {
  209     q_printf("DMA: channel %i masked, DRQ ignored\n", ch);
  210     ret = DMA_NO_DACK;
  211     }
  212     if ((dma[DI(ch)].status & 0xf0) || dma[DI(ch)].request) {
  213     error("DMA: channel %i already active! (m=%#x s=%#x r=%#x)\n",
  214           dma[DI(ch)].chans[CI(ch)].mode, dma[DI(ch)].status,
  215           dma[DI(ch)].request);
  216     ret = DMA_NO_DACK;
  217     }
  218 #if 0
  219     q_printf("DMA: pulse DRQ on channel %d\n", ch);
  220 #endif
  221     if (ret == DMA_DACK) {
  222     DMA_LOCK();
  223     dma[DI(ch)].status |= 1 << (CI(ch) + 4);
  224     memcpy(dma_data_bus, buf, 1 << DI(ch));
  225     dma_run_channel(DI(ch), CI(ch));
  226     memcpy(buf, dma_data_bus, 1 << DI(ch));
  227     DMA_UNLOCK();
  228     } else {
  229     memset(buf, 0xff, 1 << DI(ch));
  230     }
  231     return ret;
  232 }
  233 
  234 
  235 #define d(x) (x-1)
  236 static Bit8u dma_io_read(ioport_t port)
  237 {
  238     Bit8u r = 0xff;
  239     switch (port) {
  240 
  241 /* lets ride on the cpp ass */
  242 #define HANDLE_CUR_ADDR_READ(d_n, c_n) \
  243   case DMA##d_n##_ADDR_##c_n: \
  244     r = dma[d(d_n)].chans[d(c_n)].cur_addr.byte[dma[d(d_n)].ff]; \
  245     q_printf("DMA%i: cur_addr read: %#x from Channel %d byte %d\n", \
  246     d_n, r, d(c_n), dma[d(d_n)].ff); \
  247     dma[d(d_n)].ff ^= 1; \
  248     break
  249     HANDLE_CUR_ADDR_READ(1, 1);
  250     HANDLE_CUR_ADDR_READ(1, 2);
  251     HANDLE_CUR_ADDR_READ(1, 3);
  252     HANDLE_CUR_ADDR_READ(1, 4);
  253 
  254     HANDLE_CUR_ADDR_READ(2, 1);
  255     HANDLE_CUR_ADDR_READ(2, 2);
  256     HANDLE_CUR_ADDR_READ(2, 3);
  257     HANDLE_CUR_ADDR_READ(2, 4);
  258 #undef HANDLE_CUR_ADDR_READ
  259 
  260 #define HANDLE_CUR_CNT_READ(d_n, c_n) \
  261   case DMA##d_n##_CNT_##c_n: \
  262     r = dma[d(d_n)].chans[d(c_n)].cur_count.byte[dma[d(d_n)].ff]; \
  263     q_printf("DMA%i: cur_cnt read: %#x from Channel %d byte %d\n", \
  264     d_n, r, d(c_n), dma[d(d_n)].ff); \
  265     dma[d(d_n)].ff ^= 1; \
  266     break
  267     HANDLE_CUR_CNT_READ(1, 1);
  268     HANDLE_CUR_CNT_READ(1, 2);
  269     HANDLE_CUR_CNT_READ(1, 3);
  270     HANDLE_CUR_CNT_READ(1, 4);
  271 
  272     HANDLE_CUR_CNT_READ(2, 1);
  273     HANDLE_CUR_CNT_READ(2, 2);
  274     HANDLE_CUR_CNT_READ(2, 3);
  275     HANDLE_CUR_CNT_READ(2, 4);
  276 #undef HANDLE_CUR_CNT_READ
  277 
  278 #define HANDLE_PAGE_READ(d_n, c_n) \
  279   case DMA##d_n##_PAGE_##c_n: \
  280     r = dma[d(d_n)].chans[d(c_n)].page; \
  281     q_printf("DMA%i: page read: %#x from Channel %d\n", \
  282     d_n, r, d(c_n)); \
  283     break
  284     HANDLE_PAGE_READ(1, 1);
  285     HANDLE_PAGE_READ(1, 2);
  286     HANDLE_PAGE_READ(1, 3);
  287     HANDLE_PAGE_READ(1, 4);
  288 
  289     HANDLE_PAGE_READ(2, 1);
  290     HANDLE_PAGE_READ(2, 2);
  291     HANDLE_PAGE_READ(2, 3);
  292     HANDLE_PAGE_READ(2, 4);
  293 #undef HANDLE_PAGE_READ
  294 
  295     case DMA1_STAT_REG:
  296     r = dma[DMA1].status;
  297     q_printf("DMA1: Read %u from Status reg\n", r);
  298     dma[DMA1].status &= 0xf0;   /* clear status bits */
  299     break;
  300     case DMA2_STAT_REG:
  301     r = dma[DMA2].status;
  302     q_printf("DMA2: Read %u from Status reg\n", r);
  303     dma[DMA2].status &= 0xf0;   /* clear status bits */
  304     break;
  305 
  306     case DMA1_TEMP_REG:
  307     r = dma[DMA1].tmp_reg;
  308     q_printf("DMA1: Read %u from temporary register unimplemented\n",
  309          r);
  310     break;
  311     case DMA2_TEMP_REG:
  312     r = dma[DMA2].tmp_reg;
  313     q_printf("DMA2: Read %u from temporary register unimplemented\n",
  314          r);
  315     break;
  316 
  317     default:
  318     q_printf("DMA: Unhandled Read on 0x%04x\n", (Bit16u) port);
  319     }
  320 
  321     dma_process();      // Not needed in fact
  322 
  323     return r;
  324 }
  325 
  326 static void dma_io_write(ioport_t port, Bit8u value)
  327 {
  328     switch (port) {
  329 
  330 #define HANDLE_ADDR_WRITE(d_n, c_n) \
  331   case DMA##d_n##_ADDR_##c_n: \
  332     dma[d(d_n)].chans[d(c_n)].base_addr.byte[dma[d(d_n)].ff] = value; \
  333     dma[d(d_n)].chans[d(c_n)].cur_addr.byte[dma[d(d_n)].ff] = value; \
  334     q_printf("DMA%i: addr write: %#x to Channel %d byte %d\n", \
  335     d_n, value, d(c_n), dma[d(d_n)].ff); \
  336     dma[d(d_n)].ff ^= 1; \
  337     break
  338     HANDLE_ADDR_WRITE(1, 1);
  339     HANDLE_ADDR_WRITE(1, 2);
  340     HANDLE_ADDR_WRITE(1, 3);
  341     HANDLE_ADDR_WRITE(1, 4);
  342 
  343     HANDLE_ADDR_WRITE(2, 1);
  344     HANDLE_ADDR_WRITE(2, 2);
  345     HANDLE_ADDR_WRITE(2, 3);
  346     HANDLE_ADDR_WRITE(2, 4);
  347 #undef HANDLE_ADDR_WRITE
  348 
  349 #define HANDLE_CNT_WRITE(d_n, c_n) \
  350   case DMA##d_n##_CNT_##c_n: \
  351     dma[d(d_n)].chans[d(c_n)].base_count.byte[dma[d(d_n)].ff] = value; \
  352     dma[d(d_n)].chans[d(c_n)].cur_count.byte[dma[d(d_n)].ff] = value; \
  353     q_printf("DMA%i: count write: %#x to Channel %d byte %d\n", \
  354     d_n, value, d(c_n), dma[d(d_n)].ff); \
  355     dma[d(d_n)].ff ^= 1; \
  356     break
  357     HANDLE_CNT_WRITE(1, 1);
  358     HANDLE_CNT_WRITE(1, 2);
  359     HANDLE_CNT_WRITE(1, 3);
  360     HANDLE_CNT_WRITE(1, 4);
  361 
  362     HANDLE_CNT_WRITE(2, 1);
  363     HANDLE_CNT_WRITE(2, 2);
  364     HANDLE_CNT_WRITE(2, 3);
  365     HANDLE_CNT_WRITE(2, 4);
  366 #undef HANDLE_CNT_WRITE
  367 
  368 #define HANDLE_PAGE_WRITE(d_n, c_n) \
  369   case DMA##d_n##_PAGE_##c_n: \
  370     dma[d(d_n)].chans[d(c_n)].page = value; \
  371     q_printf("DMA%i: page write: %#x to Channel %d\n", \
  372     d_n, value, d(c_n)); \
  373     break
  374     HANDLE_PAGE_WRITE(1, 1);
  375     HANDLE_PAGE_WRITE(1, 2);
  376     HANDLE_PAGE_WRITE(1, 3);
  377     HANDLE_PAGE_WRITE(1, 4);
  378 
  379     HANDLE_PAGE_WRITE(2, 1);
  380     HANDLE_PAGE_WRITE(2, 2);
  381     HANDLE_PAGE_WRITE(2, 3);
  382     HANDLE_PAGE_WRITE(2, 4);
  383 #undef HANDLE_PAGE_WRITE
  384 
  385     case DMA1_MASK_REG:
  386     if (value & 4) {
  387         q_printf("DMA1: mask channel %i\n", value & 3);
  388         dma[DMA1].mask |= 1 << (value & 3);
  389     } else {
  390         q_printf("DMA1: unmask channel %i\n", value & 3);
  391         dma[DMA1].mask &= ~(1 << (value & 3));
  392         dma[DMA1].status &= ~(1 << (value & 3));
  393     }
  394     break;
  395     case DMA2_MASK_REG:
  396     if (value & 4) {
  397         q_printf("DMA2: mask channel %i\n", value & 3);
  398         dma[DMA2].mask |= 1 << (value & 3);
  399     } else {
  400         q_printf("DMA2: unmask channel %i\n", value & 3);
  401         dma[DMA2].mask &= ~(1 << (value & 3));
  402         dma[DMA2].status &= ~(1 << (value & 3));
  403     }
  404     break;
  405 
  406     case DMA1_MODE_REG:
  407     dma[DMA1].chans[value & 3].mode = value >> 2;
  408     q_printf("DMA1: Write mode 0x%x to Channel %u\n", value >> 2,
  409          value & 3);
  410     break;
  411     case DMA2_MODE_REG:
  412     dma[DMA2].chans[value & 3].mode = value >> 2;
  413     q_printf("DMA2: Write mode 0x%x to Channel %u\n", value >> 2,
  414          value & 3);
  415     break;
  416 
  417     case DMA1_CMD_REG:
  418     dma[DMA1].command = value;
  419     q_printf("DMA1: Write 0x%x to Command reg\n", value);
  420     break;
  421     case DMA2_CMD_REG:
  422     dma[DMA2].command = value;
  423     q_printf("DMA2: Write 0x%x to Command reg\n", value);
  424     break;
  425 
  426     case DMA1_CLEAR_FF_REG:
  427     q_printf("DMA1: Clearing Output Flip-Flop\n");
  428     dma[DMA1].ff = 0;
  429     break;
  430     case DMA2_CLEAR_FF_REG:
  431     q_printf("DMA2: Clearing Output Flip-Flop\n");
  432     dma[DMA2].ff = 0;
  433     break;
  434 
  435     case DMA1_RESET_REG:
  436     q_printf("DMA1: Reset\n");
  437     dma_soft_reset(DMA1);
  438     break;
  439     case DMA2_RESET_REG:
  440     q_printf("DMA2: Reset\n");
  441     dma_soft_reset(DMA2);
  442     break;
  443 
  444     case DMA1_REQ_REG:
  445     if (value & 4) {
  446         q_printf("DMA1: Setting request state %#x\n", value);
  447         dma[DMA1].request |= 1 << (value & 3);
  448     } else {
  449         q_printf("DMA1: Clearing request state %#x\n", value);
  450         dma[DMA1].request &= ~(1 << (value & 3));
  451     }
  452     break;
  453     case DMA2_REQ_REG:
  454     if (value & 4) {
  455         q_printf("DMA2: Setting request state %#x\n", value);
  456         dma[DMA2].request |= 1 << (value & 3);
  457     } else {
  458         q_printf("DMA2: Clearing request state %#x\n", value);
  459         dma[DMA2].request &= ~(1 << (value & 3));
  460     }
  461     break;
  462 
  463     case DMA1_CLR_MASK_REG:
  464     q_printf("DMA1: Clearing masks\n");
  465     dma[DMA1].mask = 0;
  466     dma[DMA1].status &= 0xf0;
  467     break;
  468     case DMA2_CLR_MASK_REG:
  469     q_printf("DMA2: Clearing masks\n");
  470     dma[DMA2].mask = 0;
  471     dma[DMA2].status &= 0xf0;
  472     break;
  473 
  474     case DMA1_MASK_ALL_REG:
  475     q_printf("DMA1: Setting masks %#x\n", value);
  476     dma[DMA1].mask = value;
  477     dma[DMA1].status &= 0xf0;
  478     break;
  479     case DMA2_MASK_ALL_REG:
  480     q_printf("DMA2: Setting masks %#x\n", value);
  481     dma[DMA2].mask = value;
  482     dma[DMA2].status &= 0xf0;
  483     break;
  484 
  485     default:
  486     q_printf("DMA: Unhandled Write on 0x%04x\n", (Bit16u) port);
  487     }
  488 
  489     dma_process();      // Not needed in fact
  490 }
  491 
  492 #undef d
  493 
  494 
  495 void dma_new_reset(void)
  496 {
  497     dma_soft_reset(DMA1);
  498     dma_soft_reset(DMA2);
  499 }
  500 
  501 void dma_new_init(void)
  502 {
  503     emu_iodev_t io_device;
  504 
  505     /* 8237 DMA controller */
  506     io_device.read_portb = dma_io_read;
  507     io_device.write_portb = dma_io_write;
  508     io_device.read_portw = NULL;
  509     io_device.write_portw = NULL;
  510     io_device.read_portd = NULL;
  511     io_device.write_portd = NULL;
  512     io_device.irq = EMU_NO_IRQ;
  513     io_device.fd = -1;
  514 
  515     /*
  516      * XT Controller 
  517      */
  518     io_device.start_addr = 0x0000;
  519     io_device.end_addr = 0x000F;
  520     io_device.handler_name = "DMA - XT Controller";
  521     port_register_handler(io_device, 0);
  522 
  523     /*
  524      * Page Registers (XT)
  525      */
  526     io_device.start_addr = 0x0081;
  527     io_device.end_addr = 0x0087;
  528     io_device.handler_name = "DMA - XT Pages";
  529     port_register_handler(io_device, 0);
  530 
  531     /*
  532      * AT Controller
  533      */
  534     io_device.start_addr = 0x00C0;
  535     io_device.end_addr = 0x00DE;
  536     io_device.handler_name = "DMA - AT Controller";
  537     port_register_handler(io_device, 0);
  538 
  539     /*
  540      * Page Registers (AT)
  541      */
  542     io_device.start_addr = 0x0089;
  543     io_device.end_addr = 0x008F;
  544     io_device.handler_name = "DMA - AT Pages";
  545     port_register_handler(io_device, 0);
  546 
  547     q_printf("DMA: DMA Controller initialized - 8 & 16 bit modes\n");
  548 }
  549 
  550 CONSTRUCTOR(static void dma_early_init(void))
  551 {
  552     /* HACK - putting this into dma_init() should work, but doesn't */
  553     register_debug_class('q', NULL, "DMA");
  554 }