Search
lxdream.org :: lxdream/src/aica/aica.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/aica.c
changeset 66:2ec5b6eb75e5
prev61:eb7a73c9bcae
next73:0bb57e51ac9e
author nkeynes
date Tue Jan 10 13:56:54 2006 +0000 (16 years ago)
permissions -rw-r--r--
last change Go go gadget audio!
Slow, but it works :)
view annotate diff log raw
     1 /**
     2  * $Id: aica.c,v 1.11 2006-01-10 13:56:54 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 "dream.h"
    22 #include "dreamcast.h"
    23 #include "mem.h"
    24 #include "aica.h"
    25 #include "armcore.h"
    26 #include "audio.h"
    27 #define MMIO_IMPL
    28 #include "aica.h"
    30 MMIO_REGION_READ_DEFFN( AICA0 )
    31 MMIO_REGION_READ_DEFFN( AICA1 )
    32 MMIO_REGION_READ_DEFFN( AICA2 )
    34 void aica_init( void );
    35 void aica_reset( void );
    36 void aica_start( void );
    37 void aica_stop( void );
    38 void aica_save_state( FILE *f );
    39 int aica_load_state( FILE *f );
    40 uint32_t aica_run_slice( uint32_t );
    42 #define IS_TIMER_ENABLED() (MMIO_READ( AICA2, AICA_TCR ) & 0x40)
    44 struct dreamcast_module aica_module = { "AICA", aica_init, aica_reset, 
    45 					aica_start, aica_run_slice, aica_stop,
    46 					aica_save_state, aica_load_state };
    48 /**
    49  * Initialize the AICA subsystem. Note requires that 
    50  */
    51 void aica_init( void )
    52 {
    53     register_io_regions( mmio_list_spu );
    54     MMIO_NOTRACE(AICA0);
    55     MMIO_NOTRACE(AICA1);
    56     arm_mem_init();
    57     aica_reset();
    58     audio_set_output( &esd_audio_driver, 44100, AUDIO_FMT_16BIT|AUDIO_FMT_STEREO );
    59 }
    61 void aica_reset( void )
    62 {
    63     arm_reset();
    64     aica_event(2); /* Pre-deliver a timer interrupt */
    65 }
    67 void aica_start( void )
    68 {
    70 }
    72 /**
    73  * Keep track of what we've done so far this second, to try to keep the
    74  * precision of samples/second.
    75  */
    76 int samples_done = 0;
    77 uint32_t nanosecs_done = 0;
    79 uint32_t aica_run_slice( uint32_t nanosecs )
    80 {
    81     /* Run arm instructions */
    82     int reset = MMIO_READ( AICA2, AICA_RESET );
    83     if( (reset & 1) == 0 ) { /* Running */
    84 	int num_samples = (nanosecs_done + nanosecs) / AICA_SAMPLE_RATE - samples_done;
    85 	int i;
    86 	for( i=0; i<num_samples; i++ ) {
    87 	    nanosecs = arm_run_slice( AICA_SAMPLE_PERIOD );
    88 	    audio_mix_sample();
    89 	    if( IS_TIMER_ENABLED() ) {
    90 		uint8_t val = MMIO_READ( AICA2, AICA_TIMER );
    91 		val++;
    92 		if( val == 0 )
    93 		    aica_event( AICA_EVENT_TIMER );
    94 		MMIO_WRITE( AICA2, AICA_TIMER, val );
    95 	    }
    96 	    if( !dreamcast_is_running() )
    97 		break;
    98 	}
    99 	samples_done += num_samples;
   100 	nanosecs_done += nanosecs;
   101     }
   102     return nanosecs;
   103 }
   105 void aica_stop( void )
   106 {
   108 }
   110 void aica_save_state( FILE *f )
   111 {
   112     arm_save_state( f );
   113 }
   115 int aica_load_state( FILE *f )
   116 {
   117     return arm_load_state( f );
   118 }
   120 int aica_event_pending = 0;
   121 int aica_clear_count = 0;
   123 /* Note: This is probably not necessarily technically correct but it should
   124  * work in the meantime.
   125  */
   127 void aica_event( int event )
   128 {
   129     if( aica_event_pending == 0 )
   130 	armr.int_pending |= CPSR_F;
   131     aica_event_pending |= (1<<event);
   133     int pending = MMIO_READ( AICA2, AICA_IRQ );
   134     if( pending == 0 || event < pending )
   135 	MMIO_WRITE( AICA2, AICA_IRQ, event );
   136 }
   138 void aica_clear_event( )
   139 {
   140     aica_clear_count++;
   141     if( aica_clear_count == 4 ) {
   142 	int i;
   143 	aica_clear_count = 0;
   145 	for( i=0; i<8; i++ ) {
   146 	    if( aica_event_pending & (1<<i) ) {
   147 		aica_event_pending &= ~(1<<i);
   148 		break;
   149 	    }
   150 	}
   151 	for( ;i<8; i++ ) {
   152 	    if( aica_event_pending & (1<<i) ) {
   153 		MMIO_WRITE( AICA2, AICA_IRQ, i );
   154 		break;
   155 	    }
   156 	}
   157 	if( aica_event_pending == 0 )
   158 	    armr.int_pending &= ~CPSR_F;
   159     }
   160 }
   162 /** Channel register structure:
   163  * 00  4  Channel config
   164  * 04  4  Waveform address lo (16 bits)
   165  * 08  4  Loop start address
   166  * 0C  4  Loop end address
   167  * 10  4  Volume envelope
   168  * 14  4  Init to 0x1F
   169  * 18  4  Frequency (floating point)
   170  * 1C  4  ?? 
   171  * 20  4  ??
   172  * 24  1  Pan
   173  * 25  1  ??
   174  * 26  
   175  * 27  
   176  * 28  1  ??
   177  * 29  1  Volume
   178  * 2C
   179  * 30
   180  * 
   182 /* Write to channels 0-31 */
   183 void mmio_region_AICA0_write( uint32_t reg, uint32_t val )
   184 {
   185     MMIO_WRITE( AICA0, reg, val );
   186     aica_write_channel( reg >> 7, reg % 128, val );
   187     //    DEBUG( "AICA0 Write %08X => %08X", val, reg );
   188 }
   190 /* Write to channels 32-64 */
   191 void mmio_region_AICA1_write( uint32_t reg, uint32_t val )
   192 {
   193     MMIO_WRITE( AICA1, reg, val );
   194     aica_write_channel( (reg >> 7) + 32, reg % 128, val );
   195     // DEBUG( "AICA1 Write %08X => %08X", val, reg );
   196 }
   198 /**
   199  * AICA control registers 
   200  */
   201 void mmio_region_AICA2_write( uint32_t reg, uint32_t val )
   202 {
   203     uint32_t tmp;
   204     switch( reg ) {
   205     case AICA_RESET:
   206 	tmp = MMIO_READ( AICA2, AICA_RESET );
   207 	if( (tmp & 1) == 1 && (val & 1) == 0 ) {
   208 	    /* ARM enabled - execute a core reset */
   209 	    DEBUG( "ARM enabled" );
   210 	    arm_reset();
   211 	    samples_done = 0;
   212 	    nanosecs_done = 0;
   213 	} else if( (tmp&1) == 0 && (val&1) == 1 ) {
   214 	    DEBUG( "ARM disabled" );
   215 	}
   216 	MMIO_WRITE( AICA2, AICA_RESET, val );
   217 	break;
   218     case AICA_IRQCLEAR:
   219 	aica_clear_event();
   220 	break;
   221     default:
   222 	MMIO_WRITE( AICA2, reg, val );
   223 	break;
   224     }
   225 }
   227 /**
   228  * Translate the channel frequency to a sample rate. The frequency is a
   229  * 14-bit floating point number, where bits 0..9 is the mantissa,
   230  * 11..14 is the signed exponent (-8 to +7). Bit 10 appears to
   231  * be unused.
   232  *
   233  * @return sample rate in samples per second.
   234  */
   235 uint32_t aica_frequency_to_sample_rate( uint32_t freq )
   236 {
   237     uint32_t exponent = (freq & 0x3800) >> 11;
   238     uint32_t mantissa = freq & 0x03FF;
   239     if( freq & 0x4000 ) {
   240 	/* neg exponent - rate < 44100 */
   241 	exponent = 8 - exponent;
   242 	return (44100 >> exponent) +
   243 	    ((44100 * mantissa) >> (10+exponent));
   244     } else {
   245 	/* pos exponent - rate > 44100 */
   246 	return (44100 << exponent) +
   247 	    ((44100 * mantissa) >> (10-exponent));
   248     }
   249 }
   251 void aica_write_channel( int channelNo, uint32_t reg, uint32_t val ) 
   252 {
   253     val &= 0x0000FFFF;
   254     audio_channel_t channel = audio_get_channel(channelNo);
   255     switch( reg ) {
   256     case 0x00: /* Config + high address bits*/
   257 	channel->start = (channel->start & 0xFFFF) | ((val&0x1F) << 16);
   258 	if( val & 0x200 ) 
   259 	    channel->loop_count = -1;
   260 	else 
   261 	    channel->loop_count = 0;
   262 	switch( (val >> 7) & 0x03 ) {
   263 	case 0:
   264 	    channel->sample_format = AUDIO_FMT_16BIT;
   265 	    break;
   266 	case 1:
   267 	    channel->sample_format = AUDIO_FMT_8BIT;
   268 	    break;
   269 	case 2:
   270 	case 3:
   271 	    channel->sample_format = AUDIO_FMT_ADPCM;
   272 	    break;
   273 	}
   274 	switch( (val >> 14) & 0x03 ) {
   275 	case 2: 
   276 	    audio_stop_channel( channelNo ); 
   277 	    break;
   278 	case 3: 
   279 	    audio_start_channel( channelNo ); 
   280 	    break;
   281 	default:
   282 	    break;
   283 	    /* Hrmm... */
   284 	}
   285 	break;
   286     case 0x04: /* Low 16 address bits */
   287 	channel->start = (channel->start & 0x001F0000) | val;
   288 	break;
   289     case 0x08: /* Loop start */
   290 	channel->loop_start = val;
   291 	break;
   292     case 0x0C: /* Loop end */
   293 	channel->loop_end = channel->end = val;
   294 	break;
   295     case 0x10: /* Envelope register 1 */
   296 	break;
   297     case 0x14: /* Envelope register 2 */
   298 	break;
   299     case 0x18: /* Frequency */
   300 	channel->sample_rate = aica_frequency_to_sample_rate ( val );
   301 	break;
   302     case 0x1C: /* ??? */
   303     case 0x20: /* ??? */
   304     case 0x24: /* Volume? /pan */
   305 	break;
   306     case 0x28: /* Volume */
   307 	channel->vol_left = channel->vol_right = val & 0xFF;
   308 	break;
   309     default: /* ??? */
   310 	break;
   311     }
   313 }
.