/* ay.c: AY-8-3912 routines Copyright (c) 1999-2004 Philip Kendall $Id: ay.c,v 1.26 2007/02/02 16:21:50 pak21 Exp $ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Author contact information: E-mail: philip-fuse@shadowmagic.org.uk */ #include #include "compat.h" #include "machine.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, }; /* 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 ); } int ay_from_snapshot( libspectrum_snap *snap, int capabilities ) { size_t i; if( 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 ); } } return 0; } int 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] ); return 0; }