1
0
mirror of https://git.code.sf.net/p/fuse-emulator/fuse synced 2026-01-30 04:22:18 +03:00
Files
fuse/specplus3.c
2001-10-21 15:47:33 +00:00

213 lines
5.7 KiB
C

/* specplus3.c: Spectrum +2A/+3 specific routines
Copyright (c) 1999-2001 Philip Kendall
$Id$
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: pak21-fuse@srcf.ucam.org
Postal address: 15 Crescent Road, Wokingham, Berks, RG40 2DB, England
*/
#include <config.h>
#include <stdio.h>
#include "ay.h"
#include "display.h"
#include "event.h"
#include "keyboard.h"
#include "machine.h"
#include "sound.h"
#include "spec128.h"
#include "specplus3.h"
#include "spectrum.h"
#include "z80/z80.h"
spectrum_port_info specplus3_peripherals[] = {
{ 0x0001, 0x0000, spectrum_ula_read, spectrum_ula_write },
{ 0xc002, 0xc000, ay_registerport_read, ay_registerport_write },
{ 0xc002, 0x8000, spectrum_port_noread, ay_dataport_write },
{ 0xc002, 0x4000, spectrum_port_noread, spec128_memoryport_write },
{ 0xf002, 0x1000, spectrum_port_noread, specplus3_memoryport_write },
{ 0, 0, NULL, NULL } /* End marker. DO NOT REMOVE */
};
BYTE specplus3_readbyte(WORD address)
{
int bank;
if(machine_current->ram.special) {
bank=address/0x4000; address-=(bank*0x4000);
switch(machine_current->ram.specialcfg) {
case 0: return RAM[bank ][address];
case 1: return RAM[bank+4][address];
case 2: switch(bank) {
case 0: return RAM[4][address];
case 1: return RAM[5][address];
case 2: return RAM[6][address];
case 3: return RAM[3][address];
}
case 3: switch(bank) {
case 0: return RAM[4][address];
case 1: return RAM[7][address];
case 2: return RAM[6][address];
case 3: return RAM[3][address];
}
default:
fprintf(stderr,"Unknown +3 special configuration %d\n",
machine_current->ram.specialcfg);
abort();
}
} else {
if(address<0x4000) return ROM[machine_current->ram.current_rom][address];
bank=address/0x4000; address-=(bank*0x4000);
switch(bank) {
case 1: return RAM[ 5][address]; break;
case 2: return RAM[ 2][address]; break;
case 3: return RAM[machine_current->ram.current_page][address]; break;
default: abort();
}
}
}
BYTE specplus3_read_screen_memory(WORD offset)
{
return RAM[machine_current->ram.current_screen][offset];
}
void specplus3_writebyte(WORD address, BYTE b)
{
int bank;
if(machine_current->ram.special) {
bank=address/0x4000; address-=(bank*0x4000);
switch(machine_current->ram.specialcfg) {
case 0: break;
case 1: bank+=4; break;
case 2:
switch(bank) {
case 0: bank=4; break;
case 1: bank=5; break;
case 2: bank=6; break;
case 3: bank=3; break;
}
break;
case 3: switch(bank) {
case 0: bank=4; break;
case 1: bank=7; break;
case 2: bank=6; break;
case 3: bank=3; break;
}
break;
}
} else {
if(address<0x4000) return;
bank=address/0x4000; address-=(bank*0x4000);
switch(bank) {
case 1: bank=5; break;
case 2: bank=2; break;
case 3: bank=machine_current->ram.current_page; break;
}
}
RAM[bank][address]=b;
if(bank==machine_current->ram.current_screen && address < 0x1b00) {
display_dirty(address+0x4000,b); /* Replot necessary pixels */
}
}
int specplus3_init( machine_info *machine )
{
int error;
machine->machine = SPECTRUM_MACHINE_PLUS3;
machine->reset = specplus3_reset;
machine_set_timings( machine, 3.54690e6, 24, 128, 24, 52, 311, 8865 );
machine->ram.read_memory = specplus3_readbyte;
machine->ram.read_screen = specplus3_read_screen_memory;
machine->ram.write_memory = specplus3_writebyte;
error = machine_allocate_roms( machine, 4 );
if( error ) return error;
error = machine_read_rom( machine, 0, "plus3-0.rom" );
if( error ) return error;
error = machine_read_rom( machine, 1, "plus3-1.rom" );
if( error ) return error;
error = machine_read_rom( machine, 2, "plus3-2.rom" );
if( error ) return error;
error = machine_read_rom( machine, 3, "plus3-3.rom" );
if( error ) return error;
machine->peripherals=specplus3_peripherals;
machine->ay.present=1;
return 0;
}
int specplus3_reset(void)
{
machine_current->ram.current_page=0; machine_current->ram.current_rom=0;
machine_current->ram.current_screen=5;
machine_current->ram.locked=0;
machine_current->ram.special=0; machine_current->ram.specialcfg=0;
event_reset();
if( event_add( machine_current->timings.cycles_per_frame,
EVENT_TYPE_INTERRUPT) ) return 1;
if( event_add( machine_current->line_times[0],
EVENT_TYPE_LINE) ) return 1;
z80_reset();
sound_ay_reset();
return 0;
}
void specplus3_memoryport_write(WORD port, BYTE b)
{
/* Do nothing if we've locked the RAM configuration */
if( machine_current->ram.locked ) return;
/* Store the last byte written in case we need it */
machine_current->ram.last_byte2=b;
if( b & 0x01) { /* Check whether we want a special RAM configuration */
/* If so, select it */
machine_current->ram.special=1;
machine_current->ram.specialcfg= ( b & 0x06 ) >> 1;
} else {
/* If not, we're selecting the high bit of the current ROM */
machine_current->ram.special=0;
machine_current->ram.current_rom=(machine_current->ram.current_rom & 0x01) |
( (b & 0x04) >> 1 );
}
}