nkeynes@11: /** nkeynes@44: * $Id: aica.c,v 1.9 2005-12-26 11:52:56 nkeynes Exp $ nkeynes@11: * nkeynes@11: * This is the core sound system (ie the bit which does the actual work) nkeynes@11: * nkeynes@11: * Copyright (c) 2005 Nathan Keynes. nkeynes@11: * nkeynes@11: * This program is free software; you can redistribute it and/or modify nkeynes@11: * it under the terms of the GNU General Public License as published by nkeynes@11: * the Free Software Foundation; either version 2 of the License, or nkeynes@11: * (at your option) any later version. nkeynes@11: * nkeynes@11: * This program is distributed in the hope that it will be useful, nkeynes@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@11: * GNU General Public License for more details. nkeynes@11: */ nkeynes@11: nkeynes@35: #define MODULE aica_module nkeynes@35: nkeynes@11: #include "dream.h" nkeynes@15: #include "mem.h" nkeynes@11: #include "aica.h" nkeynes@11: #define MMIO_IMPL nkeynes@11: #include "aica.h" nkeynes@11: nkeynes@11: MMIO_REGION_READ_DEFFN( AICA0 ) nkeynes@11: MMIO_REGION_READ_DEFFN( AICA1 ) nkeynes@11: MMIO_REGION_READ_DEFFN( AICA2 ) nkeynes@11: nkeynes@23: void aica_init( void ); nkeynes@23: void aica_reset( void ); nkeynes@23: void aica_start( void ); nkeynes@23: void aica_stop( void ); nkeynes@35: void aica_save_state( FILE *f ); nkeynes@35: int aica_load_state( FILE *f ); nkeynes@30: uint32_t aica_run_slice( uint32_t ); nkeynes@23: nkeynes@23: nkeynes@23: struct dreamcast_module aica_module = { "AICA", aica_init, aica_reset, nkeynes@23: aica_start, aica_run_slice, aica_stop, nkeynes@35: aica_save_state, aica_load_state }; nkeynes@15: nkeynes@11: /** nkeynes@11: * Initialize the AICA subsystem. Note requires that nkeynes@11: */ nkeynes@11: void aica_init( void ) nkeynes@11: { nkeynes@11: register_io_regions( mmio_list_spu ); nkeynes@11: MMIO_NOTRACE(AICA0); nkeynes@11: MMIO_NOTRACE(AICA1); nkeynes@11: arm_mem_init(); nkeynes@37: arm_reset(); nkeynes@11: } nkeynes@11: nkeynes@11: void aica_reset( void ) nkeynes@11: { nkeynes@35: arm_reset(); nkeynes@11: } nkeynes@11: nkeynes@23: void aica_start( void ) nkeynes@23: { nkeynes@23: nkeynes@23: } nkeynes@23: nkeynes@30: uint32_t aica_run_slice( uint32_t nanosecs ) nkeynes@23: { nkeynes@23: /* Run arm instructions */ nkeynes@35: int reset = MMIO_READ( AICA2, AICA_RESET ); nkeynes@44: if( (reset & 1) == 0 ) { nkeynes@35: /* Running */ nkeynes@43: nanosecs = arm_run_slice( nanosecs ); nkeynes@35: } nkeynes@23: /* Generate audio buffer */ nkeynes@43: return nanosecs; nkeynes@23: } nkeynes@23: nkeynes@23: void aica_stop( void ) nkeynes@23: { nkeynes@23: nkeynes@23: } nkeynes@23: nkeynes@35: void aica_save_state( FILE *f ) nkeynes@35: { nkeynes@35: arm_save_state( f ); nkeynes@35: } nkeynes@35: nkeynes@35: int aica_load_state( FILE *f ) nkeynes@35: { nkeynes@35: return arm_load_state( f ); nkeynes@35: } nkeynes@35: nkeynes@11: /** Channel register structure: nkeynes@43: * 00 4 Channel config nkeynes@43: * 04 4 Waveform address lo (16 bits) nkeynes@11: * 08 4 Loop start address nkeynes@11: * 0C 4 Loop end address nkeynes@11: * 10 4 Volume envelope nkeynes@43: * 14 4 Init to 0x1F nkeynes@43: * 18 4 Frequency (floating point) nkeynes@43: * 1C 4 ?? nkeynes@43: * 20 4 ?? nkeynes@11: * 24 1 Pan nkeynes@11: * 25 1 ?? nkeynes@11: * 26 nkeynes@11: * 27 nkeynes@11: * 28 1 ?? nkeynes@11: * 29 1 Volume nkeynes@11: * 2C nkeynes@11: * 30 nkeynes@11: * nkeynes@11: nkeynes@11: /* Write to channels 0-31 */ nkeynes@11: void mmio_region_AICA0_write( uint32_t reg, uint32_t val ) nkeynes@11: { nkeynes@11: // aica_write_channel( reg >> 7, reg % 128, val ); nkeynes@35: MMIO_WRITE( AICA0, reg, val ); nkeynes@37: // DEBUG( "AICA0 Write %08X => %08X", val, reg ); nkeynes@11: } nkeynes@11: nkeynes@11: /* Write to channels 32-64 */ nkeynes@11: void mmio_region_AICA1_write( uint32_t reg, uint32_t val ) nkeynes@11: { nkeynes@11: // aica_write_channel( (reg >> 7) + 32, reg % 128, val ); nkeynes@35: MMIO_WRITE( AICA1, reg, val ); nkeynes@37: // DEBUG( "AICA1 Write %08X => %08X", val, reg ); nkeynes@11: } nkeynes@11: nkeynes@11: /* General registers */ nkeynes@11: void mmio_region_AICA2_write( uint32_t reg, uint32_t val ) nkeynes@11: { nkeynes@35: uint32_t tmp; nkeynes@35: switch( reg ) { nkeynes@35: case AICA_RESET: nkeynes@35: tmp = MMIO_READ( AICA2, AICA_RESET ); nkeynes@37: if( (tmp & 1) == 1 && (val & 1) == 0 ) { nkeynes@35: /* ARM enabled - execute a core reset */ nkeynes@37: DEBUG( "ARM enabled" ); nkeynes@35: arm_reset(); nkeynes@37: } else if( (tmp&1) == 0 && (val&1) == 1 ) { nkeynes@37: DEBUG( "ARM disabled" ); nkeynes@35: } nkeynes@35: MMIO_WRITE( AICA2, AICA_RESET, val ); nkeynes@35: break; nkeynes@35: default: nkeynes@35: MMIO_WRITE( AICA2, reg, val ); nkeynes@35: break; nkeynes@35: } nkeynes@11: }