Search
lxdream.org :: lxdream/src/sh4/dmac.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/dmac.c
changeset 736:a02d1475ccfd
prev561:533f6b478071
next929:fd8cb0c82f5f
author nkeynes
date Thu Dec 11 23:26:03 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Disable the generational translation cache - I've got no evidence that it
actually helps performance, and it simplifies things to get rid of it (in
particular, translated code doesn't have to worry about being moved now).
view annotate diff log raw
     1 /**
     2  * $Id$
     3  * 
     4  * SH4 onboard DMA controller (DMAC) peripheral.
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    18 #define MODULE sh4_module
    20 #include "dream.h"
    21 #include "mem.h"
    22 #include "sh4/sh4core.h"
    23 #include "sh4/sh4mmio.h"
    24 #include "sh4/intc.h"
    25 #include "sh4/dmac.h"
    27 static int DMAC_xfer_size[8] = {8, 1, 2, 4, 32, 1, 1, 1};
    29 /* Control flags */
    30 #define CHCR_IE 0x04  /* Interrupt Enable */
    31 #define CHCR_TE 0x02  /* Transfer End */
    32 #define CHCR_DE 0x01  /* DMAC Enable */
    34 #define IS_DMAC_ENABLED() ((MMIO_READ(DMAC,DMAOR)&0x07) == 0x01)
    36 #define IS_AUTO_REQUEST(val) ((val & 0x0C00) == 0x0400)
    37 #define CHANNEL_RESOURCE(val) ((val >> 8) & 0x0F)
    39 #define DMA_SOURCE(chan) MMIO_READ(DMAC, SAR0 + (chan<<4))
    40 #define DMA_DEST(chan) MMIO_READ(DMAC, DAR0 + (chan<<4))
    41 #define DMA_COUNT(chan) (MMIO_READ(DMAC, DMATCR0 + (chan<<4)) & 0x00FFFFFF)
    42 #define DMA_CONTROL(chan) MMIO_READ(DMAC, CHCR0 + (chan<<4))
    43 #define IS_CHANNEL_ENABLED(ctrl) ((ctrl & 0x03) == 0x01)
    44 #define IS_CHANNEL_IRQ_ENABLED(ctrl) (ctrl & CHCR_IE)
    45 #define IS_CHANNEL_IRQ_ACTIVE(ctrl) ((ctrl & (CHCR_IE|CHCR_TE)) == (CHCR_IE|CHCR_TE))
    47 #define DMARES_MEMORY_TO_MEMORY 0x00
    48 #define DMARES_MEMORY_TO_DEVICE 0x02
    49 #define DMARES_DEVICE_TO_MEMORY 0x03
    50 #define DMARES_MEMORY_TO_MEMORY_AUTO 0x04
    51 #define DMARES_MEMORY_TO_PERIPH_AUTO 0x05
    52 #define DMARES_PERIPH_TO_MEMORY_AUTO 0x06
    53 #define DMARES_SCI_TRANSMIT_EMPTY 0x08
    54 #define DMARES_SCI_RECEIVE_FULL 0x09
    55 #define DMARES_SCIF_TRANSMIT_EMPTY 0x0A
    56 #define DMARES_SCIF_RECEIVE_FULL 0x0B
    57 #define DMARES_MEMORY_TO_MEMORY_TMU 0x0C
    58 #define DMARES_MEMORY_TO_PERIPH_TMU 0x0D
    59 #define DMARES_PERIPH_TO_MEMORY_TMU 0x0E
    61 void DMAC_set_control( uint32_t channel, uint32_t val ) 
    62 {
    63     uint32_t oldval = DMA_CONTROL(channel);
    64     int resource;
    65     MMIO_WRITE( DMAC, CHCR0 + (channel<<4), val );
    67     /* If TE or IE are cleared, clear the interrupt request */
    68     if( IS_CHANNEL_IRQ_ACTIVE(oldval) &&
    69             !IS_CHANNEL_IRQ_ACTIVE(val) )
    70         intc_clear_interrupt( INT_DMA_DMTE0+channel );
    72     resource = CHANNEL_RESOURCE(val);
    73     if( IS_CHANNEL_ENABLED(val) ) {
    74         if( resource >= DMARES_MEMORY_TO_MEMORY_AUTO && 
    75                 resource < DMARES_SCI_TRANSMIT_EMPTY ) {
    76             /* Autorun */
    77         }
    78     }
    80     /* Everything else we don't need to care about until we actually try to
    81      * run the channel
    82      */
    83 }
    85 int32_t mmio_region_DMAC_read( uint32_t reg )
    86 {
    87     return MMIO_READ( DMAC, reg );
    88 }
    90 void mmio_region_DMAC_write( uint32_t reg, uint32_t val ) 
    91 {
    92     switch( reg ) {
    93     case DMAOR:
    94         MMIO_WRITE( DMAC, reg, val );
    95         break;
    96     case CHCR0: DMAC_set_control( 0, val ); break;
    97     case CHCR1: DMAC_set_control( 1, val ); break;
    98     case CHCR2: DMAC_set_control( 2, val ); break;
    99     case CHCR3: DMAC_set_control( 3, val ); break;
   100     default:
   101         MMIO_WRITE( DMAC, reg, val );
   102     }
   103 }
   105 /**
   106  * Execute up to run_count transfers on the specified channel. Assumes the
   107  * trigger for the channel has been received.
   108  *
   109  * @param channel Channel number (0-3) to run.
   110  * @param run_count number of transfers to execute, or 0 to run to the 
   111  * end of the transfer count.
   112  */
   113 void DMAC_run_channel( uint32_t channel, uint32_t run_count )
   114 {
   116 #if 0 /* Should really finish this */
   117     char burst[32]; /* Transfer burst */
   118     uint32_t control = DMA_CONTROL(channel);
   120     if( IS_CHANNEL_ENABLED(control) ) {
   121         uint32_t source = DMA_SOURCE(channel);
   122         uint32_t dest = DMA_DEST(channel);
   123         uint32_t count = DMA_COUNT( channel );
   124         if( count == 0 )
   125             count = 0x01000000;
   126         if( run_count == 0 || run_count > count )
   127             run_count = count;
   128         uint32_t xfersize = DMAC_xfer_size[ (control >> 4)&0x07 ];
   129         int source_step, dest_step;
   130         int resource = (control >> 8) & 0x0F;
   131         switch( (control >> 14) & 0x03 ) {
   132         case 0: dest_step = 0; break;
   133         case 1: dest_step = xfersize; break;
   134         case 2: dest_step = -xfersize; break;
   135         case 3: dest_step = 0; break; /* Illegal */
   136         }
   137         switch( (control >> 12) & 0x03 ) {
   138         case 0: source_step = 0; break;
   139         case 1: source_step = xfersize; break;
   140         case 2: source_step = -xfersize; break;
   141         case 3: source_step = 0; break; /* Illegal */
   142         }
   144         while( run_count > 0 ) {
   145             /* Origin */
   146             if( (resource & 0x02) == 0 ) {
   147                 /* Source is a normal memory address */
   149             } else {
   150                 /* Device */
   151             }
   153             /* Destination */
   154             if( (resource & 0x01) == 0 ) {
   155                 /* Destination is a normal memory address */
   156             } else {
   157             }
   158             run_count--; 
   159             count--;
   160         }
   161     }
   162 #endif
   163 }
   165 /**
   166  * Fetch a block of data by DMA from memory to an external device (ie the
   167  * ASIC). The DMA channel must be configured for Mem=>dev or it will return
   168  * no bytes and whinge mightily. Note this is NOT used for SH4 peripheral
   169  * transfers.
   170  *
   171  * @return the number of bytes actually transferred.
   172  */
   173 uint32_t DMAC_get_buffer( int channel, sh4ptr_t buf, uint32_t numBytes )
   174 {
   175     uint32_t control = DMA_CONTROL(channel);
   176     uint32_t source, count, run_count, size, i;
   177     char tmp[32];
   179     if( !IS_CHANNEL_ENABLED(control) || !IS_DMAC_ENABLED() )
   180         return 0;
   182     if( ((control >> 8) & 0x0F) !=  DMARES_MEMORY_TO_DEVICE ) {
   183         /* Error? */
   185         return 0;
   186     } 
   188     source = DMA_SOURCE(channel);
   189     count = DMA_COUNT(channel);
   190     if( count == 0 ) count = 0x01000000;
   192     size = DMAC_xfer_size[ (control >> 4)&0x07 ];
   193     run_count = numBytes / size;
   194     if( run_count > count || run_count == 0 )
   195         run_count = count;
   197     /* Do copy - FIXME: doesn't work when crossing regions */
   198     sh4ptr_t region = mem_get_region( source );
   199     switch( (control >> 12) & 0x03 ) {
   200     case 0: 
   201         memcpy( tmp, region, size );
   202         for( i=0; i<run_count; i++ ) {
   203             memcpy( buf, tmp, size );
   204             buf += size;
   205         }
   206         break;
   207     case 1: 
   208         i = run_count * size;
   209         memcpy( buf, region, i );
   210         source += i;
   211         break;
   212     case 2: 
   213         for( i=0; i<run_count; i++ ) {
   214             memcpy( buf, region, size );
   215             buf += size;
   216             region -= size;
   217         }
   218         source -= (run_count * size);
   219         break;
   220     default:
   221         return 0; /* Illegal */
   222     }
   224     /* Update the channel registers */
   225     count -= run_count;
   226     MMIO_WRITE( DMAC, SAR0 + (channel<<4), source );
   227     MMIO_WRITE( DMAC, DMATCR0 + (channel<<4), count );
   228     if( count == 0 ) {
   229         control |= CHCR_TE; 
   230         if( IS_CHANNEL_IRQ_ENABLED(control) )
   231             intc_raise_interrupt( INT_DMA_DMTE0 + channel );
   232         MMIO_WRITE( DMAC, CHCR0 + (channel<<4), control );
   233     }
   235     return run_count * size;
   236 }
   238 uint32_t DMAC_put_buffer( int channel, sh4ptr_t buf, uint32_t numBytes )
   239 {
   240     uint32_t control = DMA_CONTROL(channel);
   241     uint32_t dest, count, run_count, size, i;
   243     if( !IS_CHANNEL_ENABLED(control) || !IS_DMAC_ENABLED() )
   244         return 0;
   246     if( ((control >> 8) & 0x0F) !=  DMARES_DEVICE_TO_MEMORY ) {
   247         /* Error? */
   248         return 0;
   249     } 
   251     dest = DMA_DEST(channel);
   252     count = DMA_COUNT(channel);
   253     if( count == 0 ) count = 0x01000000;
   255     size = DMAC_xfer_size[ (control >> 4)&0x07 ];
   256     run_count = numBytes / size;
   257     if( run_count > count || run_count == 0 )
   258         run_count = count;
   260     /* Do copy - FIXME: doesn't work when crossing regions */
   261     sh4ptr_t region = mem_get_region( dest );
   262     switch( (control >> 12) & 0x03 ) {
   263     case 0: 
   264         for( i=0; i<run_count; i++ ) { 
   265             /* Doesn't make a whole lot of sense, but hey... */
   266             memcpy( region, buf, size );
   267             buf += size;
   268         }
   269         break;
   270     case 1: 
   271         i = run_count * size;
   272         memcpy( region, buf, i );
   273         dest += i;
   274         break;
   275     case 2: 
   276         for( i=0; i<run_count; i++ ) {
   277             memcpy( region, buf, size );
   278             buf += size;
   279             region -= size;
   280         }
   281         dest -= (run_count * size);
   282         break;
   283     default:
   284         return 0; /* Illegal */
   285     }
   287     /* Update the channel registers */
   288     count -= run_count;
   289     MMIO_WRITE( DMAC, DAR0 + (channel<<4), dest );
   290     MMIO_WRITE( DMAC, DMATCR0 + (channel<<4), count );
   291     if( count == 0 ) {
   292         control |= CHCR_TE; 
   293         if( IS_CHANNEL_IRQ_ENABLED(control) )
   294             intc_raise_interrupt( INT_DMA_DMTE0 + channel );
   295         MMIO_WRITE( DMAC, CHCR0 + (channel<<4), control );
   296     }
   297     return run_count * size;
   298 }
   300 void DMAC_reset( void )
   301 {
   303 }
   305 void DMAC_save_state( FILE *F ) 
   306 {
   308 }
   310 int DMAC_load_state( FILE *f )
   311 {
   312     return 0;
   313 }
   315 void DMAC_trigger( int resource )
   316 {
   317     int i;
   318     if( !IS_DMAC_ENABLED() )
   319         return;
   320     for( i=0; i<4; i++ ) {
   321         uint32_t control = DMA_CONTROL(i);
   322         if( IS_CHANNEL_ENABLED(control) ) {
   323             uint32_t channel_res = CHANNEL_RESOURCE(control);
   324             switch( resource ) {
   325             case DMAC_EXTERNAL:
   326                 if( channel_res == DMARES_MEMORY_TO_MEMORY )
   327                     DMAC_run_channel(i,1);
   328                 break;
   329             case DMAC_SCI_TDE:
   330                 if( channel_res == DMARES_SCI_TRANSMIT_EMPTY )
   331                     DMAC_run_channel(i,1);
   332                 break;
   333             case DMAC_SCI_RDF:
   334                 if( channel_res == DMARES_SCI_RECEIVE_FULL )
   335                     DMAC_run_channel(i,1);
   336                 break;
   337             case DMAC_SCIF_TDE:
   338                 if( channel_res == DMARES_SCIF_TRANSMIT_EMPTY )
   339                     DMAC_run_channel(i,1);
   340                 break;
   341             case DMAC_SCIF_RDF:
   342                 if( channel_res == DMARES_SCIF_RECEIVE_FULL )
   343                     DMAC_run_channel(i,1);
   344                 break;
   345             case DMAC_TMU_ICI:
   346                 if( channel_res >= DMARES_MEMORY_TO_MEMORY_TMU ) 
   347                     DMAC_run_channel(i,1);
   348                 break;
   349             }
   350         }
   351     }
   352 }
.