Search
lxdream.org :: lxdream/src/aica/aica.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/aica.c
changeset 434:8af49a412d92
prev431:248dd77a9e44
next463:0655796f9bb5
author nkeynes
date Sun Oct 21 05:31:07 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Rename mmr_win.c to mmio_win.c
view annotate diff log raw
     1 /**
     2  * $Id: aica.c,v 1.23 2007-10-09 11:37:36 nkeynes Exp $
     3  * 
     4  * This is the core sound system (ie the bit which does the actual work)
     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  */
    19 #define MODULE aica_module
    21 #include <time.h>
    22 #include "dream.h"
    23 #include "dreamcast.h"
    24 #include "mem.h"
    25 #include "aica/aica.h"
    26 #include "armcore.h"
    27 #include "aica/audio.h"
    28 #define MMIO_IMPL
    29 #include "aica.h"
    31 MMIO_REGION_READ_DEFFN( AICA0 )
    32 MMIO_REGION_READ_DEFFN( AICA1 )
    33 MMIO_REGION_READ_DEFFN( AICA2 )
    35 void aica_init( void );
    36 void aica_reset( void );
    37 void aica_start( void );
    38 void aica_stop( void );
    39 void aica_save_state( FILE *f );
    40 int aica_load_state( FILE *f );
    41 uint32_t aica_run_slice( uint32_t );
    43 struct dreamcast_module aica_module = { "AICA", aica_init, aica_reset, 
    44 					aica_start, aica_run_slice, aica_stop,
    45 					aica_save_state, aica_load_state };
    47 /* 20 years in seconds */
    48 #define RTC_OFFSET 631152000
    49 unsigned int aica_time_of_day = 0;
    51 /**
    52  * Initialize the AICA subsystem. Note requires that 
    53  */
    54 void aica_init( void )
    55 {
    56     register_io_regions( mmio_list_spu );
    57     MMIO_NOTRACE(AICA0);
    58     MMIO_NOTRACE(AICA1);
    59     arm_mem_init();
    60     aica_reset();
    61 }
    63 void aica_reset( void )
    64 {
    65     arm_reset();
    66     aica_event(2); /* Pre-deliver a timer interrupt */
    67     aica_time_of_day = 0x5bfc8900;
    68 }
    70 void aica_start( void )
    71 {
    73 }
    75 /**
    76  * Keep track of what we've done so far this second, to try to keep the
    77  * precision of samples/second.
    78  */
    79 int samples_done = 0;
    80 uint32_t nanosecs_done = 0;
    82 uint32_t aica_run_slice( uint32_t nanosecs )
    83 {
    84     /* Run arm instructions */
    85     int reset = MMIO_READ( AICA2, AICA_RESET );
    86     if( (reset & 1) == 0 ) { /* Running */
    87 	int num_samples = (int)((uint64_t)AICA_SAMPLE_RATE * (nanosecs_done + nanosecs) / 1000000000) - samples_done;
    88 	num_samples = arm_run_slice( num_samples );
    89 	audio_mix_samples( num_samples );
    91 	samples_done += num_samples;
    92 	nanosecs_done += nanosecs;
    93     }
    94     if( nanosecs_done > 1000000000 ) {
    95 	samples_done -= AICA_SAMPLE_RATE;
    96 	nanosecs_done -= 1000000000;
    97 	aica_time_of_day++;
    98     }
    99     return nanosecs;
   100 }
   102 void aica_stop( void )
   103 {
   105 }
   107 void aica_save_state( FILE *f )
   108 {
   109     arm_save_state( f );
   110 }
   112 int aica_load_state( FILE *f )
   113 {
   114     return arm_load_state( f );
   115 }
   117 int aica_event_pending = 0;
   118 int aica_clear_count = 0;
   120 /* Note: This is probably not necessarily technically correct but it should
   121  * work in the meantime.
   122  */
   124 void aica_event( int event )
   125 {
   126     if( aica_event_pending == 0 )
   127 	armr.int_pending |= CPSR_F;
   128     aica_event_pending |= (1<<event);
   130     int pending = MMIO_READ( AICA2, AICA_IRQ );
   131     if( pending == 0 || event < pending )
   132 	MMIO_WRITE( AICA2, AICA_IRQ, event );
   133 }
   135 void aica_clear_event( )
   136 {
   137     aica_clear_count++;
   138     if( aica_clear_count == 4 ) {
   139 	int i;
   140 	aica_clear_count = 0;
   142 	for( i=0; i<8; i++ ) {
   143 	    if( aica_event_pending & (1<<i) ) {
   144 		aica_event_pending &= ~(1<<i);
   145 		break;
   146 	    }
   147 	}
   148 	for( ;i<8; i++ ) {
   149 	    if( aica_event_pending & (1<<i) ) {
   150 		MMIO_WRITE( AICA2, AICA_IRQ, i );
   151 		break;
   152 	    }
   153 	}
   154 	if( aica_event_pending == 0 )
   155 	    armr.int_pending &= ~CPSR_F;
   156     }
   157 }
   159 void aica_enable( void )
   160 {
   161     mmio_region_AICA2_write( AICA_RESET, MMIO_READ(AICA2,AICA_RESET) & ~1 );
   162 }
   164 /** Channel register structure:
   165  * 00  4  Channel config
   166  * 04  4  Waveform address lo (16 bits)
   167  * 08  4  Loop start address
   168  * 0C  4  Loop end address
   169  * 10  4  Volume envelope
   170  * 14  4  Init to 0x1F
   171  * 18  4  Frequency (floating point)
   172  * 1C  4  ?? 
   173  * 20  4  ??
   174  * 24  1  Pan
   175  * 25  1  ??
   176  * 26  
   177  * 27  
   178  * 28  1  ??
   179  * 29  1  Volume
   180  * 2C
   181  * 30
   182  */
   184 /* Write to channels 0-31 */
   185 void mmio_region_AICA0_write( uint32_t reg, uint32_t val )
   186 {
   187     MMIO_WRITE( AICA0, reg, val );
   188     aica_write_channel( reg >> 7, reg % 128, val );
   189     //    DEBUG( "AICA0 Write %08X => %08X", val, reg );
   190 }
   192 /* Write to channels 32-64 */
   193 void mmio_region_AICA1_write( uint32_t reg, uint32_t val )
   194 {
   195     MMIO_WRITE( AICA1, reg, val );
   196     aica_write_channel( (reg >> 7) + 32, reg % 128, val );
   197     // DEBUG( "AICA1 Write %08X => %08X", val, reg );
   198 }
   200 /**
   201  * AICA control registers 
   202  */
   203 void mmio_region_AICA2_write( uint32_t reg, uint32_t val )
   204 {
   205     uint32_t tmp;
   206     switch( reg ) {
   207     case AICA_RESET:
   208 	tmp = MMIO_READ( AICA2, AICA_RESET );
   209 	if( (tmp & 1) == 1 && (val & 1) == 0 ) {
   210 	    /* ARM enabled - execute a core reset */
   211 	    DEBUG( "ARM enabled" );
   212 	    arm_reset();
   213 	    samples_done = 0;
   214 	    nanosecs_done = 0;
   215 	} else if( (tmp&1) == 0 && (val&1) == 1 ) {
   216 	    DEBUG( "ARM disabled" );
   217 	}
   218 	MMIO_WRITE( AICA2, AICA_RESET, val );
   219 	break;
   220     case AICA_IRQCLEAR:
   221 	aica_clear_event();
   222 	break;
   223     default:
   224 	MMIO_WRITE( AICA2, reg, val );
   225 	break;
   226     }
   227 }
   230 int32_t mmio_region_AICARTC_read( uint32_t reg )
   231 {
   232     int32_t rv = 0;
   233     switch( reg ) {
   234     case AICA_RTCHI:
   235         rv = (aica_time_of_day >> 16) & 0xFFFF;
   236 	break;
   237     case AICA_RTCLO:
   238 	rv = aica_time_of_day & 0xFFFF;
   239 	break;
   240     }
   241     // DEBUG( "Read AICA RTC %d => %08X", reg, rv );
   242     return rv;
   243 }
   246 void mmio_region_AICARTC_write( uint32_t reg, uint32_t val )
   247 {
   248     switch( reg ) {
   249     case AICA_RTCEN:
   250 	MMIO_WRITE( AICARTC, reg, val&0x01 );
   251 	break;
   252     case AICA_RTCLO:
   253 	if( MMIO_READ( AICARTC, AICA_RTCEN ) & 0x01 ) {
   254 	    aica_time_of_day = (aica_time_of_day & 0xFFFF0000) | (val & 0xFFFF);
   255 	}
   256 	break;
   257     case AICA_RTCHI:
   258 	if( MMIO_READ( AICARTC, AICA_RTCEN ) & 0x01 ) {
   259 	    aica_time_of_day = (aica_time_of_day & 0xFFFF) | (val<<16);
   260 	    MMIO_WRITE( AICARTC, AICA_RTCEN, 0 );
   261 	}
   262 	break;
   263     }
   264 }
   266 /**
   267  * Translate the channel frequency to a sample rate. The frequency is a
   268  * 14-bit floating point number, where bits 0..9 is the mantissa,
   269  * 11..14 is the signed exponent (-8 to +7). Bit 10 appears to
   270  * be unused.
   271  *
   272  * @return sample rate in samples per second.
   273  */
   274 uint32_t aica_frequency_to_sample_rate( uint32_t freq )
   275 {
   276     uint32_t exponent = (freq & 0x3800) >> 11;
   277     uint32_t mantissa = freq & 0x03FF;
   278     uint32_t rate;
   279     if( freq & 0x4000 ) {
   280 	/* neg exponent - rate < 44100 */
   281 	exponent = 8 - exponent;
   282 	rate = (44100 >> exponent) +
   283 	    ((44100 * mantissa) >> (10+exponent));
   284     } else {
   285 	/* pos exponent - rate > 44100 */
   286 	rate = (44100 << exponent) +
   287 	    ((44100 * mantissa) >> (10-exponent));
   288     }
   289     return rate;
   290 }
   292 void aica_start_stop_channels()
   293 {
   294     int i;
   295     for( i=0; i<32; i++ ) {
   296 	uint32_t val = MMIO_READ( AICA0, i<<7 );
   297 	audio_start_stop_channel(i, val&0x4000);
   298     }
   299     for( ; i<64; i++ ) {
   300 	uint32_t val = MMIO_READ( AICA1, (i-32)<<7 );
   301 	audio_start_stop_channel(i, val&0x4000);
   302     }
   303 }
   305 /**
   306  * Derived directly from Dan Potter's log table
   307  */
   308 uint8_t aica_volume_table[256] = {
   309       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,
   310       1,   1,   1,   1,   1,   1,   2,   2,   2,   2,   2,   3,   3,   3,   3,   4,
   311       4,   4,   4,   5,   5,   5,   5,   6,   6,   6,   7,   7,   7,   8,   8,   9,
   312       9,   9,  10,  10,  11,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  16,
   313      16,  17,  17,  18,  18,  19,  19,  20,  20,  21,  22,  22,  23,  23,  24,  25,
   314      25,  26,  27,  27,  28,  29,  29,  30,  31,  31,  32,  33,  34,  34,  35,  36,
   315      37,  37,  38,  39,  40,  40,  41,  42,  43,  44,  45,  45,  46,  47,  48,  49,
   316      50,  51,  52,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,
   317      65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  76,  77,  78,  79,  80,  81,
   318      82,  83,  85,  86,  87,  88,  89,  90,  92,  93,  94,  95,  97,  98,  99, 100,
   319     102, 103, 104, 105, 107, 108, 109, 111, 112, 113, 115, 116, 117, 119, 120, 121,
   320     123, 124, 126, 127, 128, 130, 131, 133, 134, 136, 137, 139, 140, 142, 143, 145,
   321     146, 148, 149, 151, 152, 154, 155, 157, 159, 160, 162, 163, 165, 167, 168, 170,
   322     171, 173, 175, 176, 178, 180, 181, 183, 185, 187, 188, 190, 192, 194, 195, 197,
   323     199, 201, 202, 204, 206, 208, 210, 211, 213, 215, 217, 219, 221, 223, 224, 226,
   324     228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 253, 254, 255 };
   327 void aica_write_channel( int channelNo, uint32_t reg, uint32_t val ) 
   328 {
   329     val &= 0x0000FFFF;
   330     audio_channel_t channel = audio_get_channel(channelNo);
   331     switch( reg ) {
   332     case 0x00: /* Config + high address bits*/
   333 	channel->start = (channel->start & 0xFFFF) | ((val&0x1F) << 16);
   334 	if( val & 0x200 ) 
   335 	    channel->loop = TRUE;
   336 	else 
   337 	    channel->loop = FALSE;
   338 	switch( (val >> 7) & 0x03 ) {
   339 	case 0:
   340 	    channel->sample_format = AUDIO_FMT_16BIT;
   341 	    break;
   342 	case 1:
   343 	    channel->sample_format = AUDIO_FMT_8BIT;
   344 	    break;
   345 	case 2:
   346 	case 3:
   347 	    channel->sample_format = AUDIO_FMT_ADPCM;
   348 	    break;
   349 	}
   350 	if( val & 0x8000 ) {
   351 	    aica_start_stop_channels();
   352 	}
   353 	break;
   354     case 0x04: /* Low 16 address bits */
   355 	channel->start = (channel->start & 0x001F0000) | val;
   356 	break;
   357     case 0x08: /* Loop start */
   358 	channel->loop_start = val;
   359 	break;
   360     case 0x0C: /* End */
   361 	channel->end = val;
   362 	break;
   363     case 0x10: /* Envelope register 1 */
   364 	break;
   365     case 0x14: /* Envelope register 2 */
   366 	break;
   367     case 0x18: /* Frequency */
   368 	channel->sample_rate = aica_frequency_to_sample_rate ( val );
   369 	break;
   370     case 0x1C: /* ??? */
   371     case 0x20: /* ??? */
   372     case 0x24: /* Volume? /pan */
   373 	val = val & 0x1F;
   374 	if( val <= 0x0F ) 
   375 	    val = 0x0F - val; /* Convert to smooth pan over 0..31 */
   376 	channel->pan = val;
   377 	break;
   378     case 0x28: /* Volume */
   379 	channel->vol = aica_volume_table[val & 0xFF];
   380 	break;
   381     default: /* ??? */
   382 	break;
   383     }
   385 }
.