1 /* memory.c: Routines for accessing memory
2    Copyright (c) 1999-2012 Philip Kendall
3 
4    $Id: memory.c 4857 2013-01-23 12:00:08Z fredm $
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20    Author contact information:
21 
22    E-mail: philip-fuse@shadowmagic.org.uk
23 
24 */
25 
26 #include <config.h>
27 
28 #include <string.h>
29 
30 #include <libspectrum.h>
31 
32 #include "debugger/debugger.h"
33 #include "display.h"
34 #include "fuse.h"
35 #include "machines/pentagon.h"
36 #include "machines/spec128.h"
37 #include "memory.h"
38 #include "module.h"
39 #include "peripherals/disk/opus.h"
40 #include "peripherals/spectranet.h"
41 #include "peripherals/ula.h"
42 #include "settings.h"
43 #include "spectrum.h"
44 #include "ui/ui.h"
45 #include "utils.h"
46 
47 /* The various sources of memory available to us */
48 static GArray *memory_sources;
49 
50 /* Some "well-known" memory sources */
51 int memory_source_rom; /* System ROM */
52 int memory_source_ram; /* System RAM */
53 int memory_source_dock; /* Timex DOCK */
54 int memory_source_exrom; /* Timex EXROM */
55 int memory_source_any; /* Used by the debugger to signify an absolute address */
56 int memory_source_none; /* No memory attached here */
57 
58 /* Each RAM chunk accessible by the Z80 */
59 memory_page memory_map_read[MEMORY_PAGES_IN_64K];
60 memory_page memory_map_write[MEMORY_PAGES_IN_64K];
61 
62 /* Standard mappings for the 'normal' RAM */
63 memory_page memory_map_ram[SPECTRUM_RAM_PAGES * MEMORY_PAGES_IN_16K];
64 
65 /* Standard mappings for the ROMs */
66 memory_page memory_map_rom[SPECTRUM_ROM_PAGES * MEMORY_PAGES_IN_16K];
67 
68 /* Some allocated memory */
69 typedef struct memory_pool_entry_t {
70   int persistent;
71   libspectrum_byte *memory;
72 } memory_pool_entry_t;
73 
74 /* All the memory we've allocated for this machine */
75 static GSList *pool;
76 
77 /* Which RAM page contains the current screen */
78 int memory_current_screen;
79 
80 /* Which bits to look at when working out where the screen is */
81 libspectrum_word memory_screen_mask;
82 
83 static void memory_from_snapshot( libspectrum_snap *snap );
84 static void memory_to_snapshot( libspectrum_snap *snap );
85 
86 static module_info_t memory_module_info = {
87 
88   NULL,
89   NULL,
90   NULL,
91   memory_from_snapshot,
92   memory_to_snapshot,
93 
94 };
95 
96 /* Set up the information about the normal page mappings.
97    Memory contention and usable pages vary from machine to machine and must
98    be set in the appropriate _reset function */
99 void
memory_init(void)100 memory_init( void )
101 {
102   size_t i, j;
103 
104   memory_sources = g_array_new( FALSE, FALSE, sizeof( const char* ) );
105 
106   memory_source_rom = memory_source_register( "ROM" );
107   memory_source_ram = memory_source_register( "RAM" );
108   memory_source_dock = memory_source_register( "Timex Dock" );
109   memory_source_exrom = memory_source_register( "Timex EXROM" );
110   memory_source_any = memory_source_register( "Absolute address" );
111   memory_source_none = memory_source_register( "None" );
112 
113   /* Nothing in the memory pool as yet */
114   pool = NULL;
115 
116   for( i = 0; i < SPECTRUM_ROM_PAGES; i++ )
117     for( j = 0; j < MEMORY_PAGES_IN_16K; j++ ) {
118       memory_page *page = &memory_map_rom[i * MEMORY_PAGES_IN_16K + j];
119       page->writable = 0;
120       page->contended = 0;
121       page->source = memory_source_rom;
122     }
123 
124   for( i = 0; i < SPECTRUM_RAM_PAGES; i++ )
125     for( j = 0; j < MEMORY_PAGES_IN_16K; j++ ) {
126       memory_page *page = &memory_map_ram[i * MEMORY_PAGES_IN_16K + j];
127       page->page = &RAM[i][j * MEMORY_PAGE_SIZE];
128       page->page_num = i;
129       page->offset = j * MEMORY_PAGE_SIZE;
130       page->writable = 1;
131       page->source = memory_source_ram;
132     }
133 
134   module_register( &memory_module_info );
135 }
136 
137 static void
memory_pool_free_entry(gpointer data,gpointer user_data GCC_UNUSED)138 memory_pool_free_entry( gpointer data, gpointer user_data GCC_UNUSED )
139 {
140   memory_pool_entry_t *entry = data;
141   libspectrum_free( entry->memory );
142   libspectrum_free( entry );
143 }
144 
145 /* Tidy-up function called at end of emulation */
146 void
memory_end(void)147 memory_end( void )
148 {
149   int i;
150   char *description;
151 
152   /* Free all the memory we've allocated for this machine */
153   if( pool ) {
154     g_slist_foreach( pool, memory_pool_free_entry, NULL );
155     g_slist_free( pool );
156     pool = NULL;
157   }
158 
159   /* Free memory source types */
160   if( memory_sources ) {
161     for( i = 0; i < memory_sources->len; i++ ) {
162       description = g_array_index( memory_sources, char *, i );
163       libspectrum_free( description );
164     }
165 
166     g_array_free( memory_sources, TRUE );
167     memory_sources = NULL;
168   }
169 }
170 
171 int
memory_source_register(const char * description)172 memory_source_register( const char *description )
173 {
174   const char *copy = utils_safe_strdup( description );
175 
176   g_array_append_val( memory_sources, copy );
177 
178   return memory_sources->len - 1;
179 }
180 
181 const char*
memory_source_description(int source)182 memory_source_description( int source )
183 {
184   return g_array_index( memory_sources, const char*, source );
185 }
186 
187 int
memory_source_find(const char * description)188 memory_source_find( const char *description )
189 {
190   int i, source = -1;
191 
192   for( i = 0; i < memory_sources->len; i++ ) {
193     const char *found = g_array_index( memory_sources, const char*, i );
194     if( !strcasecmp( description, found ) ) {
195       source = i;
196       break;
197     }
198   }
199 
200   return source;
201 }
202 
203 /* Allocate some memory from the pool */
204 libspectrum_byte*
memory_pool_allocate(size_t length)205 memory_pool_allocate( size_t length )
206 {
207   return memory_pool_allocate_persistent( length, 0 );
208 }
209 
210 libspectrum_byte*
memory_pool_allocate_persistent(size_t length,int persistent)211 memory_pool_allocate_persistent( size_t length, int persistent )
212 {
213   memory_pool_entry_t *entry;
214   libspectrum_byte *memory;
215 
216   memory = libspectrum_malloc( length * sizeof( *memory ) );
217 
218   entry = libspectrum_malloc( sizeof( *entry ) );
219 
220   entry->persistent = persistent;
221   entry->memory = memory;
222 
223   pool = g_slist_prepend( pool, entry );
224 
225   return memory;
226 }
227 
228 static gint
find_non_persistent(gconstpointer data,gconstpointer user_data GCC_UNUSED)229 find_non_persistent( gconstpointer data, gconstpointer user_data GCC_UNUSED )
230 {
231   const memory_pool_entry_t *entry = data;
232   return entry->persistent;
233 }
234 
235 /* Free all non-persistent memory in the pool */
236 void
memory_pool_free(void)237 memory_pool_free( void )
238 {
239   GSList *ptr;
240 
241   while( ( ptr = g_slist_find_custom( pool, NULL, find_non_persistent ) ) != NULL )
242   {
243     memory_pool_entry_t *entry = ptr->data;
244     libspectrum_free( entry->memory );
245     pool = g_slist_remove( pool, entry );
246     libspectrum_free( entry );
247   }
248 }
249 
250 /* Set contention for 16K of RAM */
251 void
memory_ram_set_16k_contention(int page_num,int contended)252 memory_ram_set_16k_contention( int page_num, int contended )
253 {
254   int i;
255 
256   for( i = 0; i < MEMORY_PAGES_IN_16K; i++ )
257     memory_map_ram[ page_num * MEMORY_PAGES_IN_16K + i ].contended = contended;
258 }
259 
260 /* Map 16K of memory */
261 void
memory_map_16k(libspectrum_word address,memory_page source[],int page_num)262 memory_map_16k( libspectrum_word address, memory_page source[], int page_num )
263 {
264   int i;
265 
266   for( i = 0; i < MEMORY_PAGES_IN_16K; i++ ) {
267     int page = ( address >> MEMORY_PAGE_SIZE_LOGARITHM ) + i;
268     memory_map_read[ page ] = memory_map_write[ page ] =
269       source[ page_num * MEMORY_PAGES_IN_16K + i ];
270   }
271 }
272 
273 /* Map 8K of memory */
274 void
memory_map_8k(libspectrum_word address,memory_page source[],int page_num)275 memory_map_8k( libspectrum_word address, memory_page source[], int page_num )
276 {
277   int i;
278 
279   for( i = 0; i < MEMORY_PAGES_IN_8K; i++ ) {
280     int page = ( address >> MEMORY_PAGE_SIZE_LOGARITHM ) + i;
281     memory_map_read[ page ] = memory_map_write[ page ] =
282       source[ page_num * MEMORY_PAGES_IN_8K + i ];
283   }
284 }
285 
286 /* Map one page of memory */
287 void
memory_map_page(memory_page * source[],int page_num)288 memory_map_page( memory_page *source[], int page_num )
289 {
290   memory_map_read[ page_num ] = memory_map_write[ page_num ] =
291     *source[ page_num ];
292 }
293 
294 /* Page in from /ROMCS */
295 void
memory_map_romcs(memory_page source[])296 memory_map_romcs( memory_page source[] )
297 {
298   int i;
299 
300   for( i = 0; i < MEMORY_PAGES_IN_16K; i++ )
301     memory_map_read[i] = memory_map_write[i] = source[i];
302 }
303 
304 /* Page in 8K from /ROMCS */
305 void
memory_map_romcs_8k(libspectrum_word address,memory_page source[])306 memory_map_romcs_8k( libspectrum_word address, memory_page source[] )
307 {
308   int i, start;
309 
310   start = address >> MEMORY_PAGE_SIZE_LOGARITHM;
311   for( i = 0; i < MEMORY_PAGES_IN_8K; i++ )
312     memory_map_read[ start + i ] = memory_map_write[ start + i ] = source[ i ];
313 }
314 
315 /* Page in 4K from /ROMCS */
316 void
memory_map_romcs_4k(libspectrum_word address,memory_page source[])317 memory_map_romcs_4k( libspectrum_word address, memory_page source[] )
318 {
319   int i, start;
320 
321   start = address >> MEMORY_PAGE_SIZE_LOGARITHM;
322   for( i = 0; i < MEMORY_PAGES_IN_4K; i++ )
323     memory_map_read[ start + i ] = memory_map_write[ start + i ] = source[ i ];
324 }
325 
326 libspectrum_byte
readbyte(libspectrum_word address)327 readbyte( libspectrum_word address )
328 {
329   libspectrum_word bank;
330   memory_page *mapping;
331 
332   bank = address >> MEMORY_PAGE_SIZE_LOGARITHM;
333   mapping = &memory_map_read[ bank ];
334 
335   if( debugger_mode != DEBUGGER_MODE_INACTIVE )
336     debugger_check( DEBUGGER_BREAKPOINT_TYPE_READ, address );
337 
338   if( mapping->contended ) tstates += ula_contention[ tstates ];
339   tstates += 3;
340 
341   if( opus_active && address >= 0x2800 && address < 0x3800 )
342     return opus_read( address );
343 
344   if( spectranet_paged ) {
345     if( spectranet_w5100_paged_a && address >= 0x1000 && address < 0x2000 )
346       return spectranet_w5100_read( mapping, address );
347     if( spectranet_w5100_paged_b && address >= 0x2000 && address < 0x3000 )
348       return spectranet_w5100_read( mapping, address );
349   }
350 
351   return mapping->page[ address & MEMORY_PAGE_SIZE_MASK ];
352 }
353 
354 void
writebyte(libspectrum_word address,libspectrum_byte b)355 writebyte( libspectrum_word address, libspectrum_byte b )
356 {
357   libspectrum_word bank;
358   memory_page *mapping;
359 
360   bank = address >> MEMORY_PAGE_SIZE_LOGARITHM;
361   mapping = &memory_map_write[ bank ];
362 
363   if( debugger_mode != DEBUGGER_MODE_INACTIVE )
364     debugger_check( DEBUGGER_BREAKPOINT_TYPE_WRITE, address );
365 
366   if( mapping->contended ) tstates += ula_contention[ tstates ];
367 
368   tstates += 3;
369 
370   writebyte_internal( address, b );
371 }
372 
373 void
memory_display_dirty_pentagon_16_col(libspectrum_word address,libspectrum_byte b)374 memory_display_dirty_pentagon_16_col( libspectrum_word address,
375                                       libspectrum_byte b )
376 {
377   libspectrum_word bank = address >> MEMORY_PAGE_SIZE_LOGARITHM;
378   memory_page *mapping = &memory_map_write[ bank ];
379   libspectrum_word offset = address & MEMORY_PAGE_SIZE_MASK;
380   libspectrum_byte *memory = mapping->page;
381 
382   /* The offset into the 16Kb RAM page (as opposed to the 8Kb chunk) */
383   libspectrum_word offset2 = offset + mapping->offset;
384 
385   /* If this is a write to the current screen areas (and it actually changes
386      the destination), redraw that bit.
387      The trick here is that we need to check the home bank screen areas in
388      page 5 and 4 (if screen 1 is in use), and page 7 & 6 (if screen 2 is in
389      use) and both the standard and ALTDFILE areas of those pages
390    */
391   if( mapping->source == memory_source_ram &&
392       ( ( memory_current_screen  == 5 &&
393           ( mapping->page_num == 5 || mapping->page_num == 4 ) ) ||
394         ( memory_current_screen  == 7 &&
395           ( mapping->page_num == 7 || mapping->page_num == 6 ) ) ) &&
396       ( offset2 & 0xdfff ) < 0x1b00 &&
397       memory[ offset ] != b )
398     display_dirty_pentagon_16_col( offset2 );
399 }
400 
401 void
memory_display_dirty_sinclair(libspectrum_word address,libspectrum_byte b)402 memory_display_dirty_sinclair( libspectrum_word address, libspectrum_byte b ) \
403 {
404   libspectrum_word bank = address >> MEMORY_PAGE_SIZE_LOGARITHM;
405   memory_page *mapping = &memory_map_write[ bank ];
406   libspectrum_word offset = address & MEMORY_PAGE_SIZE_MASK;
407   libspectrum_byte *memory = mapping->page;
408 
409   /* The offset into the 16Kb RAM page (as opposed to the 8Kb chunk) */
410   libspectrum_word offset2 = offset + mapping->offset;
411 
412   /* If this is a write to the current screen (and it actually changes
413      the destination), redraw that bit */
414   if( mapping->source == memory_source_ram &&
415       mapping->page_num == memory_current_screen &&
416       ( offset2 & memory_screen_mask ) < 0x1b00 &&
417       memory[ offset ] != b )
418     display_dirty( offset2 );
419 }
420 
421 memory_display_dirty_fn memory_display_dirty;
422 
423 void
writebyte_internal(libspectrum_word address,libspectrum_byte b)424 writebyte_internal( libspectrum_word address, libspectrum_byte b )
425 {
426   libspectrum_word bank = address >> MEMORY_PAGE_SIZE_LOGARITHM;
427   memory_page *mapping = &memory_map_write[ bank ];
428 
429   if( spectranet_paged ) {
430     /* all writes need to be parsed by the flash rom emulation */
431     spectranet_flash_rom_write(address, b);
432 
433     if( spectranet_w5100_paged_a && address >= 0x1000 && address < 0x2000 ) {
434       spectranet_w5100_write( mapping, address, b );
435       return;
436     }
437     if( spectranet_w5100_paged_b && address >= 0x2000 && address < 0x3000 ) {
438       spectranet_w5100_write( mapping, address, b );
439       return;
440     }
441   }
442 
443   if( opus_active && address >= 0x2800 && address < 0x3800 ) {
444     opus_write( address, b );
445   } else if( mapping->writable ||
446              (mapping->source != memory_source_none &&
447               settings_current.writable_roms) ) {
448     libspectrum_word offset = address & MEMORY_PAGE_SIZE_MASK;
449     libspectrum_byte *memory = mapping->page;
450 
451     memory_display_dirty( address, b );
452 
453     memory[ offset ] = b;
454   }
455 }
456 
457 void
memory_romcs_map(void)458 memory_romcs_map( void )
459 {
460   /* Nothing changes if /ROMCS is not set */
461   if( !machine_current->ram.romcs ) return;
462 
463   /* FIXME: what should we do if more than one of these devices is
464      active? What happen in the real situation? e.g. if1+if2 with cartridge?
465 
466      OK. in the Interface 1 service manual: p.: 1.2 par.: 1.3.1
467        All the additional software needed in IC2 (the if1 ROM). IC2 enable
468        is discussed in paragraph 1.2.2 above. In addition to control from
469        IC1 (the if1 ULA), the ROM maybe disabled by a device connected to
470        the (if1's) expansion connector J1. ROMCS2 from (B25), for example,
471        Interface 2 connected to J1 would disable both ROM IC2 (if1 ROM) and
472        the Spectrum ROM, via isolating diodes D10 and D9 respectively.
473 
474      All comment in parenthesis added by me (Gergely Szasz).
475      The ROMCS2 (B25 conn) in Interface 1 J1 edge connector is in the
476      same position than ROMCS (B25 conn) in the Spectrum edge connector.
477 
478    */
479 
480   module_romcs();
481 }
482 
483 static void
memory_from_snapshot(libspectrum_snap * snap)484 memory_from_snapshot( libspectrum_snap *snap )
485 {
486   size_t i;
487   int capabilities = machine_current->capabilities;
488 
489   if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PENT1024_MEMORY ) {
490     pentagon1024_memoryport_write( 0x7ffd,
491 			      libspectrum_snap_out_128_memoryport( snap ) );
492     pentagon1024_v22_memoryport_write( 0xeff7,
493                               libspectrum_snap_out_plus3_memoryport( snap ) );
494   } else {
495     if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY )
496       spec128_memoryport_write( 0x7ffd,
497                                 libspectrum_snap_out_128_memoryport( snap ) );
498 
499     if( ( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY ) ||
500         ( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY )    )
501       specplus3_memoryport2_write(
502         0x1ffd, libspectrum_snap_out_plus3_memoryport( snap )
503       );
504   }
505 
506   for( i = 0; i < 64; i++ )
507     if( libspectrum_snap_pages( snap, i ) )
508       memcpy( RAM[i], libspectrum_snap_pages( snap, i ), 0x4000 );
509 
510   if( libspectrum_snap_custom_rom( snap ) ) {
511     for( i = 0; i < libspectrum_snap_custom_rom_pages( snap ) && i < 4; i++ ) {
512       if( libspectrum_snap_roms( snap, i ) ) {
513         machine_load_rom_bank_from_buffer( memory_map_rom, i,
514           libspectrum_snap_roms( snap, i ),
515           libspectrum_snap_rom_length( snap, i ), 1 );
516       }
517     }
518   }
519 }
520 
521 static void
write_rom_to_snap(libspectrum_snap * snap,int * current_rom_num,libspectrum_byte ** current_rom,size_t * rom_length)522 write_rom_to_snap( libspectrum_snap *snap, int *current_rom_num,
523                    libspectrum_byte **current_rom, size_t *rom_length )
524 {
525   libspectrum_snap_set_roms( snap, *current_rom_num, *current_rom );
526   libspectrum_snap_set_rom_length( snap, *current_rom_num, *rom_length );
527   (*current_rom_num)++;
528   *current_rom = NULL;
529 }
530 
531 /* Look at all ROM entries, to see if any are marked as being custom ROMs */
532 int
memory_custom_rom(void)533 memory_custom_rom( void )
534 {
535   size_t i;
536 
537   for( i = 0; i < SPECTRUM_ROM_PAGES * MEMORY_PAGES_IN_16K; i++ )
538     if( memory_map_rom[ i ].save_to_snapshot )
539       return 1;
540 
541   return 0;
542 }
543 
544 /* Reset all ROM entries to being non-custom ROMs */
545 void
memory_reset(void)546 memory_reset( void )
547 {
548   size_t i;
549 
550   for( i = 0; i < SPECTRUM_ROM_PAGES * MEMORY_PAGES_IN_16K; i++ )
551     memory_map_rom[ i ].save_to_snapshot = 0;
552 }
553 
554 static void
memory_rom_to_snapshot(libspectrum_snap * snap)555 memory_rom_to_snapshot( libspectrum_snap *snap )
556 {
557   libspectrum_byte *current_rom = NULL;
558   int current_page_num = -1;
559   int current_rom_num = 0;
560   size_t rom_length = 0;
561   size_t i;
562 
563   /* If we have custom ROMs trigger writing all roms to the snap */
564   if( !memory_custom_rom() ) return;
565 
566   libspectrum_snap_set_custom_rom( snap, 1 );
567 
568   /* write all ROMs to the snap */
569   for( i = 0; i < SPECTRUM_ROM_PAGES * MEMORY_PAGES_IN_16K; i++ ) {
570     if( memory_map_rom[ i ].page ) {
571       if( current_page_num != memory_map_rom[ i ].page_num ) {
572         if( current_rom )
573           write_rom_to_snap( snap, &current_rom_num, &current_rom, &rom_length );
574 
575         /* Start a new ROM image */
576         rom_length = MEMORY_PAGE_SIZE;
577         current_rom = libspectrum_malloc( rom_length );
578 
579         memcpy( current_rom, memory_map_rom[ i ].page, MEMORY_PAGE_SIZE );
580         current_page_num = memory_map_rom[ i ].page_num;
581       } else {
582         /* Extend the current ROM image */
583         current_rom = libspectrum_realloc( current_rom,
584                                            rom_length + MEMORY_PAGE_SIZE );
585 
586         memcpy( current_rom + rom_length, memory_map_rom[ i ].page,
587                 MEMORY_PAGE_SIZE );
588         rom_length += MEMORY_PAGE_SIZE;
589       }
590     }
591   }
592 
593   if( current_rom )
594     write_rom_to_snap( snap, &current_rom_num, &current_rom, &rom_length );
595 
596   libspectrum_snap_set_custom_rom_pages( snap, current_rom_num );
597 }
598 
599 static void
memory_to_snapshot(libspectrum_snap * snap)600 memory_to_snapshot( libspectrum_snap *snap )
601 {
602   size_t i;
603   libspectrum_byte *buffer;
604 
605   libspectrum_snap_set_out_128_memoryport( snap,
606 					   machine_current->ram.last_byte );
607   libspectrum_snap_set_out_plus3_memoryport( snap,
608 					     machine_current->ram.last_byte2 );
609 
610   for( i = 0; i < 64; i++ ) {
611     if( RAM[i] != NULL ) {
612 
613       buffer = libspectrum_malloc( 0x4000 * sizeof( libspectrum_byte ) );
614 
615       memcpy( buffer, RAM[i], 0x4000 );
616       libspectrum_snap_set_pages( snap, i, buffer );
617     }
618   }
619 
620   memory_rom_to_snapshot( snap );
621 }
622