Search
lxdream.org :: lxdream/src/aica/aica.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/aica.c
changeset 1067:d3c00ffccfcd
prev1024:c67f2d61ab97
prev934:3acd3b3ee6d1
author nkeynes
date Sun Jul 05 13:54:48 2009 +1000 (12 years ago)
permissions -rw-r--r--
last change No-op merge lxdream-mem to tip to remove head (Long since merged in
actuality)
view annotate diff log raw
     1 /**
     2  * $Id$
     3  * 
     4  * This module implements the AICA's IO interfaces, as well
     5  * as providing the core AICA module to the system.
     6  *
     7  * Copyright (c) 2005 Nathan Keynes.
     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  */
    20 #define MODULE aica_module
    22 #include <time.h>
    23 #include "dream.h"
    24 #include "dreamcast.h"
    25 #include "mem.h"
    26 #include "aica/aica.h"
    27 #include "armcore.h"
    28 #include "aica/audio.h"
    29 #define MMIO_IMPL
    30 #include "aica.h"
    32 MMIO_REGION_READ_DEFFN( AICA0 )
    33 MMIO_REGION_READ_DEFFN( AICA1 )
    34 MMIO_REGION_READ_DEFSUBFNS(AICA0)
    35 MMIO_REGION_READ_DEFSUBFNS(AICA1)
    36 MMIO_REGION_READ_DEFSUBFNS(AICA2)
    37 MMIO_REGION_READ_DEFSUBFNS(AICARTC)
    39 void aica_init( void );
    40 void aica_reset( void );
    41 void aica_start( void );
    42 void aica_stop( void );
    43 void aica_save_state( FILE *f );
    44 int aica_load_state( FILE *f );
    45 uint32_t aica_run_slice( uint32_t );
    47 struct dreamcast_module aica_module = { "AICA", aica_init, aica_reset, 
    48         aica_start, aica_run_slice, aica_stop,
    49         aica_save_state, aica_load_state };
    51 struct aica_state_struct {
    52     uint32_t time_of_day;
    53     /**
    54      * Keep track of what we've done so far this second, to try to keep the
    55      * precision of samples/second.
    56      */
    57     uint32_t samples_done;
    58     uint32_t nanosecs_done;
    59     /**
    60      * Event (IRQ) state
    61      */
    62     int event_pending;
    63     int clear_count;
    64 };
    66 static struct aica_state_struct aica_state;
    69 /**
    70  * Initialize the AICA subsystem. Note requires that 
    71  */
    72 void aica_init( void )
    73 {
    74     register_io_regions( mmio_list_spu );
    75     MMIO_NOTRACE(AICA0);
    76     MMIO_NOTRACE(AICA1);
    77     aica_reset();
    78 }
    80 void aica_reset( void )
    81 {
    82     arm_reset();
    83     aica_state.time_of_day = 0x5bfc8900;
    84     aica_state.samples_done = 0;
    85     aica_state.nanosecs_done = 0;
    86     aica_state.event_pending = 0;
    87     aica_state.clear_count = 0;
    88     //    aica_event(2); /* Pre-deliver a timer interrupt */
    89 }
    91 void aica_start( void )
    92 {
    93     audio_start_driver();
    94 }
    96 uint32_t aica_run_slice( uint32_t nanosecs )
    97 {
    98     /* Run arm instructions */
    99     int reset = MMIO_READ( AICA2, AICA_RESET );
   100     if( (reset & 1) == 0 ) { /* Running */
   101         int num_samples = (int)((uint64_t)AICA_SAMPLE_RATE * (aica_state.nanosecs_done + nanosecs) / 1000000000) - aica_state.samples_done;
   102         num_samples = arm_run_slice( num_samples );
   103         audio_mix_samples( num_samples );
   105         aica_state.samples_done += num_samples;
   106         aica_state.nanosecs_done += nanosecs;
   107     }
   108     if( aica_state.nanosecs_done > 1000000000 ) {
   109         aica_state.samples_done -= AICA_SAMPLE_RATE;
   110         aica_state.nanosecs_done -= 1000000000;
   111         aica_state.time_of_day++;
   112     }
   113     return nanosecs;
   114 }
   116 void aica_stop( void )
   117 {
   118     audio_stop_driver();
   119 }
   121 void aica_save_state( FILE *f )
   122 {
   123     fwrite( &aica_state, sizeof(struct aica_state_struct), 1, f );
   124     arm_save_state( f );
   125     audio_save_state(f);
   126 }
   128 int aica_load_state( FILE *f )
   129 {
   130     fread( &aica_state, sizeof(struct aica_state_struct), 1, f );
   131     arm_load_state( f );
   132     return audio_load_state(f);
   133 }
   135 /* Note: This is probably not necessarily technically correct but it should
   136  * work in the meantime.
   137  */
   139 void aica_event( int event )
   140 {
   141     if( aica_state.event_pending == 0 )
   142         armr.int_pending |= CPSR_F;
   143     aica_state.event_pending |= (1<<event);
   145     int pending = MMIO_READ( AICA2, AICA_IRQ );
   146     if( pending == 0 || event < pending )
   147         MMIO_WRITE( AICA2, AICA_IRQ, event );
   148 }
   150 void aica_clear_event( )
   151 {
   152     aica_state.clear_count++;
   153     if( aica_state.clear_count == 4 ) {
   154         int i;
   155         aica_state.clear_count = 0;
   157         for( i=0; i<8; i++ ) {
   158             if( aica_state.event_pending & (1<<i) ) {
   159                 aica_state.event_pending &= ~(1<<i);
   160                 break;
   161             }
   162         }
   163         for( ;i<8; i++ ) {
   164             if( aica_state.event_pending & (1<<i) ) {
   165                 MMIO_WRITE( AICA2, AICA_IRQ, i );
   166                 break;
   167             }
   168         }
   169         if( aica_state.event_pending == 0 )
   170             armr.int_pending &= ~CPSR_F;
   171     }
   172 }
   174 void aica_enable( void )
   175 {
   176     mmio_region_AICA2_write( AICA_RESET, MMIO_READ(AICA2,AICA_RESET) & ~1 );
   177 }
   179 /** Channel register structure:
   180  * 00  4  Channel config
   181  * 04  4  Waveform address lo (16 bits)
   182  * 08  4  Loop start address
   183  * 0C  4  Loop end address
   184  * 10  4  Volume envelope
   185  * 14  4  Init to 0x1F
   186  * 18  4  Frequency (floating point)
   187  * 1C  4  ?? 
   188  * 20  4  ??
   189  * 24  1  Pan
   190  * 25  1  ??
   191  * 26  
   192  * 27  
   193  * 28  1  ??
   194  * 29  1  Volume
   195  * 2C
   196  * 30
   197  */
   199 /* Write to channels 0-31 */
   200 MMIO_REGION_WRITE_FN( AICA0, reg, val )
   201 {
   202     reg &= 0xFFF;
   203     MMIO_WRITE( AICA0, reg, val );
   204     aica_write_channel( reg >> 7, reg % 128, val );
   205     //    DEBUG( "AICA0 Write %08X => %08X", val, reg );
   206 }
   208 /* Write to channels 32-64 */
   209 MMIO_REGION_WRITE_FN( AICA1, reg, val )
   210 {
   211     reg &= 0xFFF;
   212     MMIO_WRITE( AICA1, reg, val );
   213     aica_write_channel( (reg >> 7) + 32, reg % 128, val );
   214     // DEBUG( "AICA1 Write %08X => %08X", val, reg );
   215 }
   217 /**
   218  * AICA control registers 
   219  */
   220 MMIO_REGION_WRITE_FN( AICA2, reg, val )
   221 {
   222     uint32_t tmp;
   223     reg &= 0xFFF;
   225     switch( reg ) {
   226     case AICA_RESET:
   227         tmp = MMIO_READ( AICA2, AICA_RESET );
   228         if( (tmp & 1) == 1 && (val & 1) == 0 ) {
   229             /* ARM enabled - execute a core reset */
   230             DEBUG( "ARM enabled" );
   231             arm_reset();
   232             aica_state.samples_done = 0;
   233             aica_state.nanosecs_done = 0;
   234         } else if( (tmp&1) == 0 && (val&1) == 1 ) {
   235             DEBUG( "ARM disabled" );
   236         }
   237         MMIO_WRITE( AICA2, AICA_RESET, val );
   238         break;
   239     case AICA_IRQCLEAR:
   240         aica_clear_event();
   241         break;
   242     case AICA_FIFOIN: /* Read-only */
   243         break;
   244     default:
   245         MMIO_WRITE( AICA2, reg, val );
   246         break;
   247     }
   248 }
   250 MMIO_REGION_READ_FN( AICA2, reg )
   251 {
   252     audio_channel_t channel;
   253     uint32_t channo;
   254     int32_t val;
   255     reg &= 0xFFF;
   256     switch( reg ) {
   257     case AICA_CHANSTATE:
   258         channo = (MMIO_READ( AICA2, AICA_CHANSEL ) >> 8) & 0x3F;
   259         channel = audio_get_channel(channo);
   260         if( channel->loop == LOOP_LOOPED ) {
   261             val = 0x8000;
   262             channel->loop = LOOP_ON;
   263         } else {
   264             val = 0;
   265         }
   266         return val;
   267     case AICA_CHANPOSN:
   268         channo = (MMIO_READ( AICA2, AICA_CHANSEL ) >> 8) & 0x3F;
   269         channel = audio_get_channel(channo);
   270         return channel->posn;
   271     default:
   272         return MMIO_READ( AICA2, reg );
   273     }
   274 }
   276 MMIO_REGION_READ_FN( AICARTC, reg )
   277 {
   278     int32_t rv = 0;
   279     reg &= 0xFFF;
   280     switch( reg ) {
   281     case AICA_RTCHI:
   282         rv = (aica_state.time_of_day >> 16) & 0xFFFF;
   283         break;
   284     case AICA_RTCLO:
   285         rv = aica_state.time_of_day & 0xFFFF;
   286         break;
   287     }
   288     // DEBUG( "Read AICA RTC %d => %08X", reg, rv );
   289     return rv;
   290 }
   292 MMIO_REGION_WRITE_FN( AICARTC, reg, val )
   293 {
   294     reg &= 0xFFF;
   295     switch( reg ) {
   296     case AICA_RTCEN:
   297         MMIO_WRITE( AICARTC, reg, val&0x01 );
   298         break;
   299     case AICA_RTCLO:
   300         if( MMIO_READ( AICARTC, AICA_RTCEN ) & 0x01 ) {
   301             aica_state.time_of_day = (aica_state.time_of_day & 0xFFFF0000) | (val & 0xFFFF);
   302         }
   303         break;
   304     case AICA_RTCHI:
   305         if( MMIO_READ( AICARTC, AICA_RTCEN ) & 0x01 ) {
   306             aica_state.time_of_day = (aica_state.time_of_day & 0xFFFF) | (val<<16);
   307             MMIO_WRITE( AICARTC, AICA_RTCEN, 0 );
   308         }
   309         break;
   310     }
   311 }
   313 /**
   314  * Translate the channel frequency to a sample rate. The frequency is a
   315  * 14-bit floating point number, where bits 0..9 is the mantissa,
   316  * 11..14 is the signed exponent (-8 to +7). Bit 10 appears to
   317  * be unused.
   318  *
   319  * @return sample rate in samples per second.
   320  */
   321 uint32_t aica_frequency_to_sample_rate( uint32_t freq )
   322 {
   323     uint32_t exponent = (freq & 0x3800) >> 11;
   324     uint32_t mantissa = freq & 0x03FF;
   325     uint32_t rate;
   326     if( freq & 0x4000 ) {
   327         /* neg exponent - rate < 44100 */
   328         exponent = 8 - exponent;
   329         rate = (44100 >> exponent) +
   330         ((44100 * mantissa) >> (10+exponent));
   331     } else {
   332         /* pos exponent - rate > 44100 */
   333         rate = (44100 << exponent) +
   334         ((44100 * mantissa) >> (10-exponent));
   335     }
   336     return rate;
   337 }
   339 void aica_start_stop_channels()
   340 {
   341     int i;
   342     for( i=0; i<32; i++ ) {
   343         uint32_t val = MMIO_READ( AICA0, i<<7 );
   344         audio_start_stop_channel(i, val&0x4000);
   345     }
   346     for( ; i<64; i++ ) {
   347         uint32_t val = MMIO_READ( AICA1, (i-32)<<7 );
   348         audio_start_stop_channel(i, val&0x4000);
   349     }
   350 }
   352 /**
   353  * Derived directly from Dan Potter's log table
   354  */
   355 uint8_t aica_volume_table[256] = {
   356         0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,
   357         1,   1,   1,   1,   1,   1,   2,   2,   2,   2,   2,   3,   3,   3,   3,   4,
   358         4,   4,   4,   5,   5,   5,   5,   6,   6,   6,   7,   7,   7,   8,   8,   9,
   359         9,   9,  10,  10,  11,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  16,
   360         16,  17,  17,  18,  18,  19,  19,  20,  20,  21,  22,  22,  23,  23,  24,  25,
   361         25,  26,  27,  27,  28,  29,  29,  30,  31,  31,  32,  33,  34,  34,  35,  36,
   362         37,  37,  38,  39,  40,  40,  41,  42,  43,  44,  45,  45,  46,  47,  48,  49,
   363         50,  51,  52,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,
   364         65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  76,  77,  78,  79,  80,  81,
   365         82,  83,  85,  86,  87,  88,  89,  90,  92,  93,  94,  95,  97,  98,  99, 100,
   366         102, 103, 104, 105, 107, 108, 109, 111, 112, 113, 115, 116, 117, 119, 120, 121,
   367         123, 124, 126, 127, 128, 130, 131, 133, 134, 136, 137, 139, 140, 142, 143, 145,
   368         146, 148, 149, 151, 152, 154, 155, 157, 159, 160, 162, 163, 165, 167, 168, 170,
   369         171, 173, 175, 176, 178, 180, 181, 183, 185, 187, 188, 190, 192, 194, 195, 197,
   370         199, 201, 202, 204, 206, 208, 210, 211, 213, 215, 217, 219, 221, 223, 224, 226,
   371         228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 253, 254, 255 };
   374 void aica_write_channel( int channelNo, uint32_t reg, uint32_t val ) 
   375 {
   376     val &= 0x0000FFFF;
   377     audio_channel_t channel = audio_get_channel(channelNo);
   378     switch( reg ) {
   379     case 0x00: /* Config + high address bits*/
   380         channel->start = (channel->start & 0xFFFF) | ((val&0x1F) << 16);
   381         if( val & 0x200 ) 
   382             channel->loop = LOOP_ON;
   383         else 
   384             channel->loop = LOOP_OFF;
   385         switch( (val >> 7) & 0x03 ) {
   386         case 0:
   387             channel->sample_format = AUDIO_FMT_16BIT;
   388             break;
   389         case 1:
   390             channel->sample_format = AUDIO_FMT_8BIT;
   391             break;
   392         case 2:
   393         case 3:
   394             channel->sample_format = AUDIO_FMT_ADPCM;
   395             break;
   396         }
   397         if( val & 0x8000 ) {
   398             aica_start_stop_channels();
   399         }
   400         break;
   401         case 0x04: /* Low 16 address bits */
   402             channel->start = (channel->start & 0x001F0000) | val;
   403             break;
   404         case 0x08: /* Loop start */
   405             channel->loop_start = val;
   406             break;
   407         case 0x0C: /* End */
   408             channel->end = val;
   409             break;
   410         case 0x10: /* Envelope register 1 */
   411             break;
   412         case 0x14: /* Envelope register 2 */
   413             break;
   414         case 0x18: /* Frequency */
   415             channel->sample_rate = aica_frequency_to_sample_rate ( val );
   416             break;
   417         case 0x1C: /* ??? */
   418         case 0x20: /* ??? */
   419         case 0x24: /* Volume? /pan */
   420             val = val & 0x1F;
   421             if( val <= 0x0F ) 
   422                 val = 0x0F - val; /* Convert to smooth pan over 0..31 */
   423             channel->pan = val;
   424             break;
   425         case 0x28: /* Volume */
   426             // This isn't remotely correct, but it will have to suffice until I have
   427             // time to figure out what's actually going on here... 
   428             channel->vol = aica_volume_table[max((val & 0xFF),((val>>8)&0xFF))];
   429             break;
   430         default: /* ??? */
   431             break;
   432     }
   434 }
.