Search
lxdream.org :: lxdream/src/sh4/dmac.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/dmac.c
changeset 929:fd8cb0c82f5f
prev736:a02d1475ccfd
next975:007bf7eb944f
author nkeynes
date Sat Dec 27 02:59:35 2008 +0000 (15 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change Replace fpscr_mask/fpscr flags in xlat_cache_block with a single xlat_sh4_mode,
which tracks the field of the same name in sh4r - actually a little faster this way.
Now depends on SR.MD, FPSCR.PR and FPSCR.SZ (although it doesn't benefit from the SR
flag yet).

Also fixed the failure to check the flags in the common case (code address returned
by previous block) which took away the performance benefits, but oh well.
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 MMIO_REGION_READ_FN( DMAC, reg )
    86 {
    87     return MMIO_READ( DMAC, reg&0xFFF );
    88 }
    90 MMIO_REGION_WRITE_FN( DMAC, reg, val )
    91 {
    92     reg &= 0xFFF;
    93     switch( reg ) {
    94     case DMAOR:
    95         MMIO_WRITE( DMAC, reg, val );
    96         break;
    97     case CHCR0: DMAC_set_control( 0, val ); break;
    98     case CHCR1: DMAC_set_control( 1, val ); break;
    99     case CHCR2: DMAC_set_control( 2, val ); break;
   100     case CHCR3: DMAC_set_control( 3, val ); break;
   101     default:
   102         MMIO_WRITE( DMAC, reg, val );
   103     }
   104 }
   106 /**
   107  * Execute up to run_count transfers on the specified channel. Assumes the
   108  * trigger for the channel has been received.
   109  *
   110  * @param channel Channel number (0-3) to run.
   111  * @param run_count number of transfers to execute, or 0 to run to the 
   112  * end of the transfer count.
   113  */
   114 void DMAC_run_channel( uint32_t channel, uint32_t run_count )
   115 {
   117 #if 0 /* Should really finish this */
   118     char burst[32]; /* Transfer burst */
   119     uint32_t control = DMA_CONTROL(channel);
   121     if( IS_CHANNEL_ENABLED(control) ) {
   122         uint32_t source = DMA_SOURCE(channel);
   123         uint32_t dest = DMA_DEST(channel);
   124         uint32_t count = DMA_COUNT( channel );
   125         if( count == 0 )
   126             count = 0x01000000;
   127         if( run_count == 0 || run_count > count )
   128             run_count = count;
   129         uint32_t xfersize = DMAC_xfer_size[ (control >> 4)&0x07 ];
   130         int source_step, dest_step;
   131         int resource = (control >> 8) & 0x0F;
   132         switch( (control >> 14) & 0x03 ) {
   133         case 0: dest_step = 0; break;
   134         case 1: dest_step = xfersize; break;
   135         case 2: dest_step = -xfersize; break;
   136         case 3: dest_step = 0; break; /* Illegal */
   137         }
   138         switch( (control >> 12) & 0x03 ) {
   139         case 0: source_step = 0; break;
   140         case 1: source_step = xfersize; break;
   141         case 2: source_step = -xfersize; break;
   142         case 3: source_step = 0; break; /* Illegal */
   143         }
   145         while( run_count > 0 ) {
   146             /* Origin */
   147             if( (resource & 0x02) == 0 ) {
   148                 /* Source is a normal memory address */
   150             } else {
   151                 /* Device */
   152             }
   154             /* Destination */
   155             if( (resource & 0x01) == 0 ) {
   156                 /* Destination is a normal memory address */
   157             } else {
   158             }
   159             run_count--; 
   160             count--;
   161         }
   162     }
   163 #endif
   164 }
   166 /**
   167  * Fetch a block of data by DMA from memory to an external device (ie the
   168  * ASIC). The DMA channel must be configured for Mem=>dev or it will return
   169  * no bytes and whinge mightily. Note this is NOT used for SH4 peripheral
   170  * transfers.
   171  *
   172  * @return the number of bytes actually transferred.
   173  */
   174 uint32_t DMAC_get_buffer( int channel, sh4ptr_t buf, uint32_t numBytes )
   175 {
   176     uint32_t control = DMA_CONTROL(channel);
   177     uint32_t source, count, run_count, size, i;
   178     char tmp[32];
   180     if( !IS_CHANNEL_ENABLED(control) || !IS_DMAC_ENABLED() )
   181         return 0;
   183     if( ((control >> 8) & 0x0F) !=  DMARES_MEMORY_TO_DEVICE ) {
   184         /* Error? */
   186         return 0;
   187     } 
   189     source = DMA_SOURCE(channel);
   190     count = DMA_COUNT(channel);
   191     if( count == 0 ) count = 0x01000000;
   193     size = DMAC_xfer_size[ (control >> 4)&0x07 ];
   194     run_count = numBytes / size;
   195     if( run_count > count || run_count == 0 )
   196         run_count = count;
   198     /* Do copy - FIXME: doesn't work when crossing regions */
   199     sh4ptr_t region = mem_get_region( source );
   200     switch( (control >> 12) & 0x03 ) {
   201     case 0: 
   202         memcpy( tmp, region, size );
   203         for( i=0; i<run_count; i++ ) {
   204             memcpy( buf, tmp, size );
   205             buf += size;
   206         }
   207         break;
   208     case 1: 
   209         i = run_count * size;
   210         memcpy( buf, region, i );
   211         source += i;
   212         break;
   213     case 2: 
   214         for( i=0; i<run_count; i++ ) {
   215             memcpy( buf, region, size );
   216             buf += size;
   217             region -= size;
   218         }
   219         source -= (run_count * size);
   220         break;
   221     default:
   222         return 0; /* Illegal */
   223     }
   225     /* Update the channel registers */
   226     count -= run_count;
   227     MMIO_WRITE( DMAC, SAR0 + (channel<<4), source );
   228     MMIO_WRITE( DMAC, DMATCR0 + (channel<<4), count );
   229     if( count == 0 ) {
   230         control |= CHCR_TE; 
   231         if( IS_CHANNEL_IRQ_ENABLED(control) )
   232             intc_raise_interrupt( INT_DMA_DMTE0 + channel );
   233         MMIO_WRITE( DMAC, CHCR0 + (channel<<4), control );
   234     }
   236     return run_count * size;
   237 }
   239 uint32_t DMAC_put_buffer( int channel, sh4ptr_t buf, uint32_t numBytes )
   240 {
   241     uint32_t control = DMA_CONTROL(channel);
   242     uint32_t dest, count, run_count, size, i;
   244     if( !IS_CHANNEL_ENABLED(control) || !IS_DMAC_ENABLED() )
   245         return 0;
   247     if( ((control >> 8) & 0x0F) !=  DMARES_DEVICE_TO_MEMORY ) {
   248         /* Error? */
   249         return 0;
   250     } 
   252     dest = DMA_DEST(channel);
   253     count = DMA_COUNT(channel);
   254     if( count == 0 ) count = 0x01000000;
   256     size = DMAC_xfer_size[ (control >> 4)&0x07 ];
   257     run_count = numBytes / size;
   258     if( run_count > count || run_count == 0 )
   259         run_count = count;
   261     /* Do copy - FIXME: doesn't work when crossing regions */
   262     sh4ptr_t region = mem_get_region( dest );
   263     switch( (control >> 12) & 0x03 ) {
   264     case 0: 
   265         for( i=0; i<run_count; i++ ) { 
   266             /* Doesn't make a whole lot of sense, but hey... */
   267             memcpy( region, buf, size );
   268             buf += size;
   269         }
   270         break;
   271     case 1: 
   272         i = run_count * size;
   273         memcpy( region, buf, i );
   274         dest += i;
   275         break;
   276     case 2: 
   277         for( i=0; i<run_count; i++ ) {
   278             memcpy( region, buf, size );
   279             buf += size;
   280             region -= size;
   281         }
   282         dest -= (run_count * size);
   283         break;
   284     default:
   285         return 0; /* Illegal */
   286     }
   288     /* Update the channel registers */
   289     count -= run_count;
   290     MMIO_WRITE( DMAC, DAR0 + (channel<<4), dest );
   291     MMIO_WRITE( DMAC, DMATCR0 + (channel<<4), count );
   292     if( count == 0 ) {
   293         control |= CHCR_TE; 
   294         if( IS_CHANNEL_IRQ_ENABLED(control) )
   295             intc_raise_interrupt( INT_DMA_DMTE0 + channel );
   296         MMIO_WRITE( DMAC, CHCR0 + (channel<<4), control );
   297     }
   298     return run_count * size;
   299 }
   301 void DMAC_reset( void )
   302 {
   304 }
   306 void DMAC_save_state( FILE *F ) 
   307 {
   309 }
   311 int DMAC_load_state( FILE *f )
   312 {
   313     return 0;
   314 }
   316 void DMAC_trigger( int resource )
   317 {
   318     int i;
   319     if( !IS_DMAC_ENABLED() )
   320         return;
   321     for( i=0; i<4; i++ ) {
   322         uint32_t control = DMA_CONTROL(i);
   323         if( IS_CHANNEL_ENABLED(control) ) {
   324             uint32_t channel_res = CHANNEL_RESOURCE(control);
   325             switch( resource ) {
   326             case DMAC_EXTERNAL:
   327                 if( channel_res == DMARES_MEMORY_TO_MEMORY )
   328                     DMAC_run_channel(i,1);
   329                 break;
   330             case DMAC_SCI_TDE:
   331                 if( channel_res == DMARES_SCI_TRANSMIT_EMPTY )
   332                     DMAC_run_channel(i,1);
   333                 break;
   334             case DMAC_SCI_RDF:
   335                 if( channel_res == DMARES_SCI_RECEIVE_FULL )
   336                     DMAC_run_channel(i,1);
   337                 break;
   338             case DMAC_SCIF_TDE:
   339                 if( channel_res == DMARES_SCIF_TRANSMIT_EMPTY )
   340                     DMAC_run_channel(i,1);
   341                 break;
   342             case DMAC_SCIF_RDF:
   343                 if( channel_res == DMARES_SCIF_RECEIVE_FULL )
   344                     DMAC_run_channel(i,1);
   345                 break;
   346             case DMAC_TMU_ICI:
   347                 if( channel_res >= DMARES_MEMORY_TO_MEMORY_TMU ) 
   348                     DMAC_run_channel(i,1);
   349                 break;
   350             }
   351         }
   352     }
   353 }
.