1
0
mirror of https://git.code.sf.net/p/fuse-emulator/fuse synced 2026-01-27 01:41:34 +03:00
Files
fuse/memory.c
Stuart Brady 77127c1f71 Remove unused #includes.
Legacy-ID: 3009
2007-06-17 20:37:50 +00:00

322 lines
8.4 KiB
C

/* memory.c: Routines for accessing memory
Copyright (c) 1999-2004 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.,
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 <libspectrum.h>
#include "debugger/debugger.h"
#include "display.h"
#include "fuse.h"
#include "machines/spec128.h"
#include "memory.h"
#include "module.h"
#include "settings.h"
#include "spectrum.h"
#include "ui/ui.h"
#include "ula.h"
/* Each 8Kb RAM chunk accessible by the Z80 */
memory_page memory_map_read[8];
memory_page memory_map_write[8];
/* Two 8Kb memory chunks accessible by the Z80 when /ROMCS is low */
memory_page memory_map_romcs[2];
/* Mappings for the 'home' (normal ROM/RAM) pages, the Timex DOCK and
the Timex EXROM */
memory_page *memory_map_home[8];
memory_page *memory_map_dock[8];
memory_page *memory_map_exrom[8];
/* Standard mappings for the 'normal' RAM */
memory_page memory_map_ram[ 2 * SPECTRUM_RAM_PAGES ];
/* Standard mappings for the ROMs */
memory_page memory_map_rom[8];
/* All the memory we've allocated for this machine */
static GSList *pool;
/* Which RAM page contains the current screen */
int memory_current_screen;
/* Which bits to look at when working out where the screen is */
libspectrum_word memory_screen_mask;
static void memory_ram_from_snapshot( libspectrum_snap *snap );
static void memory_ram_to_snapshot( libspectrum_snap *snap );
static module_info_t memory_module_info = {
NULL,
NULL,
memory_ram_from_snapshot,
memory_ram_to_snapshot,
};
/* Set up the information about the normal page mappings.
Memory contention and useable pages vary from machine to machine and must
be set in the appropriate _reset function */
int
memory_init( void )
{
size_t i;
memory_page *mapping1, *mapping2;
/* Nothing in the memory pool as yet */
pool = NULL;
for( i = 0; i < 8; i++ ) {
mapping1 = &memory_map_rom[ i ];
mapping1->page = NULL;
mapping1->writable = 0;
mapping1->bank = MEMORY_BANK_HOME;
mapping1->page_num = i;
mapping1->source = MEMORY_SOURCE_SYSTEM;
}
for( i = 0; i < SPECTRUM_RAM_PAGES; i++ ) {
mapping1 = &memory_map_ram[ 2 * i ];
mapping2 = &memory_map_ram[ 2 * i + 1 ];
mapping1->page = &RAM[i][ 0x0000 ];
mapping2->page = &RAM[i][ MEMORY_PAGE_SIZE ];
mapping1->writable = mapping2->writable = 0;
mapping1->bank = mapping2->bank = MEMORY_BANK_HOME;
mapping1->page_num = mapping2->page_num = i;
mapping1->offset = 0x0000;
mapping2->offset = MEMORY_PAGE_SIZE;
mapping1->source = mapping2->source = MEMORY_SOURCE_SYSTEM;
}
/* Just initialise these with something */
for( i = 0; i < 8; i++ )
memory_map_home[i] = memory_map_dock[i] = memory_map_exrom[i] =
&memory_map_ram[0];
for( i = 0; i < 2; i++ ) memory_map_romcs[i].bank = MEMORY_BANK_ROMCS;
module_register( &memory_module_info );
return 0;
}
/* Allocate some memory from the pool */
libspectrum_byte*
memory_pool_allocate( size_t length )
{
libspectrum_byte *ptr;
ptr = malloc( length * sizeof( libspectrum_byte ) );
if( !ptr ) {
ui_error( UI_ERROR_ERROR, "Out of memory at %s:%d", __FILE__, __LINE__ );
return NULL;
}
pool = g_slist_prepend( pool, ptr );
return ptr;
}
static void
free_memory( gpointer data, gpointer user_data )
{
free( data );
}
void
memory_pool_free( void )
{
g_slist_foreach( pool, free_memory, NULL );
g_slist_free( pool );
pool = NULL;
}
const char*
memory_bank_name( memory_page *page )
{
switch( page->bank ) {
case MEMORY_BANK_NONE: return "Empty";
case MEMORY_BANK_HOME: return page->writable ? "RAM" : "ROM";
case MEMORY_BANK_DOCK: return "Dock";
case MEMORY_BANK_EXROM: return "Exrom";
case MEMORY_BANK_ROMCS: return "Chip Select";
}
return "[Undefined]";
}
libspectrum_byte
readbyte( libspectrum_word address )
{
libspectrum_word bank;
memory_page *mapping;
bank = address >> 13;
mapping = &memory_map_read[ bank ];
if( debugger_mode != DEBUGGER_MODE_INACTIVE &&
debugger_check( DEBUGGER_BREAKPOINT_TYPE_READ, address ) )
debugger_mode = DEBUGGER_MODE_HALTED;
if( mapping->contended ) tstates += ula_contention[ tstates ];
tstates += 3;
return mapping->page[ address & 0x1fff ];
}
void
writebyte( libspectrum_word address, libspectrum_byte b )
{
libspectrum_word bank;
memory_page *mapping;
bank = address >> 13;
mapping = &memory_map_write[ bank ];
if( debugger_mode != DEBUGGER_MODE_INACTIVE &&
debugger_check( DEBUGGER_BREAKPOINT_TYPE_WRITE, address ) )
debugger_mode = DEBUGGER_MODE_HALTED;
if( mapping->contended ) tstates += ula_contention[ tstates ];
tstates += 3;
writebyte_internal( address, b );
}
void
writebyte_internal( libspectrum_word address, libspectrum_byte b )
{
libspectrum_word bank, offset;
memory_page *mapping;
libspectrum_byte *memory;
bank = address >> 13; offset = address & 0x1fff;
mapping = &memory_map_write[ bank ];
memory = mapping->page;
if( mapping->writable || settings_current.writable_roms ) {
/* The offset into the 16Kb RAM page (as opposed to the 8Kb chunk) */
libspectrum_word offset2 = offset + mapping->offset;
/* If this is a write to the current screen (and it actually changes
the destination), redraw that bit */
if( mapping->bank == MEMORY_BANK_HOME &&
mapping->page_num == memory_current_screen &&
( offset2 & memory_screen_mask ) < 0x1b00 &&
memory[ offset ] != b )
display_dirty( offset2 );
memory[ offset ] = b;
}
}
void
memory_romcs_map( void )
{
/* Nothing changes if /ROMCS is not set */
if( !machine_current->ram.romcs ) return;
/* FIXME: what should we do if more than one of these devices is
active? What happen in the real situation? e.g. if1+if2 with cartridge?
OK. in the Interface 1 service manual: p.: 1.2 par.: 1.3.1
All the additional software needed in IC2 (the if1 ROM). IC2 enable
is discussed in paragraph 1.2.2 above. In addition to control from
IC1 (the if1 ULA), the ROM maybe disabled by a device connected to
the (if1's) expansion connector J1. ROMCS2 from (B25), for example,
Interface 2 connected to J1 would disable both ROM IC2 (if1 ROM) and
the Spectrum ROM, via isolating diodes D10 and D9 respectively.
All comment in paranthesis added by me (Gergely Szasz).
The ROMCS2 (B25 conn) in Interface 1 J1 edge connector is in the
same position than ROMCS (B25 conn) in the Spectrum edge connector.
*/
module_romcs();
}
static void
memory_ram_from_snapshot( libspectrum_snap *snap )
{
size_t i;
int capabilities = machine_current->capabilities;
if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY )
spec128_memoryport_write( 0x7ffd,
libspectrum_snap_out_128_memoryport( snap ) );
if( ( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY ) ||
( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY ) )
specplus3_memoryport2_write(
0x1ffd, libspectrum_snap_out_plus3_memoryport( snap )
);
for( i = 0; i < 16; i++ )
if( libspectrum_snap_pages( snap, i ) )
memcpy( RAM[i], libspectrum_snap_pages( snap, i ), 0x4000 );
}
static void
memory_ram_to_snapshot( libspectrum_snap *snap )
{
size_t i;
libspectrum_byte *buffer;
libspectrum_snap_set_out_128_memoryport( snap,
machine_current->ram.last_byte );
libspectrum_snap_set_out_plus3_memoryport( snap,
machine_current->ram.last_byte2 );
for( i = 0; i < 16; i++ ) {
if( RAM[i] != NULL ) {
buffer = malloc( 0x4000 * sizeof( libspectrum_byte ) );
if( !buffer ) {
ui_error( UI_ERROR_ERROR, "Out of memory at %s:%d", __FILE__,
__LINE__ );
return;
}
memcpy( buffer, RAM[i], 0x4000 );
libspectrum_snap_set_pages( snap, i, buffer );
}
}
}