166 lines
4.3 KiB
C
166 lines
4.3 KiB
C
/* ay.c: AY-8-3912 routines
|
|
Copyright (c) 1999-2004 Philip Kendall
|
|
|
|
$Id: ay.c 3494 2008-01-15 16:37:50Z pak21 $
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
Author contact information:
|
|
|
|
E-mail: philip-fuse@shadowmagic.org.uk
|
|
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "compat.h"
|
|
#include "machine.h"
|
|
#include "module.h"
|
|
#include "printer.h"
|
|
#include "psg.h"
|
|
#include "sound.h"
|
|
|
|
/* Unused bits in the AY registers are silently zeroed out; these masks
|
|
accomplish this */
|
|
static const libspectrum_byte mask[ AY_REGISTERS ] = {
|
|
|
|
0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0xff,
|
|
0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff,
|
|
|
|
};
|
|
|
|
static void ay_reset( int hard_reset );
|
|
static void ay_from_snapshot( libspectrum_snap *snap );
|
|
static void ay_to_snapshot( libspectrum_snap *snap );
|
|
|
|
static module_info_t ay_module_info = {
|
|
|
|
ay_reset,
|
|
NULL,
|
|
NULL,
|
|
ay_from_snapshot,
|
|
ay_to_snapshot,
|
|
|
|
};
|
|
|
|
int
|
|
ay_init( void )
|
|
{
|
|
module_register( &ay_module_info );
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
ay_reset( int hard_reset GCC_UNUSED )
|
|
{
|
|
ayinfo *ay = &machine_current->ay;
|
|
|
|
ay->current_register = 0;
|
|
memset( ay->registers, 0, sizeof( ay->registers ) );
|
|
}
|
|
|
|
/* What happens when the AY register port (traditionally 0xfffd on the 128K
|
|
machines) is read from */
|
|
libspectrum_byte
|
|
ay_registerport_read( libspectrum_word port GCC_UNUSED, int *attached )
|
|
{
|
|
int current;
|
|
const libspectrum_byte port_input = 0xbf; /* always allow serial output */
|
|
|
|
*attached = 1;
|
|
|
|
current = machine_current->ay.current_register;
|
|
|
|
/* The AY I/O ports return input directly from the port when in
|
|
input mode; but in output mode, they return an AND between the
|
|
register value and the port input. So, allow for this when
|
|
reading R14... */
|
|
|
|
if( current == 14 ) {
|
|
if(machine_current->ay.registers[7] & 0x40)
|
|
return (port_input & machine_current->ay.registers[14]);
|
|
else
|
|
return port_input;
|
|
}
|
|
|
|
/* R15 is simpler to do, as the 8912 lacks the second I/O port, and
|
|
the input-mode input is always 0xff */
|
|
if( current == 15 && !( machine_current->ay.registers[7] & 0x80 ) )
|
|
return 0xff;
|
|
|
|
/* Otherwise return register value, appropriately masked */
|
|
return machine_current->ay.registers[ current ] & mask[ current ];
|
|
}
|
|
|
|
/* And when it's written to */
|
|
void
|
|
ay_registerport_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
|
|
{
|
|
machine_current->ay.current_register = (b & 15);
|
|
}
|
|
|
|
/* What happens when the AY data port (traditionally 0xbffd on the 128K
|
|
machines) is written to; no corresponding read function as this
|
|
always returns 0xff */
|
|
void
|
|
ay_dataport_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
|
|
{
|
|
int current;
|
|
|
|
current = machine_current->ay.current_register;
|
|
|
|
machine_current->ay.registers[ current ] = b & mask[ current ];
|
|
sound_ay_write( current, b, tstates );
|
|
if( psg_recording ) psg_write_register( current, b );
|
|
|
|
if( current == 14 ) printer_serial_write( b );
|
|
}
|
|
|
|
static void
|
|
ay_from_snapshot( libspectrum_snap *snap )
|
|
{
|
|
size_t i;
|
|
|
|
if( machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_AY ) {
|
|
|
|
ay_registerport_write( 0xfffd,
|
|
libspectrum_snap_out_ay_registerport( snap ) );
|
|
|
|
for( i = 0; i < AY_REGISTERS; i++ ) {
|
|
machine_current->ay.registers[i] =
|
|
libspectrum_snap_ay_registers( snap, i );
|
|
sound_ay_write( i, machine_current->ay.registers[i], 0 );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
static void
|
|
ay_to_snapshot( libspectrum_snap *snap )
|
|
{
|
|
size_t i;
|
|
|
|
libspectrum_snap_set_out_ay_registerport(
|
|
snap, machine_current->ay.current_register
|
|
);
|
|
|
|
for( i = 0; i < AY_REGISTERS; i++ )
|
|
libspectrum_snap_set_ay_registers( snap, i,
|
|
machine_current->ay.registers[i] );
|
|
}
|