PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/fuse-1.0.0.1/memory.c

#
C | 458 lines | 296 code | 90 blank | 72 comment | 62 complexity | 9bbdab32c80fd2780e961c4da594fad4 MD5 | raw file
Possible License(s): GPL-2.0
  1. /* memory.c: Routines for accessing memory
  2. Copyright (c) 1999-2004 Philip Kendall
  3. $Id: memory.c 4207 2010-12-05 10:01:23Z fredm $
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. Author contact information:
  16. E-mail: philip-fuse@shadowmagic.org.uk
  17. */
  18. #include <config.h>
  19. #include <string.h>
  20. #include <libspectrum.h>
  21. #include "debugger/debugger.h"
  22. #include "display.h"
  23. #include "disk/opus.h"
  24. #include "fuse.h"
  25. #include "machines/spec128.h"
  26. #include "memory.h"
  27. #include "module.h"
  28. #include "settings.h"
  29. #include "spectrum.h"
  30. #include "ui/ui.h"
  31. #include "ula.h"
  32. /* Each 8Kb RAM chunk accessible by the Z80 */
  33. memory_page memory_map_read[8];
  34. memory_page memory_map_write[8];
  35. /* Mappings for the 'home' (normal ROM/RAM) pages, the Timex DOCK and
  36. the Timex EXROM */
  37. memory_page *memory_map_home[8];
  38. memory_page *memory_map_dock[8];
  39. memory_page *memory_map_exrom[8];
  40. /* Standard mappings for the 'normal' RAM */
  41. memory_page memory_map_ram[ 2 * SPECTRUM_RAM_PAGES ];
  42. #define SPECTRUM_ROM_PAGES 4
  43. /* Standard mappings for the ROMs */
  44. memory_page memory_map_rom[ 2 * SPECTRUM_ROM_PAGES ];
  45. /* All the memory we've allocated for this machine */
  46. static GSList *pool;
  47. /* Which RAM page contains the current screen */
  48. int memory_current_screen;
  49. /* Which bits to look at when working out where the screen is */
  50. libspectrum_word memory_screen_mask;
  51. static void memory_from_snapshot( libspectrum_snap *snap );
  52. static void memory_to_snapshot( libspectrum_snap *snap );
  53. static module_info_t memory_module_info = {
  54. NULL,
  55. NULL,
  56. NULL,
  57. memory_from_snapshot,
  58. memory_to_snapshot,
  59. };
  60. /* Set up the information about the normal page mappings.
  61. Memory contention and usable pages vary from machine to machine and must
  62. be set in the appropriate _reset function */
  63. int
  64. memory_init( void )
  65. {
  66. size_t i;
  67. memory_page *mapping1, *mapping2;
  68. /* Nothing in the memory pool as yet */
  69. pool = NULL;
  70. for( i = 0; i < 8; i++ ) {
  71. mapping1 = &memory_map_rom[ i ];
  72. mapping1->page = NULL;
  73. mapping1->writable = 0;
  74. mapping1->bank = MEMORY_BANK_HOME;
  75. mapping1->page_num = i;
  76. mapping1->source = MEMORY_SOURCE_SYSTEM;
  77. }
  78. for( i = 0; i < SPECTRUM_RAM_PAGES; i++ ) {
  79. mapping1 = &memory_map_ram[ 2 * i ];
  80. mapping2 = &memory_map_ram[ 2 * i + 1 ];
  81. mapping1->page = &RAM[i][ 0x0000 ];
  82. mapping2->page = &RAM[i][ MEMORY_PAGE_SIZE ];
  83. mapping1->writable = mapping2->writable = 0;
  84. mapping1->bank = mapping2->bank = MEMORY_BANK_HOME;
  85. mapping1->page_num = mapping2->page_num = i;
  86. mapping1->offset = 0x0000;
  87. mapping2->offset = MEMORY_PAGE_SIZE;
  88. mapping1->source = mapping2->source = MEMORY_SOURCE_SYSTEM;
  89. }
  90. /* Just initialise these with something */
  91. for( i = 0; i < 8; i++ )
  92. memory_map_home[i] = memory_map_dock[i] = memory_map_exrom[i] =
  93. &memory_map_ram[0];
  94. module_register( &memory_module_info );
  95. return 0;
  96. }
  97. /* Allocate some memory from the pool */
  98. libspectrum_byte*
  99. memory_pool_allocate( size_t length )
  100. {
  101. libspectrum_byte *ptr;
  102. ptr = malloc( length * sizeof( libspectrum_byte ) );
  103. if( !ptr ) {
  104. ui_error( UI_ERROR_ERROR, "Out of memory at %s:%d", __FILE__, __LINE__ );
  105. return NULL;
  106. }
  107. pool = g_slist_prepend( pool, ptr );
  108. return ptr;
  109. }
  110. static void
  111. free_memory( gpointer data, gpointer user_data GCC_UNUSED )
  112. {
  113. free( data );
  114. }
  115. void
  116. memory_pool_free( void )
  117. {
  118. g_slist_foreach( pool, free_memory, NULL );
  119. g_slist_free( pool );
  120. pool = NULL;
  121. }
  122. const char*
  123. memory_bank_name( memory_page *page )
  124. {
  125. switch( page->bank ) {
  126. case MEMORY_BANK_NONE: return "Empty";
  127. case MEMORY_BANK_HOME: return page->writable ? "RAM" : "ROM";
  128. case MEMORY_BANK_DOCK: return "Dock";
  129. case MEMORY_BANK_EXROM: return "Exrom";
  130. case MEMORY_BANK_ROMCS: return "Chip Select";
  131. }
  132. return "[Undefined]";
  133. }
  134. libspectrum_byte
  135. readbyte( libspectrum_word address )
  136. {
  137. libspectrum_word bank;
  138. memory_page *mapping;
  139. bank = address >> 13;
  140. mapping = &memory_map_read[ bank ];
  141. if( debugger_mode != DEBUGGER_MODE_INACTIVE )
  142. debugger_check( DEBUGGER_BREAKPOINT_TYPE_READ, address );
  143. if( mapping->contended ) tstates += ula_contention[ tstates ];
  144. tstates += 3;
  145. if( opus_active && address >= 0x2800 && address < 0x3800 )
  146. return opus_read( address );
  147. return mapping->page[ address & 0x1fff ];
  148. }
  149. void
  150. writebyte( libspectrum_word address, libspectrum_byte b )
  151. {
  152. libspectrum_word bank;
  153. memory_page *mapping;
  154. bank = address >> 13;
  155. mapping = &memory_map_write[ bank ];
  156. if( debugger_mode != DEBUGGER_MODE_INACTIVE )
  157. debugger_check( DEBUGGER_BREAKPOINT_TYPE_WRITE, address );
  158. if( mapping->contended ) tstates += ula_contention[ tstates ];
  159. tstates += 3;
  160. writebyte_internal( address, b );
  161. }
  162. void
  163. memory_display_dirty_pentagon_16_col( libspectrum_word address,
  164. libspectrum_byte b )
  165. {
  166. libspectrum_word bank = address >> 13;
  167. memory_page *mapping = &memory_map_write[ bank ];
  168. libspectrum_word offset = address & 0x1fff;
  169. libspectrum_byte *memory = mapping->page;
  170. /* The offset into the 16Kb RAM page (as opposed to the 8Kb chunk) */
  171. libspectrum_word offset2 = offset + mapping->offset;
  172. /* If this is a write to the current screen areas (and it actually changes
  173. the destination), redraw that bit.
  174. The trick here is that we need to check the home bank screen areas in
  175. page 5 and 4 (if screen 1 is in use), and page 7 & 6 (if screen 2 is in
  176. use) and both the standard and ALTDFILE areas of those pages
  177. */
  178. if( mapping->bank == MEMORY_BANK_HOME &&
  179. ( ( memory_current_screen == 5 &&
  180. ( mapping->page_num == 5 || mapping->page_num == 4 ) ) ||
  181. ( memory_current_screen == 7 &&
  182. ( mapping->page_num == 7 || mapping->page_num == 6 ) ) ) &&
  183. ( offset2 & 0xdfff ) < 0x1b00 &&
  184. memory[ offset ] != b )
  185. display_dirty_pentagon_16_col( offset2 );
  186. }
  187. void
  188. memory_display_dirty_sinclair( libspectrum_word address, libspectrum_byte b ) \
  189. {
  190. libspectrum_word bank = address >> 13;
  191. memory_page *mapping = &memory_map_write[ bank ];
  192. libspectrum_word offset = address & 0x1fff;
  193. libspectrum_byte *memory = mapping->page;
  194. /* The offset into the 16Kb RAM page (as opposed to the 8Kb chunk) */
  195. libspectrum_word offset2 = offset + mapping->offset;
  196. /* If this is a write to the current screen (and it actually changes
  197. the destination), redraw that bit */
  198. if( mapping->bank == MEMORY_BANK_HOME &&
  199. mapping->page_num == memory_current_screen &&
  200. ( offset2 & memory_screen_mask ) < 0x1b00 &&
  201. memory[ offset ] != b )
  202. display_dirty( offset2 );
  203. }
  204. memory_display_dirty_fn memory_display_dirty;
  205. void
  206. writebyte_internal( libspectrum_word address, libspectrum_byte b )
  207. {
  208. libspectrum_word bank = address >> 13;
  209. memory_page *mapping = &memory_map_write[ bank ];
  210. if( opus_active && address >= 0x2800 && address < 0x3800 ) {
  211. opus_write( address, b );
  212. } else if( mapping->writable ||
  213. (mapping->bank != MEMORY_BANK_NONE &&
  214. settings_current.writable_roms) ) {
  215. libspectrum_word offset = address & 0x1fff;
  216. libspectrum_byte *memory = mapping->page;
  217. memory_display_dirty( address, b );
  218. memory[ offset ] = b;
  219. }
  220. }
  221. void
  222. memory_romcs_map( void )
  223. {
  224. /* Nothing changes if /ROMCS is not set */
  225. if( !machine_current->ram.romcs ) return;
  226. /* FIXME: what should we do if more than one of these devices is
  227. active? What happen in the real situation? e.g. if1+if2 with cartridge?
  228. OK. in the Interface 1 service manual: p.: 1.2 par.: 1.3.1
  229. All the additional software needed in IC2 (the if1 ROM). IC2 enable
  230. is discussed in paragraph 1.2.2 above. In addition to control from
  231. IC1 (the if1 ULA), the ROM maybe disabled by a device connected to
  232. the (if1's) expansion connector J1. ROMCS2 from (B25), for example,
  233. Interface 2 connected to J1 would disable both ROM IC2 (if1 ROM) and
  234. the Spectrum ROM, via isolating diodes D10 and D9 respectively.
  235. All comment in parenthesis added by me (Gergely Szasz).
  236. The ROMCS2 (B25 conn) in Interface 1 J1 edge connector is in the
  237. same position than ROMCS (B25 conn) in the Spectrum edge connector.
  238. */
  239. module_romcs();
  240. }
  241. static void
  242. memory_from_snapshot( libspectrum_snap *snap )
  243. {
  244. size_t i;
  245. int capabilities = machine_current->capabilities;
  246. if( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY )
  247. spec128_memoryport_write( 0x7ffd,
  248. libspectrum_snap_out_128_memoryport( snap ) );
  249. if( ( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY ) ||
  250. ( capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_SCORP_MEMORY ) )
  251. specplus3_memoryport2_write(
  252. 0x1ffd, libspectrum_snap_out_plus3_memoryport( snap )
  253. );
  254. for( i = 0; i < 16; i++ )
  255. if( libspectrum_snap_pages( snap, i ) )
  256. memcpy( RAM[i], libspectrum_snap_pages( snap, i ), 0x4000 );
  257. if( libspectrum_snap_custom_rom( snap ) ) {
  258. for( i = 0; i < libspectrum_snap_custom_rom_pages( snap ) && i < 4; i++ ) {
  259. if( libspectrum_snap_roms( snap, i ) ) {
  260. machine_load_rom_bank_from_buffer(
  261. memory_map_rom, i * 2,
  262. i, libspectrum_snap_roms( snap, i ),
  263. libspectrum_snap_rom_length( snap, i ),
  264. 1 );
  265. }
  266. }
  267. /* Need to reset memory_map_[read|write] */
  268. machine_current->memory_map();
  269. }
  270. }
  271. static void
  272. write_rom_to_snap( libspectrum_snap *snap, int *current_rom_num,
  273. libspectrum_byte **current_rom, size_t *rom_length )
  274. {
  275. libspectrum_snap_set_roms( snap, *current_rom_num, *current_rom );
  276. libspectrum_snap_set_rom_length( snap, *current_rom_num, *rom_length );
  277. (*current_rom_num)++;
  278. *current_rom = NULL;
  279. }
  280. /* Look at all ROM entries, to see if any are marked as
  281. MEMORY_SOURCE_CUSTOMROM */
  282. int
  283. memory_custom_rom( void )
  284. {
  285. size_t i;
  286. for( i = 0; i < 2 * SPECTRUM_ROM_PAGES; i++ ) {
  287. if( memory_map_rom[ i ].source == MEMORY_SOURCE_CUSTOMROM ) return 1;
  288. }
  289. return 0;
  290. }
  291. static void
  292. memory_rom_to_snapshot( libspectrum_snap *snap )
  293. {
  294. libspectrum_byte *current_rom = NULL;
  295. int current_page_num = -1;
  296. int current_rom_num = 0;
  297. size_t rom_length = 0;
  298. size_t i;
  299. /* If we have custom ROMs trigger writing all roms to the snap */
  300. if( !memory_custom_rom() ) return;
  301. libspectrum_snap_set_custom_rom( snap, 1 );
  302. /* write all ROMs to the snap */
  303. for( i = 0; i < 2 * SPECTRUM_ROM_PAGES; i++ ) {
  304. if( memory_map_rom[ i ].page ) {
  305. if( current_page_num != memory_map_rom[ i ].page_num ) {
  306. if( current_rom )
  307. write_rom_to_snap( snap, &current_rom_num, &current_rom, &rom_length );
  308. /* Start a new ROM image */
  309. rom_length = MEMORY_PAGE_SIZE;
  310. current_rom = malloc( rom_length );
  311. if( !current_rom ) {
  312. ui_error( UI_ERROR_ERROR, "Out of memory at %s:%d", __FILE__,
  313. __LINE__ );
  314. return;
  315. }
  316. memcpy( current_rom, memory_map_rom[ i ].page, MEMORY_PAGE_SIZE );
  317. current_page_num = memory_map_rom[ i ].page_num;
  318. } else {
  319. /* Extend the current ROM image */
  320. current_rom = realloc( current_rom, rom_length + MEMORY_PAGE_SIZE );
  321. if( !current_rom ) {
  322. ui_error( UI_ERROR_ERROR, "Out of memory at %s:%d", __FILE__,
  323. __LINE__ );
  324. return;
  325. }
  326. memcpy( current_rom + rom_length, memory_map_rom[ i ].page,
  327. MEMORY_PAGE_SIZE );
  328. rom_length += MEMORY_PAGE_SIZE;
  329. }
  330. }
  331. }
  332. if( current_rom )
  333. write_rom_to_snap( snap, &current_rom_num, &current_rom, &rom_length );
  334. libspectrum_snap_set_custom_rom_pages( snap, current_rom_num );
  335. }
  336. static void
  337. memory_to_snapshot( libspectrum_snap *snap )
  338. {
  339. size_t i;
  340. libspectrum_byte *buffer;
  341. libspectrum_snap_set_out_128_memoryport( snap,
  342. machine_current->ram.last_byte );
  343. libspectrum_snap_set_out_plus3_memoryport( snap,
  344. machine_current->ram.last_byte2 );
  345. for( i = 0; i < 16; i++ ) {
  346. if( RAM[i] != NULL ) {
  347. buffer = malloc( 0x4000 * sizeof( libspectrum_byte ) );
  348. if( !buffer ) {
  349. ui_error( UI_ERROR_ERROR, "Out of memory at %s:%d", __FILE__,
  350. __LINE__ );
  351. return;
  352. }
  353. memcpy( buffer, RAM[i], 0x4000 );
  354. libspectrum_snap_set_pages( snap, i, buffer );
  355. }
  356. }
  357. memory_rom_to_snapshot( snap );
  358. }